From ff61ef9ef7fe5377e36a0e5551fcd5b595a864e9 Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Thu, 17 Feb 2022 15:49:27 -0700 Subject: [PATCH 0001/1487] Provide alternate SE RoT provisioning path. On some devices it is infeasible to provision the KeyMint RoT bits in the Android Bootloader. This provides an alternate path to provision them from the TEE during early boot. Bug: 219076736 Test: VtsAidlKeyMintTargetTest Change-Id: Ibae9050b9a102dad3710f9495d3dfa43fa1d1b3f --- .../trusty_keymaster/TrustyKeyMintDevice.h | 10 ++++++++-- trusty/keymaster/keymint/TrustyKeyMintDevice.cpp | 15 ++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h index 5fd628f3c92c..c8d8932c429b 100644 --- a/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h +++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h @@ -27,6 +27,7 @@ namespace aidl::android::hardware::security::keymint::trusty { using ::keymaster::TrustyKeymaster; using ::ndk::ScopedAStatus; using secureclock::TimeStampToken; +using ::std::array; using ::std::optional; using ::std::shared_ptr; using ::std::vector; @@ -77,8 +78,13 @@ class TrustyKeyMintDevice : public BnKeyMintDevice { const optional& timestampToken) override; ScopedAStatus earlyBootEnded() override; - ScopedAStatus convertStorageKeyToEphemeral(const std::vector& storageKeyBlob, - std::vector* ephemeralKeyBlob) override; + ScopedAStatus convertStorageKeyToEphemeral(const vector& storageKeyBlob, + vector* ephemeralKeyBlob) override; + + ScopedAStatus getRootOfTrustChallenge(array* challenge) override; + ScopedAStatus getRootOfTrust(const array& challenge, + vector* rootOfTrust) override; + ScopedAStatus sendRootOfTrust(const vector& rootOfTrust) override; protected: std::shared_ptr impl_; diff --git a/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp index 68a791259f7d..44780e835c28 100644 --- a/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp +++ b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp @@ -306,7 +306,7 @@ ScopedAStatus TrustyKeyMintDevice::earlyBootEnded() { } ScopedAStatus TrustyKeyMintDevice::convertStorageKeyToEphemeral( - const std::vector& storageKeyBlob, std::vector* ephemeralKeyBlob) { + const vector& storageKeyBlob, vector* ephemeralKeyBlob) { keymaster::ExportKeyRequest request(impl_->message_version()); request.SetKeyMaterial(storageKeyBlob.data(), storageKeyBlob.size()); request.key_format = KM_KEY_FORMAT_RAW; @@ -321,4 +321,17 @@ ScopedAStatus TrustyKeyMintDevice::convertStorageKeyToEphemeral( return ScopedAStatus::ok(); } +ScopedAStatus TrustyKeyMintDevice::getRootOfTrustChallenge(array* /* challenge */) { + return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED); +} + +ScopedAStatus TrustyKeyMintDevice::getRootOfTrust(const array& /* challenge */, + vector* /* rootOfTrust */) { + return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED); +} + +ScopedAStatus TrustyKeyMintDevice::sendRootOfTrust(const vector& /* rootOfTrust */) { + return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED); +} + } // namespace aidl::android::hardware::security::keymint::trusty From 24d3ac349a98350ce12b5f8a3bc1917dd4d16a7a Mon Sep 17 00:00:00 2001 From: Atneya Nair Date: Fri, 11 Feb 2022 17:26:28 -0500 Subject: [PATCH 0002/1487] Fix OkOrFail conversion ambiguities OkOrFail has specialized conversions for Result to avoid ambiguous implicit conversion sequences. Since user conversion operators sequences can be followed by integral promotion, specializing for integral types is necessary. Specialize ResultError so calling code() returns a status_t instead of a StatusT and message() is implemented even when not carrying a string. Eventually, these classes should be combined. Add equality operators for ResultError. Bug: 219580167 Test: atest Errors_test.cpp Ignore-AOSP-First: Internal topic dependencies Change-Id: I14acecfd2aef33c40e79ddb091e2f4af9291d837 --- libutils/Errors_test.cpp | 62 +++++++++++++++ libutils/include/utils/ErrorsMacros.h | 108 +++++++++++++++++++++++++- 2 files changed, 166 insertions(+), 4 deletions(-) diff --git a/libutils/Errors_test.cpp b/libutils/Errors_test.cpp index 873c9949059d..0d13bb03c815 100644 --- a/libutils/Errors_test.cpp +++ b/libutils/Errors_test.cpp @@ -108,3 +108,65 @@ TEST(errors, result_in_status) { status_t b = g(false); EXPECT_EQ(PERMISSION_DENIED, b); } + +TEST(errors, conversion_promotion) { + constexpr size_t successVal = 10ull; + auto f = [&](bool success) -> Result { + OR_RETURN(success_or_fail(success)); + return successVal; + }; + auto s = f(true); + ASSERT_TRUE(s.ok()); + EXPECT_EQ(s.value(), successVal); + auto r = f(false); + EXPECT_TRUE(!r.ok()); + EXPECT_EQ(PERMISSION_DENIED, r.error().code()); +} + +TEST(errors, conversion_promotion_bool) { + constexpr size_t successVal = true; + auto f = [&](bool success) -> Result { + OR_RETURN(success_or_fail(success)); + return successVal; + }; + auto s = f(true); + ASSERT_TRUE(s.ok()); + EXPECT_EQ(s.value(), successVal); + auto r = f(false); + EXPECT_TRUE(!r.ok()); + EXPECT_EQ(PERMISSION_DENIED, r.error().code()); +} + +TEST(errors, conversion_promotion_char) { + constexpr char successVal = 'a'; + auto f = [&](bool success) -> Result { + OR_RETURN(success_or_fail(success)); + return successVal; + }; + auto s = f(true); + ASSERT_TRUE(s.ok()); + EXPECT_EQ(s.value(), successVal); + auto r = f(false); + EXPECT_TRUE(!r.ok()); + EXPECT_EQ(PERMISSION_DENIED, r.error().code()); +} + +struct IntContainer { + // Implicit conversion from int is desired + IntContainer(int val) : val_(val) {} + int val_; +}; + +TEST(errors, conversion_construct) { + constexpr int successVal = 10; + auto f = [&](bool success) -> Result { + OR_RETURN(success_or_fail(success)); + return successVal; + }; + auto s = f(true); + ASSERT_TRUE(s.ok()); + EXPECT_EQ(s.value().val_, successVal); + auto r = f(false); + EXPECT_TRUE(!r.ok()); + EXPECT_EQ(PERMISSION_DENIED, r.error().code()); +} diff --git a/libutils/include/utils/ErrorsMacros.h b/libutils/include/utils/ErrorsMacros.h index 048c5386f159..fdc46e617923 100644 --- a/libutils/include/utils/ErrorsMacros.h +++ b/libutils/include/utils/ErrorsMacros.h @@ -25,6 +25,7 @@ // [1] build/soong/cc/config/global.go#commonGlobalIncludes #include #include +#include #include @@ -44,13 +45,58 @@ struct StatusT { status_t val_; }; + namespace base { +// TODO(b/221235365) StatusT fulfill ResultError contract and cleanup. + +// Unlike typical ResultError types, the underlying code should be a status_t +// instead of a StatusT. We also special-case message generation. +template<> +struct ResultError { + ResultError(status_t s) : val_(s) { + LOG_FATAL_IF(s == OK, "Result error should not hold success"); + } + + template + operator expected>() const { + return unexpected(*this); + } + + std::string message() const { return statusToString(val_); } + status_t code() const { return val_; } + + private: + const status_t val_; +}; + +template<> +struct ResultError { + template + ResultError(T&& message, status_t s) : val_(s), message_(std::forward(message)) { + LOG_FATAL_IF(s == OK, "Result error should not hold success"); + } + + ResultError(status_t s) : val_(s) {} + + template + operator expected>() const { + return unexpected(*this); + } + + status_t code() const { return val_; } + + std::string message() const { return statusToString(val_) + message_; } + private: + const status_t val_; + std::string message_; +}; // Specialization of android::base::OkOrFail for V = status_t. This is used to use the OR_RETURN // and OR_FATAL macros with statements that yields a value of status_t. See android-base/errors.h // for the detailed contract. template <> struct OkOrFail { + static_assert(std::is_same_v); // Tests if status_t is a success value of not. static bool IsOk(const status_t& s) { return s == OK; } @@ -71,16 +117,70 @@ struct OkOrFail { // Or converts into Result. This is used when OR_RETURN is used in a function whose // return type is Result. - template >> + + template operator Result() && { - return Error(std::move(val_)); + return ResultError(std::move(val_)); } - operator Result() && { return Error(std::move(val_)); } + template + operator Result() && { + return ResultError(std::move(val_)); + } + // Since user defined conversion can be followed by numeric conversion, + // we have to specialize all conversions to results holding numeric types to + // avoid conversion ambiguities with the constructor of expected. +#pragma push_macro("SPECIALIZED_CONVERSION") +#define SPECIALIZED_CONVERSION(type)\ + operator Result() && { return ResultError(std::move(val_)); }\ + operator Result() && { return ResultError(std::move(val_));} + + SPECIALIZED_CONVERSION(int) + SPECIALIZED_CONVERSION(short int) + SPECIALIZED_CONVERSION(unsigned short int) + SPECIALIZED_CONVERSION(unsigned int) + SPECIALIZED_CONVERSION(long int) + SPECIALIZED_CONVERSION(unsigned long int) + SPECIALIZED_CONVERSION(long long int) + SPECIALIZED_CONVERSION(unsigned long long int) + SPECIALIZED_CONVERSION(bool) + SPECIALIZED_CONVERSION(char) + SPECIALIZED_CONVERSION(unsigned char) + SPECIALIZED_CONVERSION(signed char) + SPECIALIZED_CONVERSION(wchar_t) + SPECIALIZED_CONVERSION(char16_t) + SPECIALIZED_CONVERSION(char32_t) + SPECIALIZED_CONVERSION(float) + SPECIALIZED_CONVERSION(double) + SPECIALIZED_CONVERSION(long double) +#undef SPECIALIZED_CONVERSION +#pragma pop_macro("SPECIALIZED_CONVERSION") // String representation of the error value. static std::string ErrorMessage(const status_t& s) { return statusToString(s); } }; - } // namespace base + + +// These conversions make StatusT directly comparable to status_t in order to +// avoid calling code whenever comparisons are desired. + +template +bool operator==(const base::ResultError& l, const status_t& r) { + return (l.code() == r); +} +template +bool operator==(const status_t& l, const base::ResultError& r) { + return (l == r.code()); +} + +template +bool operator!=(const base::ResultError& l, const status_t& r) { + return (l.code() != r); +} +template +bool operator!=(const status_t& l, const base::ResultError& r) { + return (l != r.code()); +} + } // namespace android From 206e8a4f827254173ea04461a772cccf2f0c558c Mon Sep 17 00:00:00 2001 From: Almaz Mingaleev Date: Tue, 31 May 2022 09:25:17 +0100 Subject: [PATCH 0003/1487] Remove TZUvA feature. The feature was superseded by tzdata mainline module(s). Ignore-AOSP-First: merge conflict on aosp/master -> goog/master Bug: 148144561 Test: see system/timezone Change-Id: If87e9a71a725f665bfc977d95e52c04668447081 --- rootdir/init.rc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 70a3736cb55b..b811e977391d 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -1021,10 +1021,6 @@ on post-fs-data # completed and apexd.status becomes "ready". exec_start apexd-snapshotde - # Check any timezone data in /data is newer than the copy in the time zone data - # module, delete if not. - exec - system system -- /system/bin/tzdatacheck /apex/com.android.tzdata/etc/tz /data/misc/zoneinfo - # sys.memfd_use set to false by default, which keeps it disabled # until it is confirmed that apps and vendor processes don't make # IOCTLs on ashmem fds any more. From 7d8c25b0c99bc5628ea9464f89e7771a82077283 Mon Sep 17 00:00:00 2001 From: Suchang Woo Date: Mon, 20 Dec 2021 13:23:28 +0900 Subject: [PATCH 0004/1487] ueventd: Wait for runtime apex before running external firmware handler External firmware handlers cannot run until com.android.runtime.apex is activated. However, it may be possible to request firmware from the kernel before apex activation. Waiting for runtime apex is required before running an external firmware handler. Test: atest CtsInitTestCases Change-Id: Id63b7f29084d3cecb901049162d3e5cd0055566f Signed-off-by: Suchang Woo --- init/firmware_handler.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp index 30e808d9fcd3..b682cd0aec7c 100644 --- a/init/firmware_handler.cpp +++ b/init/firmware_handler.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ using android::base::Split; using android::base::Timer; using android::base::Trim; using android::base::unique_fd; +using android::base::WaitForProperty; using android::base::WriteFully; namespace android { @@ -82,6 +84,33 @@ static bool IsBooting() { return access("/dev/.booting", F_OK) == 0; } +static bool IsApexActivated() { + static bool apex_activated = []() { + // Wait for com.android.runtime.apex activation + // Property name and value must be kept in sync with system/apexd/apex/apex_constants.h + // 60s is the default firmware sysfs fallback timeout. (/sys/class/firmware/timeout) + if (!WaitForProperty("apexd.status", "activated", 60s)) { + LOG(ERROR) << "Apexd activation wait timeout"; + return false; + } + return true; + }(); + + return apex_activated; +} + +static bool NeedsRerunExternalHandler() { + static bool first = true; + + // Rerun external handler only on the first try and when apex is activated + if (first) { + first = false; + return IsApexActivated(); + } + + return first; +} + ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid, gid_t gid, std::string handler_path) : devpath(std::move(devpath)), uid(uid), gid(gid), handler_path(std::move(handler_path)) { @@ -210,6 +239,11 @@ std::string FirmwareHandler::GetFirmwarePath(const Uevent& uevent) const { auto result = RunExternalHandler(external_handler.handler_path, external_handler.uid, external_handler.gid, uevent); + if (!result.ok() && NeedsRerunExternalHandler()) { + auto res = RunExternalHandler(external_handler.handler_path, external_handler.uid, + external_handler.gid, uevent); + result = std::move(res); + } if (!result.ok()) { LOG(ERROR) << "Using default firmware; External firmware handler failed: " << result.error(); From 123d45e1d3825a0e54f84c9d7c2895155f69873f Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Fri, 8 Jul 2022 18:22:34 -0700 Subject: [PATCH 0005/1487] libsnapshot: fix integer overflow when calculating sector id. Ignore-AOSP-First: fuzzer-detected overflow Test: WIP Bug: 237639416 Change-Id: I91dedc1ccfab8dcf40e5b4756e199697e62b1f3c --- fs_mgr/libsnapshot/partition_cow_creator.cpp | 21 ++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/fs_mgr/libsnapshot/partition_cow_creator.cpp b/fs_mgr/libsnapshot/partition_cow_creator.cpp index 5569da03834b..acbcbe2193d8 100644 --- a/fs_mgr/libsnapshot/partition_cow_creator.cpp +++ b/fs_mgr/libsnapshot/partition_cow_creator.cpp @@ -131,15 +131,28 @@ bool OptimizeSourceCopyOperation(const InstallOperation& operation, InstallOpera return is_optimized; } -void WriteExtent(DmSnapCowSizeCalculator* sc, const chromeos_update_engine::Extent& de, +bool WriteExtent(DmSnapCowSizeCalculator* sc, const chromeos_update_engine::Extent& de, unsigned int sectors_per_block) { const auto block_boundary = de.start_block() + de.num_blocks(); for (auto b = de.start_block(); b < block_boundary; ++b) { for (unsigned int s = 0; s < sectors_per_block; ++s) { - const auto sector_id = b * sectors_per_block + s; + // sector_id = b * sectors_per_block + s; + uint64_t block_start_sector_id; + if (__builtin_mul_overflow(b, sectors_per_block, &block_start_sector_id)) { + LOG(ERROR) << "Integer overflow when calculating sector id (" << b << " * " + << sectors_per_block << ")"; + return false; + } + uint64_t sector_id; + if (__builtin_add_overflow(block_start_sector_id, s, §or_id)) { + LOG(ERROR) << "Integer overflow when calculating sector id (" + << block_start_sector_id << " + " << s << ")"; + return false; + } sc->WriteSector(sector_id); } } + return true; } std::optional PartitionCowCreator::GetCowSize() { @@ -167,7 +180,7 @@ std::optional PartitionCowCreator::GetCowSize() { // Allocate space for extra extents (if any). These extents are those that can be // used for error corrections or to store verity hash trees. for (const auto& de : extra_extents) { - WriteExtent(&sc, de, sectors_per_block); + if (!WriteExtent(&sc, de, sectors_per_block)) return std::nullopt; } if (update == nullptr) return sc.cow_size_bytes(); @@ -182,7 +195,7 @@ std::optional PartitionCowCreator::GetCowSize() { } for (const auto& de : written_op->dst_extents()) { - WriteExtent(&sc, de, sectors_per_block); + if (!WriteExtent(&sc, de, sectors_per_block)) return std::nullopt; } } From e6281db539133e7958ec77e37f6c545a6185a587 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Tue, 26 Jul 2022 16:37:58 +0000 Subject: [PATCH 0006/1487] libprocessgroup: Add support for SetUserProfiles Provide SetUserProfiles API to apply profiles at UID level. This enables applying the freezer profile to an entire UID instead of just individual process cgroups. Test: bash arg: -p Test: bash arg: com.haok.nirvana Test: bash arg: 1 Test: args: [-p, com.haok.nirvana, 1] Test: arg: "-p" Test: arg: "com.haok.nirvana" Test: arg: "1" Test: data="com.haok.nirvana" Test: Events injected: 1 Test: ## Network stats: elapsed time=14ms (0ms mobile, 0ms wifi, 14ms not connected) Test: raven:/ $ ps -eo pid,uid,ppid,name|grep 10266 Test: 2499 10266 823 com.haok.nirvana Test: 2577 10266 823 com.haok.nirvana:resident Test: 2584 10266 823 android.media Test: 2669 10266 1 app_d Test: 2672 10266 1 app_d Test: raven:/ $ am force-stop com.haok.nirvana Test: raven:/ $ ps -eo pid,uid,ppid,name|grep 10266 Test: 1|raven:/ $ Ignore-AOSP-First: Topic with AMS changes which is developed on git_master Bug: 236708592 Change-Id: I45e34244f9943c217757cf346c9410672a1ce365 --- .../include/processgroup/processgroup.h | 1 + libprocessgroup/processgroup.cpp | 4 ++ libprocessgroup/task_profiles.cpp | 66 +++++++++++++++++++ libprocessgroup/task_profiles.h | 6 ++ libprocessgroup/task_profiles_test.cpp | 4 ++ 5 files changed, 81 insertions(+) diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index 39b9f3fc024c..32479e45844a 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -32,6 +32,7 @@ bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::s bool SetTaskProfiles(int tid, const std::vector& profiles, bool use_fd_cache = false); bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles); +bool SetUserProfiles(uid_t uid, const std::vector& profiles); #ifndef __ANDROID_VNDK__ diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index 51c810e9886e..b1ce8af1f033 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -174,6 +174,10 @@ extern "C" bool android_set_process_profiles(uid_t uid, pid_t pid, size_t num_pr return SetProcessProfiles(uid, pid, profiles_); } +bool SetUserProfiles(uid_t uid, const std::vector& profiles) { + return TaskProfiles::GetInstance().SetUserProfiles(uid, profiles, false); +} + static std::string ConvertUidToPath(const char* cgroup, uid_t uid) { return StringPrintf("%s/uid_%d", cgroup, uid); } diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index e1c5934073c1..9dfc0ba9a435 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -139,6 +139,19 @@ bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { 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 +238,31 @@ bool SetAttributeAction::ExecuteForTask(int tid) const { 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 +590,16 @@ bool TaskProfile::ExecuteForTask(int tid) const { 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; @@ -804,6 +852,24 @@ const IProfileAttribute* TaskProfiles::GetAttribute(const std::string& name) con return nullptr; } +bool TaskProfiles::SetUserProfiles(uid_t uid, const std::vector& 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; +} + bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles, bool use_fd_cache) { bool success = true; diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index df08f65c7604..cdd9b42a28d2 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -33,6 +33,7 @@ class IProfileAttribute { 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 { @@ -50,6 +51,7 @@ class ProfileAttribute : public IProfileAttribute { 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_; @@ -69,6 +71,7 @@ class ProfileAction { // 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) {} @@ -113,6 +116,7 @@ class SetAttributeAction : public ProfileAction { 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_; @@ -176,6 +180,7 @@ class TaskProfile { 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); @@ -212,6 +217,7 @@ class TaskProfiles { bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles, bool use_fd_cache); bool SetTaskProfiles(int tid, const std::vector& profiles, bool use_fd_cache); + bool SetUserProfiles(uid_t uid, const std::vector& profiles, bool use_fd_cache); private: std::map> profiles_; diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp index 09ac44c6b254..fed819e5320e 100644 --- a/libprocessgroup/task_profiles_test.cpp +++ b/libprocessgroup/task_profiles_test.cpp @@ -121,6 +121,10 @@ class ProfileAttributeMock : public IProfileAttribute { return true; }; + bool GetPathForUID(uid_t, std::string *) const override { + return false; + } + private: const std::string file_name_; }; From aee11b0a3da5bbfd09d258278700b358a8691151 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Fri, 19 Aug 2022 18:40:14 +0000 Subject: [PATCH 0007/1487] Revert "libprocessgroup: Add support for SetUserProfiles" Revert "Freeze package cgroup before killing" Revert submission 19436294-freeze_kill Reason for revert: b/243096961 Reverted Changes: I06aaa5a08:Freeze package cgroup before killing I45e34244f:libprocessgroup: Add support for SetUserProfiles Bug: 243096961 Change-Id: I32162341d6a38f458a9c59d63e0cdc56a97f1efe --- .../include/processgroup/processgroup.h | 1 - libprocessgroup/processgroup.cpp | 4 -- libprocessgroup/task_profiles.cpp | 66 ------------------- libprocessgroup/task_profiles.h | 6 -- libprocessgroup/task_profiles_test.cpp | 4 -- 5 files changed, 81 deletions(-) diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index 32479e45844a..39b9f3fc024c 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -32,7 +32,6 @@ bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::s bool SetTaskProfiles(int tid, const std::vector& profiles, bool use_fd_cache = false); bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles); -bool SetUserProfiles(uid_t uid, const std::vector& profiles); #ifndef __ANDROID_VNDK__ diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index b1ce8af1f033..51c810e9886e 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -174,10 +174,6 @@ extern "C" bool android_set_process_profiles(uid_t uid, pid_t pid, size_t num_pr return SetProcessProfiles(uid, pid, profiles_); } -bool SetUserProfiles(uid_t uid, const std::vector& profiles) { - return TaskProfiles::GetInstance().SetUserProfiles(uid, profiles, false); -} - static std::string ConvertUidToPath(const char* cgroup, uid_t uid) { return StringPrintf("%s/uid_%d", cgroup, uid); } diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 9dfc0ba9a435..e1c5934073c1 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -139,19 +139,6 @@ bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { 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"; @@ -238,31 +225,6 @@ bool SetAttributeAction::ExecuteForTask(int tid) const { 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]); @@ -590,16 +552,6 @@ bool TaskProfile::ExecuteForTask(int tid) const { 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; @@ -852,24 +804,6 @@ const IProfileAttribute* TaskProfiles::GetAttribute(const std::string& name) con return nullptr; } -bool TaskProfiles::SetUserProfiles(uid_t uid, const std::vector& 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; -} - bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles, bool use_fd_cache) { bool success = true; diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index cdd9b42a28d2..df08f65c7604 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -33,7 +33,6 @@ class IProfileAttribute { 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 { @@ -51,7 +50,6 @@ class ProfileAttribute : public IProfileAttribute { 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_; @@ -71,7 +69,6 @@ class ProfileAction { // 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,7 +113,6 @@ class SetAttributeAction : public ProfileAction { 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_; @@ -180,7 +176,6 @@ class TaskProfile { 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); @@ -217,7 +212,6 @@ class TaskProfiles { bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles, bool use_fd_cache); bool SetTaskProfiles(int tid, const std::vector& profiles, bool use_fd_cache); - bool SetUserProfiles(uid_t uid, const std::vector& profiles, bool use_fd_cache); private: std::map> profiles_; diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp index fed819e5320e..09ac44c6b254 100644 --- a/libprocessgroup/task_profiles_test.cpp +++ b/libprocessgroup/task_profiles_test.cpp @@ -121,10 +121,6 @@ class ProfileAttributeMock : public IProfileAttribute { return true; }; - bool GetPathForUID(uid_t, std::string *) const override { - return false; - } - private: const std::string file_name_; }; From 7f47b5204180a6f98e3d64280eb8142b43392668 Mon Sep 17 00:00:00 2001 From: Sanjana Sunil Date: Mon, 28 Mar 2022 19:05:36 +0000 Subject: [PATCH 0008/1487] Create misc_ce and misc_de mirror storage Create a mirror directory for misc_ce and misc_de storage by bind mounting the respective directories. This is done for the defaul null volume only, and other volumes are handled at a later staged. When an SDK sandbox process is spawned and data isolation needs to occur, the sdksandbox directories present in the misc directories will be used to bind mount from, after tmpfs is mounted on the original. Bug: 214241165 Test: atest SdkSandboxStorageHostTest Ignore-AOSP-First: Will cherry pick based on other CLs in the topic Change-Id: Icb1dc7d7fbd53a5c3853acf2f9d4d75b278d7295 --- rootdir/init.rc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 60bf57bef2e0..e791b31ed3e5 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -939,22 +939,28 @@ on post-fs-data restorecon /data/media exec - media_rw media_rw -- /system/bin/chattr +F /data/media - # A tmpfs directory, which will contain all apps CE DE data directory that - # bind mount from the original source. + # A tmpfs directory, which will contain all apps and sdk sandbox CE and DE + # data directory that bind mount from the original source. mount tmpfs tmpfs /data_mirror nodev noexec nosuid mode=0700,uid=0,gid=1000 restorecon /data_mirror mkdir /data_mirror/data_ce 0700 root root mkdir /data_mirror/data_de 0700 root root + mkdir /data_mirror/misc_ce 0700 root root + mkdir /data_mirror/misc_de 0700 root root # Create CE and DE data directory for default volume mkdir /data_mirror/data_ce/null 0700 root root mkdir /data_mirror/data_de/null 0700 root root + mkdir /data_mirror/misc_ce/null 0700 root root + mkdir /data_mirror/misc_de/null 0700 root root # Bind mount CE and DE data directory to mirror's default volume directory. # The 'slave' option (MS_SLAVE) is needed to cause the later bind mount of # /data/data onto /data/user/0 to propagate to /data_mirror/data_ce/null/0. mount none /data/user /data_mirror/data_ce/null bind rec slave mount none /data/user_de /data_mirror/data_de/null bind rec + mount none /data/misc_ce /data_mirror/misc_ce/null bind rec + mount none /data/misc_de /data_mirror/misc_de/null bind rec # Create mirror directory for jit profiles mkdir /data_mirror/cur_profiles 0700 root root From 673da5b972e751b723b735a63ae57bd54d956b7e Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Mon, 22 Aug 2022 21:25:09 +0000 Subject: [PATCH 0009/1487] Revert "Revert "libprocessgroup: Add support for SetUserProfiles"" This reverts commit aee11b0a3da5bbfd09d258278700b358a8691151. This change was originally reverted because its only user was reverted under b/243096961 at ag/19679188. We bring it back now with a fixed user. Bug: 236708592 Bug: 148425913 Ignore-AOSP-First: Topic with AMS changes which is developed on git_master Change-Id: I2a8ae0d9faabe7950b758a09870d128889be4d0a --- .../include/processgroup/processgroup.h | 1 + libprocessgroup/processgroup.cpp | 5 ++ libprocessgroup/task_profiles.cpp | 64 +++++++++++++++++++ libprocessgroup/task_profiles.h | 7 ++ libprocessgroup/task_profiles_test.cpp | 4 ++ 5 files changed, 81 insertions(+) diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index 45a723f74c26..f3cd421dd1dd 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -35,6 +35,7 @@ bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::s bool SetTaskProfiles(int tid, const std::vector& profiles, bool use_fd_cache = false); bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles); +bool SetUserProfiles(uid_t uid, const std::vector& profiles); __END_DECLS diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index bdda1020c7d4..393936ca7bd0 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -195,6 +195,11 @@ extern "C" bool android_set_process_profiles(uid_t uid, pid_t pid, size_t num_pr return SetProcessProfiles(uid, pid, std::span(profiles_)); } +bool SetUserProfiles(uid_t uid, const std::vector& profiles) { + return TaskProfiles::GetInstance().SetUserProfiles(uid, std::span(profiles), + false); +} + static std::string ConvertUidToPath(const char* cgroup, uid_t uid) { return StringPrintf("%s/uid_%d", cgroup, uid); } diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 744710f3b25b..0fbfc8c079d7 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -139,6 +139,17 @@ bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { 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 @@ bool SetAttributeAction::ExecuteForTask(int tid) const { 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 @@ bool TaskProfile::ExecuteForTask(int tid) const { 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; @@ -804,6 +848,24 @@ const IProfileAttribute* TaskProfiles::GetAttribute(std::string_view name) const return nullptr; } +template +bool TaskProfiles::SetUserProfiles(uid_t uid, std::span 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 bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid, std::span profiles, bool use_fd_cache) { @@ -857,3 +919,5 @@ template bool TaskProfiles::SetTaskProfiles(int tid, std::span profiles, bool use_fd_cache); +template bool TaskProfiles::SetUserProfiles(uid_t uid, std::span profiles, + bool use_fd_cache); diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index 85b3f9162f7c..a8ecb873d88e 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -36,6 +36,7 @@ class IProfileAttribute { 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 @@ class ProfileAttribute : public IProfileAttribute { 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 @@ class ProfileAction { // 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 @@ class SetAttributeAction : public ProfileAction { 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 @@ class TaskProfile { 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 @@ class TaskProfiles { bool SetProcessProfiles(uid_t uid, pid_t pid, std::span profiles, bool use_fd_cache); template bool SetTaskProfiles(int tid, std::span profiles, bool use_fd_cache); + template + bool SetUserProfiles(uid_t uid, std::span profiles, bool use_fd_cache); private: TaskProfiles(); diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp index 09ac44c6b254..aa74f9d2563e 100644 --- a/libprocessgroup/task_profiles_test.cpp +++ b/libprocessgroup/task_profiles_test.cpp @@ -121,6 +121,10 @@ class ProfileAttributeMock : public IProfileAttribute { return true; }; + bool GetPathForUID(uid_t, std::string*) const override { + return false; + } + private: const std::string file_name_; }; From 43a172fb1d6fbf9b92f4de8ee12b89d886cef705 Mon Sep 17 00:00:00 2001 From: Rajesh Nyamagoud Date: Thu, 22 Sep 2022 20:25:52 +0000 Subject: [PATCH 0010/1487] Changes to adapt confirmationui AIDL spec. Replaced HIDL spec implementation with AIDL spec in confirmationui module. Ignore-AOSP-First: Dependent on internal change. Bug: b/205760172 Test: Run confirmation UI test using CTS Verifier, atest VtsHalConfirmationUITargetTest Change-Id: I49b9cb6d93fa35fd611003f7545d2ce4976eec7c --- trusty/confirmationui/Android.bp | 23 ++-- .../confirmationui/TrustyConfirmationUI.cpp | 124 +++++++++--------- trusty/confirmationui/TrustyConfirmationUI.h | 52 ++++---- ....hardware.confirmationui-service.trusty.rc | 5 + ...ardware.confirmationui-service.trusty.xml} | 5 +- ...dware.confirmationui@1.0-service.trusty.rc | 4 - .../include/TrustyConfirmationuiHal.h | 16 +-- trusty/confirmationui/service.cpp | 25 ++-- 8 files changed, 124 insertions(+), 130 deletions(-) create mode 100644 trusty/confirmationui/android.hardware.confirmationui-service.trusty.rc rename trusty/confirmationui/{android.hardware.confirmationui@1.0-service.trusty.xml => android.hardware.confirmationui-service.trusty.xml} (71%) delete mode 100644 trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc diff --git a/trusty/confirmationui/Android.bp b/trusty/confirmationui/Android.bp index 092241528f26..29ef3c098d16 100644 --- a/trusty/confirmationui/Android.bp +++ b/trusty/confirmationui/Android.bp @@ -24,21 +24,23 @@ package { } cc_binary { - name: "android.hardware.confirmationui@1.0-service.trusty", + name: "android.hardware.confirmationui-service.trusty", relative_install_path: "hw", vendor: true, shared_libs: [ - "android.hardware.confirmationui@1.0", + "android.hardware.confirmationui-V1-ndk", "android.hardware.confirmationui.not-so-secure-input", - "android.hardware.confirmationui@1.0-lib.trusty", + "android.hardware.confirmationui-lib.trusty", + "libbinder_ndk", + "libteeui_hal_support", "libbase", "libhidlbase", "libutils", ], - init_rc: ["android.hardware.confirmationui@1.0-service.trusty.rc"], + init_rc: ["android.hardware.confirmationui-service.trusty.rc"], - vintf_fragments: ["android.hardware.confirmationui@1.0-service.trusty.xml"], + vintf_fragments: ["android.hardware.confirmationui-service.trusty.xml"], srcs: [ "service.cpp", @@ -52,17 +54,20 @@ cc_binary { } cc_library { - name: "android.hardware.confirmationui@1.0-lib.trusty", + name: "android.hardware.confirmationui-lib.trusty", + defaults: [ + "keymint_use_latest_hal_aidl_ndk_shared", + ], vendor: true, shared_libs: [ - "android.hardware.confirmationui@1.0", - "android.hardware.keymaster@4.0", + "android.hardware.confirmationui-V1-ndk", "libbase", + "libcutils", "libdmabufheap", - "libhidlbase", "libteeui_hal_support", "libtrusty", "libutils", + "libbinder_ndk", ], export_include_dirs: ["include"], diff --git a/trusty/confirmationui/TrustyConfirmationUI.cpp b/trusty/confirmationui/TrustyConfirmationUI.cpp index c6625e0a1aa3..f01a4e1e9fee 100644 --- a/trusty/confirmationui/TrustyConfirmationUI.cpp +++ b/trusty/confirmationui/TrustyConfirmationUI.cpp @@ -18,8 +18,6 @@ #include "TrustyConfirmationUI.h" #include -#include -#include #include #include #include @@ -42,12 +40,7 @@ #include #include -namespace android { -namespace hardware { -namespace confirmationui { -namespace V1_0 { -namespace implementation { - +namespace aidl::android::hardware::confirmationui { using namespace secure_input; using ::android::trusty::confirmationui::TrustyAppError; @@ -64,8 +57,6 @@ using ::teeui::ResultMsg; using ::secure_input::createSecureInput; -using ::android::hardware::keymaster::V4_0::HardwareAuthToken; - using ::std::tie; using TeeuiRc = ::teeui::ResponseCode; @@ -87,46 +78,47 @@ class Finalize { void release() { f_ = {}; } }; -ResponseCode convertRc(TeeuiRc trc) { +int convertRc(TeeuiRc trc) { static_assert( - uint32_t(TeeuiRc::OK) == uint32_t(ResponseCode::OK) && - uint32_t(TeeuiRc::Canceled) == uint32_t(ResponseCode::Canceled) && - uint32_t(TeeuiRc::Aborted) == uint32_t(ResponseCode::Aborted) && - uint32_t(TeeuiRc::OperationPending) == uint32_t(ResponseCode::OperationPending) && - uint32_t(TeeuiRc::Ignored) == uint32_t(ResponseCode::Ignored) && - uint32_t(TeeuiRc::SystemError) == uint32_t(ResponseCode::SystemError) && - uint32_t(TeeuiRc::Unimplemented) == uint32_t(ResponseCode::Unimplemented) && - uint32_t(TeeuiRc::Unexpected) == uint32_t(ResponseCode::Unexpected) && - uint32_t(TeeuiRc::UIError) == uint32_t(ResponseCode::UIError) && - uint32_t(TeeuiRc::UIErrorMissingGlyph) == uint32_t(ResponseCode::UIErrorMissingGlyph) && + uint32_t(TeeuiRc::OK) == uint32_t(IConfirmationUI::OK) && + uint32_t(TeeuiRc::Canceled) == uint32_t(IConfirmationUI::CANCELED) && + uint32_t(TeeuiRc::Aborted) == uint32_t(IConfirmationUI::ABORTED) && + uint32_t(TeeuiRc::OperationPending) == uint32_t(IConfirmationUI::OPERATION_PENDING) && + uint32_t(TeeuiRc::Ignored) == uint32_t(IConfirmationUI::IGNORED) && + uint32_t(TeeuiRc::SystemError) == uint32_t(IConfirmationUI::SYSTEM_ERROR) && + uint32_t(TeeuiRc::Unimplemented) == uint32_t(IConfirmationUI::UNIMPLEMENTED) && + uint32_t(TeeuiRc::Unexpected) == uint32_t(IConfirmationUI::UNEXPECTED) && + uint32_t(TeeuiRc::UIError) == uint32_t(IConfirmationUI::UI_ERROR) && + uint32_t(TeeuiRc::UIErrorMissingGlyph) == + uint32_t(IConfirmationUI::UI_ERROR_MISSING_GLYPH) && uint32_t(TeeuiRc::UIErrorMessageTooLong) == - uint32_t(ResponseCode::UIErrorMessageTooLong) && + uint32_t(IConfirmationUI::UI_ERROR_MESSAGE_TOO_LONG) && uint32_t(TeeuiRc::UIErrorMalformedUTF8Encoding) == - uint32_t(ResponseCode::UIErrorMalformedUTF8Encoding), + uint32_t(IConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING), "teeui::ResponseCode and " "::android::hardware::confirmationui::V1_0::Responsecude are out of " "sync"); - return ResponseCode(trc); + return static_cast(trc); } teeui::UIOption convertUIOption(UIOption uio) { - static_assert(uint32_t(UIOption::AccessibilityInverted) == + static_assert(uint32_t(UIOption::ACCESSIBILITY_INVERTED) == uint32_t(teeui::UIOption::AccessibilityInverted) && - uint32_t(UIOption::AccessibilityMagnified) == + uint32_t(UIOption::ACCESSIBILITY_MAGNIFIED) == uint32_t(teeui::UIOption::AccessibilityMagnified), "teeui::UIOPtion and ::android::hardware::confirmationui::V1_0::UIOption " - "anre out of sync"); + "are out of sync"); return teeui::UIOption(uio); } -inline MsgString hidl2MsgString(const hidl_string& s) { +inline MsgString stdString2MsgString(const string& s) { return {s.c_str(), s.c_str() + s.size()}; } -template inline MsgVector hidl2MsgVector(const hidl_vec& v) { +template inline MsgVector stdVector2MsgVector(const vector& v) { return {v}; } -inline MsgVector hidl2MsgVector(const hidl_vec& v) { +inline MsgVector stdVector2MsgVector(const vector& v) { MsgVector result(v.size()); for (unsigned int i = 0; i < v.size(); ++i) { result[i] = convertUIOption(v[i]); @@ -137,7 +129,7 @@ inline MsgVector hidl2MsgVector(const hidl_vec& v) { } // namespace TrustyConfirmationUI::TrustyConfirmationUI() - : listener_state_(ListenerState::None), prompt_result_(ResponseCode::Ignored) {} + : listener_state_(ListenerState::None), prompt_result_(IConfirmationUI::IGNORED) {} TrustyConfirmationUI::~TrustyConfirmationUI() { ListenerState state = listener_state_; @@ -385,15 +377,16 @@ TrustyConfirmationUI::promptUserConfirmation_(const MsgString& promptText, // ############################## Start 4th Phase - cleanup ################################## } -// Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI +// Methods from ::aidl::android::hardware::confirmationui::IConfirmationUI // follow. -Return TrustyConfirmationUI::promptUserConfirmation( - const sp& resultCB, const hidl_string& promptText, - const hidl_vec& extraData, const hidl_string& locale, - const hidl_vec& uiOptions) { +::ndk::ScopedAStatus TrustyConfirmationUI::promptUserConfirmation( + const shared_ptr& resultCB, const vector& promptTextBytes, + const vector& extraData, const string& locale, const vector& uiOptions) { std::unique_lock stateLock(listener_state_lock_, std::defer_lock); + string promptText(promptTextBytes.begin(), promptTextBytes.end()); if (!stateLock.try_lock()) { - return ResponseCode::OperationPending; + return ndk::ScopedAStatus( + AStatus_fromServiceSpecificError(IConfirmationUI::OPERATION_PENDING)); } switch (listener_state_) { case ListenerState::None: @@ -401,23 +394,25 @@ Return TrustyConfirmationUI::promptUserConfirmation( case ListenerState::Starting: case ListenerState::SetupDone: case ListenerState::Interactive: - return ResponseCode::OperationPending; + return ndk::ScopedAStatus( + AStatus_fromServiceSpecificError(IConfirmationUI::OPERATION_PENDING)); case ListenerState::Terminating: callback_thread_.join(); listener_state_ = ListenerState::None; break; default: - return ResponseCode::Unexpected; + return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(IConfirmationUI::UNEXPECTED)); } assert(listener_state_ == ListenerState::None); callback_thread_ = std::thread( - [this](sp resultCB, hidl_string promptText, - hidl_vec extraData, hidl_string locale, hidl_vec uiOptions) { - auto [trc, msg, token] = - promptUserConfirmation_(hidl2MsgString(promptText), hidl2MsgVector(extraData), - hidl2MsgString(locale), hidl2MsgVector(uiOptions)); + [this](const shared_ptr& resultCB, const string& promptText, + const vector& extraData, const string& locale, + const vector& uiOptions) { + auto [trc, msg, token] = promptUserConfirmation_( + stdString2MsgString(promptText), stdVector2MsgVector(extraData), + stdString2MsgString(locale), stdVector2MsgVector(uiOptions)); bool do_callback = (listener_state_ == ListenerState::Interactive || listener_state_ == ListenerState::SetupDone) && resultCB; @@ -426,7 +421,7 @@ Return TrustyConfirmationUI::promptUserConfirmation( if (do_callback) { auto error = resultCB->result(prompt_result_, msg, token); if (!error.isOk()) { - LOG(ERROR) << "Result callback failed " << error.description(); + LOG(ERROR) << "Result callback failed " << error.getDescription(); } } else { listener_state_condv_.notify_all(); @@ -442,14 +437,14 @@ Return TrustyConfirmationUI::promptUserConfirmation( if (listener_state_ == ListenerState::Terminating) { callback_thread_.join(); listener_state_ = ListenerState::None; - return prompt_result_; + return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(prompt_result_)); } - return ResponseCode::OK; + return ndk::ScopedAStatus::ok(); } -Return +::ndk::ScopedAStatus TrustyConfirmationUI::deliverSecureInputEvent(const HardwareAuthToken& secureInputToken) { - ResponseCode rc = ResponseCode::Ignored; + int rc = IConfirmationUI::IGNORED; { /* * deliverSecureInputEvent is only used by the VTS test to mock human input. A correct @@ -467,13 +462,17 @@ TrustyConfirmationUI::deliverSecureInputEvent(const HardwareAuthToken& secureInp listener_state_condv_.wait(stateLock, [this] { return listener_state_ != ListenerState::SetupDone; }); - if (listener_state_ != ListenerState::Interactive) return ResponseCode::Ignored; + if (listener_state_ != ListenerState::Interactive) + return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(IConfirmationUI::IGNORED)); auto sapp = app_.lock(); - if (!sapp) return ResponseCode::Ignored; + if (!sapp) + return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(IConfirmationUI::IGNORED)); auto [error, response] = sapp->issueCmd( static_cast(secureInputToken.challenge)); - if (error != TrustyAppError::OK) return ResponseCode::SystemError; + if (error != TrustyAppError::OK) + return ndk::ScopedAStatus( + AStatus_fromServiceSpecificError(IConfirmationUI::SYSTEM_ERROR)); auto& [trc] = response; if (trc != TeeuiRc::Ignored) secureInputDelivered_ = true; rc = convertRc(trc); @@ -484,11 +483,14 @@ TrustyConfirmationUI::deliverSecureInputEvent(const HardwareAuthToken& secureInp // Canceled into OK. Canceled is only returned if the delivered event canceled // the operation, which means that the event was successfully delivered. Thus // we return OK. - if (rc == ResponseCode::Canceled) return ResponseCode::OK; - return rc; + if (rc == IConfirmationUI::CANCELED) return ndk::ScopedAStatus::ok(); + if (rc != IConfirmationUI::OK) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(rc)); + } + return ndk::ScopedAStatus::ok(); } -Return TrustyConfirmationUI::abort() { +::ndk::ScopedAStatus TrustyConfirmationUI::abort() { { std::unique_lock stateLock(listener_state_lock_); if (listener_state_ == ListenerState::SetupDone || @@ -499,15 +501,11 @@ Return TrustyConfirmationUI::abort() { } } listener_state_condv_.notify_all(); - return Void(); + return ndk::ScopedAStatus::ok(); } -android::sp createTrustyConfirmationUI() { - return new TrustyConfirmationUI(); +std::shared_ptr createTrustyConfirmationUI() { + return ndk::SharedRefBase::make(); } -} // namespace implementation -} // namespace V1_0 -} // namespace confirmationui -} // namespace hardware -} // namespace android +} // namespace aidl::android::hardware::confirmationui diff --git a/trusty/confirmationui/TrustyConfirmationUI.h b/trusty/confirmationui/TrustyConfirmationUI.h index 0bd703c9fd36..6e85704b61c7 100644 --- a/trusty/confirmationui/TrustyConfirmationUI.h +++ b/trusty/confirmationui/TrustyConfirmationUI.h @@ -17,9 +17,11 @@ #ifndef ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_TRUSTY_CONFIRMATIONUI_H #define ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_TRUSTY_CONFIRMATIONUI_H -#include -#include -#include +#include +#include +#include +#include +#include #include #include @@ -30,35 +32,29 @@ #include "TrustyApp.h" -namespace android { -namespace hardware { -namespace confirmationui { -namespace V1_0 { -namespace implementation { +namespace aidl::android::hardware::confirmationui { -using ::android::sp; -using ::android::hardware::hidl_array; -using ::android::hardware::hidl_string; -using ::android::hardware::hidl_vec; -using ::android::hardware::Return; -using ::android::hardware::Void; +using std::shared_ptr; +using std::string; +using std::vector; +using ::aidl::android::hardware::security::keymint::HardwareAuthToken; using ::android::trusty::confirmationui::TrustyApp; -class TrustyConfirmationUI : public IConfirmationUI { +class TrustyConfirmationUI : public BnConfirmationUI { public: TrustyConfirmationUI(); virtual ~TrustyConfirmationUI(); - // Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI + // Methods from ::aidl::android::hardware::confirmationui::IConfirmationUI // follow. - Return promptUserConfirmation(const sp& resultCB, - const hidl_string& promptText, - const hidl_vec& extraData, - const hidl_string& locale, - const hidl_vec& uiOptions) override; - Return deliverSecureInputEvent( - const ::android::hardware::keymaster::V4_0::HardwareAuthToken& secureInputToken) override; - Return abort() override; + ::ndk::ScopedAStatus + promptUserConfirmation(const shared_ptr& resultCB, + const vector& promptText, const vector& extraData, + const string& locale, const vector& uiOptions) override; + ::ndk::ScopedAStatus + deliverSecureInputEvent(const HardwareAuthToken& secureInputToken) override; + + ::ndk::ScopedAStatus abort() override; private: std::weak_ptr app_; @@ -85,7 +81,7 @@ class TrustyConfirmationUI : public IConfirmationUI { bool abort_called_; std::mutex listener_state_lock_; std::condition_variable listener_state_condv_; - ResponseCode prompt_result_; + int prompt_result_; bool secureInputDelivered_; std::tuple, teeui::MsgVector> @@ -95,10 +91,6 @@ class TrustyConfirmationUI : public IConfirmationUI { const teeui::MsgVector& uiOptions); }; -} // namespace implementation -} // namespace V1_0 -} // namespace confirmationui -} // namespace hardware -} // namespace android +} // namespace aidl::android::hardware::confirmationui #endif // ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_TRUSTY_CONFIRMATIONUI_H diff --git a/trusty/confirmationui/android.hardware.confirmationui-service.trusty.rc b/trusty/confirmationui/android.hardware.confirmationui-service.trusty.rc new file mode 100644 index 000000000000..b5c315986747 --- /dev/null +++ b/trusty/confirmationui/android.hardware.confirmationui-service.trusty.rc @@ -0,0 +1,5 @@ +service vendor.confirmationui_default /vendor/bin/hw/android.hardware.confirmationui-service.trusty + interface aidl android.hardware.confirmationui.IConfirmationUI/default + class hal + user system + group drmrpc input system diff --git a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.xml b/trusty/confirmationui/android.hardware.confirmationui-service.trusty.xml similarity index 71% rename from trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.xml rename to trusty/confirmationui/android.hardware.confirmationui-service.trusty.xml index 9008b872e68e..afa2e8e66e89 100644 --- a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.xml +++ b/trusty/confirmationui/android.hardware.confirmationui-service.trusty.xml @@ -1,8 +1,7 @@ - + android.hardware.confirmationui - hwbinder - 1.0 + 1 IConfirmationUI default diff --git a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc deleted file mode 100644 index 3ba6fc04b9b3..000000000000 --- a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc +++ /dev/null @@ -1,4 +0,0 @@ -service confirmationui-1-0 /vendor/bin/hw/android.hardware.confirmationui@1.0-service.trusty - class hal - user system - group drmrpc input system diff --git a/trusty/confirmationui/include/TrustyConfirmationuiHal.h b/trusty/confirmationui/include/TrustyConfirmationuiHal.h index 2ab9389b1b72..8000ee2f0678 100644 --- a/trusty/confirmationui/include/TrustyConfirmationuiHal.h +++ b/trusty/confirmationui/include/TrustyConfirmationuiHal.h @@ -16,18 +16,10 @@ #pragma once -#include +#include -namespace android { -namespace hardware { -namespace confirmationui { -namespace V1_0 { -namespace implementation { +namespace aidl::android::hardware::confirmationui { -android::sp createTrustyConfirmationUI(); +std::shared_ptr createTrustyConfirmationUI(); -} // namespace implementation -} // namespace V1_0 -} // namespace confirmationui -} // namespace hardware -} // namespace android +} // namespace aidl::android::hardware::confirmationui diff --git a/trusty/confirmationui/service.cpp b/trusty/confirmationui/service.cpp index dd7e84b444fd..b286c0a985ab 100644 --- a/trusty/confirmationui/service.cpp +++ b/trusty/confirmationui/service.cpp @@ -15,21 +15,28 @@ */ #include -#include +#include +#include #include -using android::sp; -using android::hardware::confirmationui::V1_0::implementation::createTrustyConfirmationUI; +using ::aidl::android::hardware::confirmationui::createTrustyConfirmationUI; +using ::aidl::android::hardware::confirmationui::IConfirmationUI; int main() { - ::android::hardware::configureRpcThreadpool(1, true /*willJoinThreadpool*/); - auto service = createTrustyConfirmationUI(); - auto status = service->registerAsService(); - if (status != android::OK) { - LOG(FATAL) << "Could not register service for ConfirmationUI 1.0 (" << status << ")"; + ABinderProcess_setThreadPoolMaxThreadCount(0); + + auto confirmationui = createTrustyConfirmationUI(); + + const auto instance = std::string(IConfirmationUI::descriptor) + "/default"; + binder_status_t status = + AServiceManager_addService(confirmationui->asBinder().get(), instance.c_str()); + + if (status != STATUS_OK) { + LOG(FATAL) << "Could not register service for " << instance.c_str() << "(" << status << ")"; return -1; } - ::android::hardware::joinRpcThreadpool(); + + ABinderProcess_joinThreadPool(); return -1; } From 23d35bbfafc784a7dfe686e7954a53cac60caf2b Mon Sep 17 00:00:00 2001 From: Wayne Ma Date: Wed, 28 Sep 2022 15:23:04 +0800 Subject: [PATCH 0011/1487] Make libstatspull_bindgen available to resolv apex. Test: m successed Change-Id: Ia367ab5a87794c82238291b27a783278f319e767 (cherry picked from commit 8044045a1ecf2afae948a9877341b1ea372f2a80) Merged-In: Ia367ab5a87794c82238291b27a783278f319e767 --- libstats/pull_rust/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/libstats/pull_rust/Android.bp b/libstats/pull_rust/Android.bp index 4ffa98d1446f..cc9f5b4cf5a9 100644 --- a/libstats/pull_rust/Android.bp +++ b/libstats/pull_rust/Android.bp @@ -47,6 +47,7 @@ rust_bindgen { min_sdk_version: "apex_inherit", apex_available: [ "//apex_available:platform", + "com.android.resolv", "com.android.virt", ] } From b5f75c4ecbcfeff6f4bc78b8d24e638b51339e51 Mon Sep 17 00:00:00 2001 From: Seth Moore Date: Wed, 2 Nov 2022 21:41:58 -0700 Subject: [PATCH 0012/1487] Add dependency on split out RKP HAL Bug: 254112961 Test: N/A Ignore-AOSP-First: need to fix internal-only dependencies first Change-Id: Ia13374cbc4f29964d91da3ce31d5fffa4d54d5ce --- trusty/keymaster/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp index adc9fdffb72d..31f0a7224998 100644 --- a/trusty/keymaster/Android.bp +++ b/trusty/keymaster/Android.bp @@ -109,6 +109,7 @@ cc_binary { "keymint_use_latest_hal_aidl_ndk_shared", ], shared_libs: [ + "android.hardware.security.rkp-V3-ndk", "android.hardware.security.secureclock-V1-ndk", "android.hardware.security.sharedsecret-V1-ndk", "lib_android_keymaster_keymint_utils", From 9d99701bead30ffc6a9849fb33024680082ca782 Mon Sep 17 00:00:00 2001 From: Seth Moore Date: Fri, 4 Nov 2022 16:40:46 +0000 Subject: [PATCH 0013/1487] Revert "Add dependency on split out RKP HAL" Revert "Add dependency on split out RKP HAL" Revert "Split rkp from keymint." Revert "Add dependency on newly-split RKP HAL" Revert "Add dependencies on newly-split RKP HAL" Revert "Add dependency on split out RKP HAL" Revert submission 20364235-split-rkp-aidl Reason for revert: Build break in android.hardware.identity-api Reverted Changes: Ib86454bbb:Update dependencies on HAL types moved from keymin... I501c967e2:Add dependencies on newly-split RKP HAL I08560f9af:Add dependency on split out RKP HAL I87133e385:Add dependency on split out RKP HAL Ia13374cbc:Add dependency on split out RKP HAL I72bc1774c:Add dependency on newly-split RKP HAL I71ac265e3:Add dependency on newly-split RKP HAL Ie0e17bb2c:Update the RKP aidl dependency I5d24f47ce:Update README and CHANGELOG for RKP I4b2498dd1:Split rkp from keymint. I266009d75:Add dependency on newly-split rkp HAL Change-Id: Ibac15817a4d2170e4c8c36956d7be1ad0f3cb8a8 --- trusty/keymaster/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp index 31f0a7224998..adc9fdffb72d 100644 --- a/trusty/keymaster/Android.bp +++ b/trusty/keymaster/Android.bp @@ -109,7 +109,6 @@ cc_binary { "keymint_use_latest_hal_aidl_ndk_shared", ], shared_libs: [ - "android.hardware.security.rkp-V3-ndk", "android.hardware.security.secureclock-V1-ndk", "android.hardware.security.sharedsecret-V1-ndk", "lib_android_keymaster_keymint_utils", From 681abb61a2ad8b626019b8c117055856019e8a1d Mon Sep 17 00:00:00 2001 From: Seth Moore Date: Fri, 4 Nov 2022 17:39:05 +0000 Subject: [PATCH 0014/1487] Revert^2 "Add dependency on split out RKP HAL" 9d99701bead30ffc6a9849fb33024680082ca782 Change-Id: I9dcb9b94b0e22466cd42592f4921eec3e4fcb13d --- trusty/keymaster/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp index adc9fdffb72d..31f0a7224998 100644 --- a/trusty/keymaster/Android.bp +++ b/trusty/keymaster/Android.bp @@ -109,6 +109,7 @@ cc_binary { "keymint_use_latest_hal_aidl_ndk_shared", ], shared_libs: [ + "android.hardware.security.rkp-V3-ndk", "android.hardware.security.secureclock-V1-ndk", "android.hardware.security.sharedsecret-V1-ndk", "lib_android_keymaster_keymint_utils", From ecfbf9c6f48915b76a62c2668137a985e04d1436 Mon Sep 17 00:00:00 2001 From: Jiakai Zhang Date: Tue, 6 Dec 2022 15:42:48 +0000 Subject: [PATCH 0015/1487] Add task profile "Dex2OatBackground". Bug: 261557677 Test: Presubmit Ignore-AOSP-First: Will cherry-pick as soon as the CL is merged. Change-Id: I33f4d1d2270da82cf90a772ef52b450bcecafec2 --- libprocessgroup/profiles/task_profiles.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json index 15f95fcff3fb..39c124e94f4c 100644 --- a/libprocessgroup/profiles/task_profiles.json +++ b/libprocessgroup/profiles/task_profiles.json @@ -805,6 +805,10 @@ "Name": "Dex2OatBootComplete", "Profiles": [ "Dex2oatPerformance", "LowIoPriority", "TimerSlackHigh" ] }, + { + "Name": "Dex2OatBootBackground", + "Profiles": [ "Dex2OatBootComplete" ] + }, { "Name": "OtaProfiles", "Profiles": [ "ServiceCapacityLow", "LowIoPriority", "HighEnergySaving" ] From ab9b5df4b84d83426006d1e84b0c361ae8c9b18e Mon Sep 17 00:00:00 2001 From: Zhi Dou Date: Fri, 9 Dec 2022 22:30:57 +0000 Subject: [PATCH 0016/1487] Replace "apex_inherit" min_sdk_version Replace "apex_inherit" min_sdk_version to a conditional setting. If environment veriable KEEP_APEX_INHERIT is set, using "apex_inherit" as the min_sdk_version, otherwise set the number to "29". For more detail please refer https://docs.google.com/document/d/1R2vZw0cQa-haAMgFyQ682uSq9aGBNQrzMHKIsU17-XY/edit?usp=sharing&resourcekey=0-gUbs463r9LCKs7vdP_Xkmg Test: build APEX uses this library, and presubmit Bug: 254634795 Ignore-AOSP-First: Need to submit with other changes. Change-Id: Ie6984128e6b84ba73de3f4c08eca5560657c5ca2 --- libutils/Android.bp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libutils/Android.bp b/libutils/Android.bp index af4a3dc5d565..d77efd6dfb6a 100644 --- a/libutils/Android.bp +++ b/libutils/Android.bp @@ -21,11 +21,13 @@ cc_library_headers { vendor_ramdisk_available: true, host_supported: true, native_bridge_supported: true, + defaults: [ + "apex-lowest-min-sdk-version", + ], apex_available: [ "//apex_available:platform", "//apex_available:anyapex", ], - min_sdk_version: "apex_inherit", header_libs: [ "libbase_headers", @@ -124,7 +126,10 @@ cc_defaults { cc_defaults { name: "libutils_impl_defaults", - defaults: ["libutils_defaults"], + defaults: [ + "libutils_defaults", + "apex-lowest-min-sdk-version", + ], native_bridge_supported: true, srcs: [ @@ -167,7 +172,6 @@ cc_defaults { "//apex_available:anyapex", "//apex_available:platform", ], - min_sdk_version: "apex_inherit", afdo: true, } From 473f03bfd9497abe614ea34d96c8b6305c31a1ff Mon Sep 17 00:00:00 2001 From: Jiakai Zhang Date: Fri, 9 Dec 2022 23:50:58 +0000 Subject: [PATCH 0017/1487] Rename "Dex2OatBootBackground" to "Dex2OatBackground". Bug: 261557677 Change-Id: I52e778d13cffcae4212acb05ef2bd62b827fbaf3 Test: Presubmit Ignore-AOSP-First: Will cherry-pick as soon as the CL is merged. --- libprocessgroup/profiles/task_profiles.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json index 39c124e94f4c..c485097882fc 100644 --- a/libprocessgroup/profiles/task_profiles.json +++ b/libprocessgroup/profiles/task_profiles.json @@ -806,7 +806,7 @@ "Profiles": [ "Dex2oatPerformance", "LowIoPriority", "TimerSlackHigh" ] }, { - "Name": "Dex2OatBootBackground", + "Name": "Dex2OatBackground", "Profiles": [ "Dex2OatBootComplete" ] }, { From 8ef2a47c0aae39188d40e6c1936b6dd03776fa7d Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Wed, 23 Mar 2022 18:40:02 +0000 Subject: [PATCH 0018/1487] snapuserd: Update verification Initiate update verification from daemon. This will help in two ways: 1: We avoid reading everything into page-cache. Since, low end devices are already short on memory, we don't want to read and populate page-cache which can slow down boot. 2: During boot, once the selinux transition is done, daemon is all ready to kick off the verification since verity is already setup. Note that we are still guarded by update_verifier. Update_verifier will still block marking new slot as boot success until the verification is completed. So, there is no change in the behavior. Bug: 193863442 Bug: 261913544 Test: Full and incremental OTA on Pixel 6 Incremental OTA of 500M (Monthly OTA) Boot-time (Without this patch): 38 seconds Boot-time (With this patch): 32 seconds Full OTA of 2.2G: Boot-time (Without this patch): 27 seconds Boot-time (With this patch): 21 seconds Signed-off-by: Akilesh Kailash Merged-In: I4f17db19bdd0dd261902c670be6212862d861fe1 Change-Id: I4f17db19bdd0dd261902c670be6212862d861fe1 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 7 + .../include/snapuserd/snapuserd_client.h | 4 + .../snapuserd/snapuserd_client.cpp | 10 + .../user-space-merge/snapuserd_core.cpp | 242 +----------------- .../user-space-merge/snapuserd_core.h | 45 +++- .../user-space-merge/snapuserd_server.cpp | 26 ++ .../user-space-merge/snapuserd_server.h | 3 + .../user-space-merge/snapuserd_verify.cpp | 222 ++++++++++++++++ 8 files changed, 320 insertions(+), 239 deletions(-) create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index bc2bcebbf2d5..d751fb88f875 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -47,6 +47,7 @@ cc_library_static { "libbase", "liblog", ], + export_include_dirs: ["include"], ramdisk_available: true, } @@ -68,6 +69,7 @@ cc_defaults { "user-space-merge/snapuserd_readahead.cpp", "user-space-merge/snapuserd_transitions.cpp", "user-space-merge/snapuserd_server.cpp", + "user-space-merge/snapuserd_verify.cpp", ], cflags: [ @@ -88,6 +90,11 @@ cc_defaults { "libext4_utils", "liburing", ], + + header_libs: [ + "libstorage_literals_headers", + ], + include_dirs: ["bionic/libc/kernel"], } diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h index cebda1ccb0d4..9a69d588cf32 100644 --- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h +++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h @@ -89,6 +89,10 @@ class SnapuserdClient { // Return the status of the snapshot std::string QuerySnapshotStatus(const std::string& misc_name); + + // Check the update verification status - invoked by update_verifier during + // boot + bool QueryUpdateVerification(); }; } // namespace snapshot diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp index 7b1c7a3a662a..e08cf9b590ed 100644 --- a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp +++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp @@ -269,5 +269,15 @@ std::string SnapuserdClient::QuerySnapshotStatus(const std::string& misc_name) { return Receivemsg(); } +bool SnapuserdClient::QueryUpdateVerification() { + std::string msg = "update-verify"; + if (!Sendmsg(msg)) { + LOG(ERROR) << "Failed to send message " << msg << " to snapuserd"; + return false; + } + std::string response = Receivemsg(); + return response == "success"; +} + } // namespace snapshot } // namespace android 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 718c13ce0b40..8939b786c28c 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -18,6 +18,7 @@ #include +#include #include #include #include @@ -70,6 +71,9 @@ bool SnapshotHandler::InitializeWorkers() { read_ahead_thread_ = std::make_unique(cow_device_, backing_store_device_, misc_name_, GetSharedPtr()); + + update_verify_ = std::make_unique(misc_name_); + return true; } @@ -307,206 +311,6 @@ bool SnapshotHandler::InitCowDevice() { return ReadMetadata(); } -void SnapshotHandler::FinalizeIouring() { - io_uring_queue_exit(ring_.get()); -} - -bool SnapshotHandler::InitializeIouring(int io_depth) { - ring_ = std::make_unique(); - - int ret = io_uring_queue_init(io_depth, ring_.get(), 0); - if (ret) { - LOG(ERROR) << "io_uring_queue_init failed with ret: " << ret; - return false; - } - - LOG(INFO) << "io_uring_queue_init success with io_depth: " << io_depth; - return true; -} - -bool SnapshotHandler::ReadBlocksAsync(const std::string& dm_block_device, - const std::string& partition_name, size_t size) { - // 64k block size with io_depth of 64 is optimal - // for a single thread. We just need a single thread - // to read all the blocks from all dynamic partitions. - size_t io_depth = 64; - size_t bs = (64 * 1024); - - if (!InitializeIouring(io_depth)) { - return false; - } - - LOG(INFO) << "ReadBlockAsync start " - << " Block-device: " << dm_block_device << " Partition-name: " << partition_name - << " Size: " << size; - - auto scope_guard = android::base::make_scope_guard([this]() -> void { FinalizeIouring(); }); - - std::vector> vecs; - using AlignedBuf = std::unique_ptr; - std::vector alignedBufVector; - - /* - * TODO: We need aligned memory for DIRECT-IO. However, if we do - * a DIRECT-IO and verify the blocks then we need to inform - * update-verifier that block verification has been done and - * there is no need to repeat the same. We are not there yet - * as we need to see if there are any boot time improvements doing - * a DIRECT-IO. - * - * Also, we could you the same function post merge for block verification; - * again, we can do a DIRECT-IO instead of thrashing page-cache and - * hurting other applications. - * - * For now, we will just create aligned buffers but rely on buffered - * I/O until we have perf numbers to justify DIRECT-IO. - */ - for (int i = 0; i < io_depth; i++) { - auto iovec = std::make_unique(); - vecs.push_back(std::move(iovec)); - - struct iovec* iovec_ptr = vecs[i].get(); - - if (posix_memalign(&iovec_ptr->iov_base, BLOCK_SZ, bs)) { - LOG(ERROR) << "posix_memalign failed"; - return false; - } - - iovec_ptr->iov_len = bs; - alignedBufVector.push_back( - std::unique_ptr(iovec_ptr->iov_base, free)); - } - - android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY))); - if (fd.get() == -1) { - SNAP_PLOG(ERROR) << "File open failed - block-device " << dm_block_device - << " partition-name: " << partition_name; - return false; - } - - loff_t offset = 0; - size_t remain = size; - size_t read_sz = io_depth * bs; - - while (remain > 0) { - size_t to_read = std::min(remain, read_sz); - size_t queue_size = to_read / bs; - - for (int i = 0; i < queue_size; i++) { - struct io_uring_sqe* sqe = io_uring_get_sqe(ring_.get()); - if (!sqe) { - SNAP_LOG(ERROR) << "io_uring_get_sqe() failed"; - return false; - } - - struct iovec* iovec_ptr = vecs[i].get(); - - io_uring_prep_read(sqe, fd.get(), iovec_ptr->iov_base, iovec_ptr->iov_len, offset); - sqe->flags |= IOSQE_ASYNC; - offset += bs; - } - - int ret = io_uring_submit(ring_.get()); - if (ret != queue_size) { - SNAP_LOG(ERROR) << "submit got: " << ret << " wanted: " << queue_size; - return false; - } - - for (int i = 0; i < queue_size; i++) { - struct io_uring_cqe* cqe; - - int ret = io_uring_wait_cqe(ring_.get(), &cqe); - if (ret) { - SNAP_PLOG(ERROR) << "wait_cqe failed" << ret; - return false; - } - - if (cqe->res < 0) { - SNAP_LOG(ERROR) << "io failed with res: " << cqe->res; - return false; - } - io_uring_cqe_seen(ring_.get(), cqe); - } - - remain -= to_read; - } - - LOG(INFO) << "ReadBlockAsync complete: " - << " Block-device: " << dm_block_device << " Partition-name: " << partition_name - << " Size: " << size; - return true; -} - -void SnapshotHandler::ReadBlocksToCache(const std::string& dm_block_device, - const std::string& partition_name, off_t offset, - size_t size) { - android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY))); - if (fd.get() == -1) { - SNAP_PLOG(ERROR) << "Error reading " << dm_block_device - << " partition-name: " << partition_name; - return; - } - - size_t remain = size; - off_t file_offset = offset; - // We pick 4M I/O size based on the fact that the current - // update_verifier has a similar I/O size. - size_t read_sz = 1024 * BLOCK_SZ; - std::vector buf(read_sz); - - while (remain > 0) { - size_t to_read = std::min(remain, read_sz); - - if (!android::base::ReadFullyAtOffset(fd.get(), buf.data(), to_read, file_offset)) { - SNAP_PLOG(ERROR) << "Failed to read block from block device: " << dm_block_device - << " at offset: " << file_offset - << " partition-name: " << partition_name << " total-size: " << size - << " remain_size: " << remain; - return; - } - - file_offset += to_read; - remain -= to_read; - } - - SNAP_LOG(INFO) << "Finished reading block-device: " << dm_block_device - << " partition: " << partition_name << " size: " << size - << " offset: " << offset; -} - -void SnapshotHandler::ReadBlocks(const std::string partition_name, - const std::string& dm_block_device) { - SNAP_LOG(DEBUG) << "Reading partition: " << partition_name - << " Block-Device: " << dm_block_device; - - uint64_t dev_sz = 0; - - unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY | O_CLOEXEC))); - if (fd < 0) { - SNAP_LOG(ERROR) << "Cannot open block device"; - return; - } - - dev_sz = get_block_device_size(fd.get()); - if (!dev_sz) { - SNAP_PLOG(ERROR) << "Could not determine block device size: " << dm_block_device; - return; - } - - int num_threads = 2; - size_t num_blocks = dev_sz >> BLOCK_SHIFT; - size_t num_blocks_per_thread = num_blocks / num_threads; - size_t read_sz_per_thread = num_blocks_per_thread << BLOCK_SHIFT; - off_t offset = 0; - - for (int i = 0; i < num_threads; i++) { - std::async(std::launch::async, &SnapshotHandler::ReadBlocksToCache, this, dm_block_device, - partition_name, offset, read_sz_per_thread); - - offset += read_sz_per_thread; - } -} - /* * Entry point to launch threads */ @@ -527,42 +331,22 @@ bool SnapshotHandler::Start() { std::async(std::launch::async, &Worker::RunThread, worker_threads_[i].get())); } - bool second_stage_init = true; + bool partition_verification = true; - // We don't want to read the blocks during first stage init. + // We don't want to read the blocks during first stage init or + // during post-install phase. if (android::base::EndsWith(misc_name_, "-init") || is_socket_present_) { - second_stage_init = false; - } - - if (second_stage_init) { - SNAP_LOG(INFO) << "Reading blocks to cache...."; - auto& dm = DeviceMapper::Instance(); - auto dm_block_devices = dm.FindDmPartitions(); - if (dm_block_devices.empty()) { - SNAP_LOG(ERROR) << "No dm-enabled block device is found."; - } else { - auto parts = android::base::Split(misc_name_, "-"); - std::string partition_name = parts[0]; - - const char* suffix_b = "_b"; - const char* suffix_a = "_a"; - - partition_name.erase(partition_name.find_last_not_of(suffix_b) + 1); - partition_name.erase(partition_name.find_last_not_of(suffix_a) + 1); - - if (dm_block_devices.find(partition_name) == dm_block_devices.end()) { - SNAP_LOG(ERROR) << "Failed to find dm block device for " << partition_name; - } else { - ReadBlocks(partition_name, dm_block_devices.at(partition_name)); - } - } - } else { - SNAP_LOG(INFO) << "Not reading block device into cache"; + partition_verification = false; } std::future merge_thread = std::async(std::launch::async, &Worker::RunMergeThread, merge_thread_.get()); + // Now that the worker threads are up, scan the partitions. + if (partition_verification) { + update_verify_->VerifyUpdatePartition(); + } + bool ret = true; for (auto& t : threads) { ret = t.get() && ret; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index c6805e5d9434..42237ef602c0 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -45,12 +45,14 @@ #include #include #include +#include namespace android { namespace snapshot { using android::base::unique_fd; using namespace std::chrono_literals; +using namespace android::storage_literals; static constexpr size_t PAYLOAD_BUFFER_SZ = (1UL << 20); static_assert(PAYLOAD_BUFFER_SZ >= BLOCK_SZ); @@ -170,6 +172,36 @@ class ReadAhead { std::unique_ptr ring_; }; +class UpdateVerify { + public: + UpdateVerify(const std::string& misc_name); + void VerifyUpdatePartition(); + bool CheckPartitionVerification(); + + private: + enum class UpdateVerifyState { + VERIFY_UNKNOWN, + VERIFY_FAILED, + VERIFY_SUCCESS, + }; + + std::string misc_name_; + UpdateVerifyState state_; + std::mutex m_lock_; + std::condition_variable m_cv_; + + int kMinThreadsToVerify = 1; + int kMaxThreadsToVerify = 4; + uint64_t kThresholdSize = 512_MiB; + uint64_t kBlockSizeVerify = 1_MiB; + + bool IsBlockAligned(uint64_t read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } + void UpdatePartitionVerificationState(UpdateVerifyState state); + bool VerifyPartition(const std::string& partition_name, const std::string& dm_block_device); + bool VerifyBlocks(const std::string& partition_name, const std::string& dm_block_device, + off_t offset, int skip_blocks, uint64_t dev_sz); +}; + class Worker { public: Worker(const std::string& cow_device, const std::string& backing_device, @@ -352,24 +384,16 @@ class SnapshotHandler : public std::enable_shared_from_this { MERGE_GROUP_STATE ProcessMergingBlock(uint64_t new_block, void* buffer); bool IsIouringSupported(); + bool CheckPartitionVerification() { return update_verify_->CheckPartitionVerification(); } private: bool ReadMetadata(); sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; } chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; } - bool IsBlockAligned(int read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } + bool IsBlockAligned(uint64_t read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } struct BufferState* GetBufferState(); void UpdateMergeCompletionPercentage(); - void ReadBlocks(const std::string partition_name, const std::string& dm_block_device); - void ReadBlocksToCache(const std::string& dm_block_device, const std::string& partition_name, - off_t offset, size_t size); - - bool InitializeIouring(int io_depth); - void FinalizeIouring(); - bool ReadBlocksAsync(const std::string& dm_block_device, const std::string& partition_name, - size_t size); - // COW device std::string cow_device_; // Source device @@ -422,6 +446,7 @@ class SnapshotHandler : public std::enable_shared_from_this { bool scratch_space_ = false; std::unique_ptr ring_; + std::unique_ptr update_verify_; }; } // namespace snapshot 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 5d93f01a749d..1e7daed3995f 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp @@ -55,6 +55,7 @@ DaemonOps UserSnapshotServer::Resolveop(std::string& input) { if (input == "initiate_merge") return DaemonOps::INITIATE; if (input == "merge_percent") return DaemonOps::PERCENTAGE; if (input == "getstatus") return DaemonOps::GETSTATUS; + if (input == "update-verify") return DaemonOps::UPDATE_VERIFY; return DaemonOps::INVALID; } @@ -290,6 +291,14 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st return Sendmsg(fd, merge_status); } } + case DaemonOps::UPDATE_VERIFY: { + std::lock_guard lock(lock_); + if (!UpdateVerification(&lock)) { + return Sendmsg(fd, "fail"); + } + + return Sendmsg(fd, "success"); + } default: { LOG(ERROR) << "Received unknown message type from client"; Sendmsg(fd, "fail"); @@ -750,5 +759,22 @@ bool UserSnapshotServer::RunForSocketHandoff() { return true; } +bool UserSnapshotServer::UpdateVerification(std::lock_guard* proof_of_lock) { + CHECK(proof_of_lock); + + bool status = true; + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + auto& th = (*iter)->thread(); + if (th.joinable() && status) { + status = (*iter)->snapuserd()->CheckPartitionVerification() && status; + } else { + // return immediately if there is a failure + return false; + } + } + + return status; +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h index e0844aeb1a66..c2af61fbfd6f 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h @@ -50,6 +50,7 @@ enum class DaemonOps { INITIATE, PERCENTAGE, GETSTATUS, + UPDATE_VERIFY, INVALID, }; @@ -130,6 +131,8 @@ class UserSnapshotServer { double GetMergePercentage(std::lock_guard* proof_of_lock); void TerminateMergeThreads(std::lock_guard* proof_of_lock); + bool UpdateVerification(std::lock_guard* proof_of_lock); + public: UserSnapshotServer(); ~UserSnapshotServer(); diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp new file mode 100644 index 000000000000..18c1dfcd9288 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2022 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 "snapuserd_core.h" + +#include +#include +#include + +namespace android { +namespace snapshot { + +using namespace android; +using namespace android::dm; +using android::base::unique_fd; + +UpdateVerify::UpdateVerify(const std::string& misc_name) + : misc_name_(misc_name), state_(UpdateVerifyState::VERIFY_UNKNOWN) {} + +bool UpdateVerify::CheckPartitionVerification() { + auto now = std::chrono::system_clock::now(); + auto deadline = now + 10s; + { + std::unique_lock cv_lock(m_lock_); + while (state_ == UpdateVerifyState::VERIFY_UNKNOWN) { + auto status = m_cv_.wait_until(cv_lock, deadline); + if (status == std::cv_status::timeout) { + return false; + } + } + } + + return (state_ == UpdateVerifyState::VERIFY_SUCCESS); +} + +void UpdateVerify::UpdatePartitionVerificationState(UpdateVerifyState state) { + { + std::lock_guard lock(m_lock_); + state_ = state; + } + m_cv_.notify_all(); +} + +void UpdateVerify::VerifyUpdatePartition() { + bool succeeded = false; + + auto scope_guard = android::base::make_scope_guard([this, &succeeded]() -> void { + if (!succeeded) { + UpdatePartitionVerificationState(UpdateVerifyState::VERIFY_FAILED); + } + }); + + auto& dm = DeviceMapper::Instance(); + auto dm_block_devices = dm.FindDmPartitions(); + if (dm_block_devices.empty()) { + SNAP_LOG(ERROR) << "No dm-enabled block device is found."; + return; + } + + const auto parts = android::base::Split(misc_name_, "-"); + std::string partition_name = parts[0]; + + constexpr auto&& suffix_b = "_b"; + constexpr auto&& suffix_a = "_a"; + + partition_name.erase(partition_name.find_last_not_of(suffix_b) + 1); + partition_name.erase(partition_name.find_last_not_of(suffix_a) + 1); + + if (dm_block_devices.find(partition_name) == dm_block_devices.end()) { + SNAP_LOG(ERROR) << "Failed to find dm block device for " << partition_name; + return; + } + + if (!VerifyPartition(partition_name, dm_block_devices.at(partition_name))) { + SNAP_LOG(ERROR) << "Partition: " << partition_name + << " Block-device: " << dm_block_devices.at(partition_name) + << " verification failed"; + } + succeeded = true; +} + +bool UpdateVerify::VerifyBlocks(const std::string& partition_name, + const std::string& dm_block_device, off_t offset, int skip_blocks, + uint64_t dev_sz) { + unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY | O_DIRECT))); + if (fd < 0) { + SNAP_LOG(ERROR) << "open failed: " << dm_block_device; + return false; + } + + loff_t file_offset = offset; + const uint64_t read_sz = kBlockSizeVerify; + + void* addr; + ssize_t page_size = getpagesize(); + if (posix_memalign(&addr, page_size, read_sz) < 0) { + SNAP_PLOG(ERROR) << "posix_memalign failed " + << " page_size: " << page_size << " read_sz: " << read_sz; + return false; + } + + std::unique_ptr buffer(addr, ::free); + + uint64_t bytes_read = 0; + + while (true) { + size_t to_read = std::min((dev_sz - file_offset), read_sz); + + if (!android::base::ReadFullyAtOffset(fd.get(), buffer.get(), to_read, file_offset)) { + SNAP_PLOG(ERROR) << "Failed to read block from block device: " << dm_block_device + << " partition-name: " << partition_name + << " at offset: " << file_offset << " read-size: " << to_read + << " block-size: " << dev_sz; + return false; + } + + bytes_read += to_read; + file_offset += (skip_blocks * kBlockSizeVerify); + if (file_offset >= dev_sz) { + break; + } + } + + SNAP_LOG(DEBUG) << "Verification success with bytes-read: " << bytes_read + << " dev_sz: " << dev_sz << " partition_name: " << partition_name; + + return true; +} + +bool UpdateVerify::VerifyPartition(const std::string& partition_name, + const std::string& dm_block_device) { + android::base::Timer timer; + + SNAP_LOG(INFO) << "VerifyPartition: " << partition_name << " Block-device: " << dm_block_device; + + bool succeeded = false; + auto scope_guard = android::base::make_scope_guard([this, &succeeded]() -> void { + if (!succeeded) { + UpdatePartitionVerificationState(UpdateVerifyState::VERIFY_FAILED); + } + }); + + unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY | O_DIRECT))); + if (fd < 0) { + SNAP_LOG(ERROR) << "open failed: " << dm_block_device; + return false; + } + + uint64_t dev_sz = get_block_device_size(fd.get()); + if (!dev_sz) { + SNAP_PLOG(ERROR) << "Could not determine block device size: " << dm_block_device; + return false; + } + + if (!IsBlockAligned(dev_sz)) { + SNAP_LOG(ERROR) << "dev_sz: " << dev_sz << " is not block aligned"; + return false; + } + + /* + * Not all partitions are of same size. Some partitions are as small as + * 100Mb. We can just finish them in a single thread. For bigger partitions + * such as product, 4 threads are sufficient enough. + * + * TODO: With io_uring SQ_POLL support, we can completely cut this + * down to just single thread for all partitions and potentially verify all + * the partitions with zero syscalls. Additionally, since block layer + * supports polling, IO_POLL could be used which will further cut down + * latency. + */ + int num_threads = kMinThreadsToVerify; + if (dev_sz > kThresholdSize) { + num_threads = kMaxThreadsToVerify; + } + + std::vector> threads; + off_t start_offset = 0; + const int skip_blocks = num_threads; + + while (num_threads) { + threads.emplace_back(std::async(std::launch::async, &UpdateVerify::VerifyBlocks, this, + partition_name, dm_block_device, start_offset, skip_blocks, + dev_sz)); + start_offset += kBlockSizeVerify; + num_threads -= 1; + if (start_offset >= dev_sz) { + break; + } + } + + bool ret = true; + for (auto& t : threads) { + ret = t.get() && ret; + } + + if (ret) { + succeeded = true; + UpdatePartitionVerificationState(UpdateVerifyState::VERIFY_SUCCESS); + SNAP_LOG(INFO) << "Partition: " << partition_name << " Block-device: " << dm_block_device + << " Size: " << dev_sz + << " verification success. Duration : " << timer.duration().count() << " ms"; + return true; + } + + return false; +} + +} // namespace snapshot +} // namespace android From d5e026e1af9a3e0d28793cbaa33b28bee953501d Mon Sep 17 00:00:00 2001 From: Alessandra Loro Date: Thu, 1 Sep 2022 10:33:35 +0000 Subject: [PATCH 0019/1487] Resolve ro.debuggable at build time Ignore-AOSP-First: cherry-pick for tm-qpr-dev Test: n/a Bug: 193912100 Bug: 243645021 Merged-In: I83b0021b91536335c63d19f8a65933bad1b26b4e Change-Id: I42c4b1e81383d83c73a565c5e74ac22f17389faf --- debuggerd/Android.bp | 6 ++++++ debuggerd/include/debuggerd/handler.h | 7 ++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index ad0231d8ddbc..51988727d459 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -14,9 +14,15 @@ cc_defaults { "-Wno-nullability-completeness", "-Os", "-fno-finite-loops", + "-DANDROID_DEBUGGABLE=0", ], local_include_dirs: ["include"], + product_variables: { + debuggable: { + cflags: ["-UANDROID_DEBUGGABLE", "-DANDROID_DEBUGGABLE=1"], + } + }, } cc_library_headers { diff --git a/debuggerd/include/debuggerd/handler.h b/debuggerd/include/debuggerd/handler.h index bc08327a1c75..68b2e678b830 100644 --- a/debuggerd/include/debuggerd/handler.h +++ b/debuggerd/include/debuggerd/handler.h @@ -62,10 +62,11 @@ void debuggerd_init(debuggerd_callbacks_t* callbacks); #define DEBUGGER_SIGNAL BIONIC_SIGNAL_DEBUGGER static void __attribute__((__unused__)) debuggerd_register_handlers(struct sigaction* action) { + bool enabled = true; +#if ANDROID_DEBUGGABLE char value[PROP_VALUE_MAX] = ""; - bool enabled = - !(__system_property_get("ro.debuggable", value) > 0 && !strcmp(value, "1") && - __system_property_get("debug.debuggerd.disable", value) > 0 && !strcmp(value, "1")); + enabled = !(__system_property_get("debug.debuggerd.disable", value) > 0 && !strcmp(value, "1")); +#endif if (enabled) { sigaction(SIGABRT, action, nullptr); sigaction(SIGBUS, action, nullptr); From 3182e9c2a29900f08c92ce5980af461723dda8ec Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Wed, 14 Dec 2022 11:24:56 -0800 Subject: [PATCH 0020/1487] init: Take wakelock on zygote restart If the framework is restarting (and cannot yet aquire wakelocks to block suspend). Take a kernel wakelock to allow the system to make sufficient progress before autosuspend can be triggered. The wakelock is later disable when the framework has and invokeds enableAutosuspend() on the suspend service. Bug: 255898234 Bug: 265513788 Bug: 266077359 Test: adb shell "echo mem > /sys/power/state && killall system_server" Change-Id: Id8cff6564ef05d8c22a8264c51dd313263cb6a9d Merged-In: Id8cff6564ef05d8c22a8264c51dd313263cb6a9d --- rootdir/init.zygote32.rc | 3 +++ rootdir/init.zygote64.rc | 3 +++ 2 files changed, 6 insertions(+) diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc index 63b09c0d6334..2f0ec8a17d4c 100644 --- a/rootdir/init.zygote32.rc +++ b/rootdir/init.zygote32.rc @@ -7,6 +7,9 @@ service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-sys socket usap_pool_primary stream 660 root system onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse onrestart write /sys/power/state on + # NOTE: If the wakelock name here is changed, then also + # update it in SystemSuspend.cpp + onrestart write /sys/power/wake_lock zygote_kwl onrestart restart audioserver onrestart restart cameraserver onrestart restart media diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc index 5bde5f469bf2..805267d1dd2b 100644 --- a/rootdir/init.zygote64.rc +++ b/rootdir/init.zygote64.rc @@ -7,6 +7,9 @@ service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-s socket usap_pool_primary stream 660 root system onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse onrestart write /sys/power/state on + # NOTE: If the wakelock name here is changed, then also + # update it in SystemSuspend.cpp + onrestart write /sys/power/wake_lock zygote_kwl onrestart restart audioserver onrestart restart cameraserver onrestart restart media From 90879edeea0b2fd1e766428693d736163f39c511 Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Fri, 20 Jan 2023 13:52:35 -0800 Subject: [PATCH 0021/1487] Listen on property_service_for_system socket It is easy to dos the property_service socket, since it will wait for a complete data packet from one command before moving on to the next one. To prevent low privilege apps interfering with system and root apps, add a second property_service socket that only they can use Bug: 262237198 Test: Run POC in one shell, set properties as root and system in another Ignore-AOSP-First: Security fix Change-Id: I1d6fec833fc24352546bb90f770d3c4b675f5716 --- init/property_service.cpp | 53 +++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/init/property_service.cpp b/init/property_service.cpp index 87ffdb917bf7..14e55b36abbf 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -57,12 +57,12 @@ #include #include #include +#include #include #include #include #include #include - #include "debug_ramdisk.h" #include "epoll.h" #include "init.h" @@ -111,12 +111,13 @@ constexpr auto API_LEVEL_CURRENT = 10000; static bool persistent_properties_loaded = false; -static int property_set_fd = -1; static int from_init_socket = -1; static int init_socket = -1; static bool accept_messages = false; static std::mutex accept_messages_lock; static std::thread property_service_thread; +static std::thread property_service_for_system_thread; +static std::mutex set_property_lock; static std::unique_ptr persist_write_thread; @@ -394,6 +395,7 @@ static std::optional PropertySet(const std::string& name, const std::s return {PROP_ERROR_INVALID_VALUE}; } + auto lock = std::lock_guard{set_property_lock}; prop_info* pi = (prop_info*)__system_property_find(name.c_str()); if (pi != nullptr) { // ro.* properties are actually "write-once". @@ -582,10 +584,10 @@ uint32_t HandlePropertySetNoSocket(const std::string& name, const std::string& v return *ret; } -static void handle_property_set_fd() { +static void handle_property_set_fd(int fd) { static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */ - int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC); + int s = accept4(fd, nullptr, nullptr, SOCK_CLOEXEC); if (s == -1) { return; } @@ -1422,19 +1424,21 @@ static void HandleInitSocket() { } } -static void PropertyServiceThread() { +static void PropertyServiceThread(int fd, bool listen_init) { Epoll epoll; if (auto result = epoll.Open(); !result.ok()) { LOG(FATAL) << result.error(); } - if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd); + if (auto result = epoll.RegisterHandler(fd, std::bind(handle_property_set_fd, fd)); !result.ok()) { LOG(FATAL) << result.error(); } - if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) { - LOG(FATAL) << result.error(); + if (listen_init) { + if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) { + LOG(FATAL) << result.error(); + } } while (true) { @@ -1485,6 +1489,23 @@ void PersistWriteThread::Write(std::string name, std::string value, SocketConnec cv_.notify_all(); } +void StartThread(const char* name, int mode, int gid, std::thread& t, bool listen_init) { + int fd = -1; + if (auto result = CreateSocket(name, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + /*passcred=*/false, /*should_listen=*/false, mode, /*uid=*/0, + /*gid=*/gid, /*socketcon=*/{}); + result.ok()) { + fd = *result; + } else { + LOG(FATAL) << "start_property_service socket creation failed: " << result.error(); + } + + listen(fd, 8); + + auto new_thread = std::thread(PropertyServiceThread, fd, listen_init); + t.swap(new_thread); +} + void StartPropertyService(int* epoll_socket) { InitPropertySet("ro.property_service.version", "2"); @@ -1496,19 +1517,9 @@ void StartPropertyService(int* epoll_socket) { init_socket = sockets[1]; StartSendingMessages(); - if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - /*passcred=*/false, /*should_listen=*/false, 0666, /*uid=*/0, - /*gid=*/0, /*socketcon=*/{}); - result.ok()) { - property_set_fd = *result; - } else { - LOG(FATAL) << "start_property_service socket creation failed: " << result.error(); - } - - listen(property_set_fd, 8); - - auto new_thread = std::thread{PropertyServiceThread}; - property_service_thread.swap(new_thread); + StartThread(PROP_SERVICE_FOR_SYSTEM_NAME, 0660, AID_SYSTEM, property_service_for_system_thread, + true); + StartThread(PROP_SERVICE_NAME, 0666, 0, property_service_thread, false); auto async_persist_writes = android::base::GetBoolProperty("ro.property_service.async_persist_writes", false); From bc680ab1fafffc811896e9723cded4dbde46f39b Mon Sep 17 00:00:00 2001 From: Nicolas Gagnon Date: Wed, 14 Sep 2022 17:48:18 +0000 Subject: [PATCH 0022/1487] Port ADB's new handling of the USB packet ClearFeature(HALT) to Fastboot. This patch addresses Fastboot/Fastbootd connection issues seen on ARM Mac devices. Original ADB patch: https://android-review.googlesource.com/c/platform/packages/modules/adb/+/1699250/ Bug: 238779161 Test: 'fastboot update .zip' now works on ARM Mac. Signed-off-by: Nicolas Gagnon Merged-In: Id67904d91abc8b66ef1a00962e1fd57c97df98a7 Change-Id: Id67904d91abc8b66ef1a00962e1fd57c97df98a7 (cherry picked from commit 3efef5694ee242f0fbeeaaa15c128dfb84418798) --- fastboot/device/usb.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fastboot/device/usb.cpp b/fastboot/device/usb.cpp index 4115a6d28bfe..1257055dea15 100644 --- a/fastboot/device/usb.cpp +++ b/fastboot/device/usb.cpp @@ -171,6 +171,16 @@ static int usb_ffs_do_aio(usb_handle* h, const void* data, int len, bool read) { if (num_bufs == 1 && aiob->events[0].res == -EINTR) { continue; } + if (read && aiob->events[0].res == -EPIPE) { + // On initial connection, some clients will send a ClearFeature(HALT) to + // attempt to resynchronize host and device after the fastboot server is killed. + // On newer device kernels, the reads we've already dispatched will be cancelled. + // Instead of treating this as a failure, which will tear down the interface and + // lead to the client doing the same thing again, just resubmit if this happens + // before we've actually read anything. + PLOG(ERROR) << "aio: got -EPIPE on first read attempt. Re-submitting read... "; + continue; + } int ret = 0; for (int i = 0; i < num_bufs; i++) { if (aiob->events[i].res < 0) { From b5e68a67f1a0710753a9e59c8517826f0646da46 Mon Sep 17 00:00:00 2001 From: Hongwei Wang Date: Fri, 20 Jan 2023 12:15:28 -0800 Subject: [PATCH 0023/1487] Grant wmtrace access to platform_app:systemui Grant read/write access to anyone for /data/misc/wmtrace folder on debuggable builds, it's further protected by the selinux policy. This is to allow systemui process to write proto logs to the same folder on device as WindowManager, both can contribute to the transitions like PiP, Split-Screen and etc. Bug: 251513116 Test: adb shell dumpsys activity service SystemUIService \ WMShell protolog [start | stop] Ignore-AOSP-First: cherry-pick of aosp/2397772 Merged-In: Ice57efa17c61d132b02c0a11a762c24d772bd90a Change-Id: Ice57efa17c61d132b02c0a11a762c24d772bd90a --- rootdir/init.rc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 02e51d2c4ad9..c3216da52c2c 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -1269,11 +1269,13 @@ service console /system/bin/sh setenv HOSTNAME console on property:ro.debuggable=1 - # Give writes to anyone for the trace folder on debug builds. + # Give writes to the same group for the trace folder on debug builds, + # it's further protected by selinux policy. # The folder is used to store method traces. chmod 0773 /data/misc/trace - # Give reads to anyone for the window trace folder on debug builds. - chmod 0775 /data/misc/wmtrace + # Give writes and reads to anyone for the window trace folder on debug builds, + # it's further protected by selinux policy. + chmod 0777 /data/misc/wmtrace # Give reads to anyone for the accessibility trace folder on debug builds. chmod 0775 /data/misc/a11ytrace From 719b97add040eb4d60e8a6b87d1e2f35ab73e6a0 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Tue, 31 Jan 2023 17:50:22 -0800 Subject: [PATCH 0024/1487] Display offset in backtraces if necessary. When moving to a proto tombstone, backtraces no longer contain an offset when a frame is in a shared library from an apk. Add the offset display again if needed, and add a test to verify this behavior. Bug: 267341682 Test: All unit tests pass. Test: Dumped a process running through an apk to verify the offset Test: is present. Change-Id: Ib720ccb5bfcc8531d1e407f3d01817e8a0b9128c (cherry picked from commit 22035ccb01693da3e0ec94776c86988c7d5c617e) --- debuggerd/debuggerd_test.cpp | 60 ++++++++++++++++++- .../libdebuggerd/tombstone_proto_to_text.cpp | 10 +++- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index e1133081970c..9163ca0ab789 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -1842,7 +1843,7 @@ TEST_F(CrasherTest, stack_overflow) { ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)"); } -static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) { +static std::string GetTestLibraryPath() { std::string test_lib(testing::internal::GetArgvs()[0]); auto const value = test_lib.find_last_of('/'); if (value == std::string::npos) { @@ -1850,7 +1851,62 @@ static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) { } else { test_lib = test_lib.substr(0, value + 1) + "./"; } - test_lib += "libcrash_test.so"; + return test_lib + "libcrash_test.so"; +} + +static void CreateEmbeddedLibrary(int out_fd) { + std::string test_lib(GetTestLibraryPath()); + android::base::unique_fd fd(open(test_lib.c_str(), O_RDONLY | O_CLOEXEC)); + ASSERT_NE(fd.get(), -1); + off_t file_size = lseek(fd, 0, SEEK_END); + ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0); + std::vector contents(file_size); + ASSERT_TRUE(android::base::ReadFully(fd, contents.data(), contents.size())); + + // Put the shared library data at a pagesize() offset. + ASSERT_EQ(lseek(out_fd, 4 * getpagesize(), SEEK_CUR), 4 * getpagesize()); + ASSERT_EQ(static_cast(write(out_fd, contents.data(), contents.size())), contents.size()); +} + +TEST_F(CrasherTest, non_zero_offset_in_library) { + int intercept_result; + unique_fd output_fd; + TemporaryFile tf; + CreateEmbeddedLibrary(tf.fd); + StartProcess([&tf]() { + android_dlextinfo extinfo{}; + extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; + extinfo.library_fd = tf.fd; + extinfo.library_fd_offset = 4 * getpagesize(); + void* handle = android_dlopen_ext(tf.path, RTLD_NOW, &extinfo); + if (handle == nullptr) { + _exit(1); + } + void (*crash_func)() = reinterpret_cast(dlsym(handle, "crash")); + if (crash_func == nullptr) { + _exit(1); + } + crash_func(); + }); + + StartIntercept(&output_fd); + FinishCrasher(); + AssertDeath(SIGSEGV); + FinishIntercept(&intercept_result); + + ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; + + std::string result; + ConsumeFd(std::move(output_fd), &result); + + // Verify the crash includes an offset value in the backtrace. + std::string match_str = android::base::StringPrintf("%s\\!libcrash_test.so \\(offset 0x%x\\)", + tf.path, 4 * getpagesize()); + ASSERT_MATCH(result, match_str); +} + +static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) { + std::string test_lib(GetTestLibraryPath()); *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so"; std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir); diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp index 026564112d64..0696601bc0c0 100644 --- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp @@ -168,8 +168,14 @@ static void print_backtrace(CallbackType callback, const Tombstone& tombstone, build_id = StringPrintf(" (BuildId: %s)", frame.build_id().c_str()); } - CB(should_log, " #%02d pc %0*" PRIx64 " %s%s%s", index++, pointer_width(tombstone) * 2, - frame.rel_pc(), frame.file_name().c_str(), function.c_str(), build_id.c_str()); + std::string line = + StringPrintf(" #%02d pc %0*" PRIx64 " %s", index++, pointer_width(tombstone) * 2, + frame.rel_pc(), frame.file_name().c_str()); + if (frame.file_map_offset() != 0) { + line += StringPrintf(" (offset 0x%" PRIx64 ")", frame.file_map_offset()); + } + line += function + build_id; + CB(should_log, "%s", line.c_str()); } } From f4846e2d08aca746622dbb5826e9f33cdf02ab6d Mon Sep 17 00:00:00 2001 From: AleX Pelosi Date: Fri, 17 Feb 2023 01:39:21 +0000 Subject: [PATCH 0025/1487] BatteryMonitor: batteryStateOfHealth should be a property Bug: 251427118 Test: m Ignore-AOSP-First: will cherry-pick to aosp later Change-Id: I21bcd160f51cf8818d0c3c8c54c615314808e586 Signed-off-by: AleX Pelosi --- healthd/BatteryMonitor.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp index b180a58fec83..66e1e63ef62e 100644 --- a/healthd/BatteryMonitor.cpp +++ b/healthd/BatteryMonitor.cpp @@ -392,12 +392,13 @@ void BatteryMonitor::updateValues(void) { mHealthInfo->batteryFullChargeDesignCapacityUah = getIntField(mHealthdConfig->batteryFullChargeDesignCapacityUahPath); - if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty()) - mHealthInfo->batteryStateOfHealth = getIntField(mHealthdConfig->batteryStateOfHealthPath); - if (!mHealthdConfig->batteryHealthStatusPath.isEmpty()) mBatteryHealthStatus = getIntField(mHealthdConfig->batteryHealthStatusPath); + if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty()) + mHealthInfo->batteryHealthData->batteryStateOfHealth = + getIntField(mHealthdConfig->batteryStateOfHealthPath); + if (!mHealthdConfig->batteryManufacturingDatePath.isEmpty()) mHealthInfo->batteryHealthData->batteryManufacturingDateSeconds = getIntField(mHealthdConfig->batteryManufacturingDatePath); @@ -591,6 +592,10 @@ int BatteryMonitor::getBatteryHealthData(int id) { if (!mHealthdConfig->batteryFirstUsageDatePath.isEmpty()) return getIntField(mHealthdConfig->batteryFirstUsageDatePath); } + if (id == BATTERY_PROP_STATE_OF_HEALTH) { + if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty()) + return getIntField(mHealthdConfig->batteryStateOfHealthPath); + } return 0; } @@ -669,6 +674,11 @@ status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { ret = OK; break; + case BATTERY_PROP_STATE_OF_HEALTH: + val->valueInt64 = getBatteryHealthData(BATTERY_PROP_STATE_OF_HEALTH); + ret = OK; + break; + default: break; } From 6f7f7c8bcdd73df2c4b8d956442b797c593beaed Mon Sep 17 00:00:00 2001 From: Jack Wu Date: Sun, 19 Feb 2023 01:38:45 +0800 Subject: [PATCH 0026/1487] Revert "BatteryMonitor: batteryStateOfHealth should be a property" This reverts commit f4846e2d08aca746622dbb5826e9f33cdf02ab6d. Reason for revert: merge to aosp first Bug: 251427118 Test: m Ignore-AOSP-First: merge to aosp first Change-Id: I84bf3d2059303172161466333db7ad45da5d5270 Signed-off-by: Jack Wu --- healthd/BatteryMonitor.cpp | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp index 66e1e63ef62e..b180a58fec83 100644 --- a/healthd/BatteryMonitor.cpp +++ b/healthd/BatteryMonitor.cpp @@ -392,13 +392,12 @@ void BatteryMonitor::updateValues(void) { mHealthInfo->batteryFullChargeDesignCapacityUah = getIntField(mHealthdConfig->batteryFullChargeDesignCapacityUahPath); + if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty()) + mHealthInfo->batteryStateOfHealth = getIntField(mHealthdConfig->batteryStateOfHealthPath); + if (!mHealthdConfig->batteryHealthStatusPath.isEmpty()) mBatteryHealthStatus = getIntField(mHealthdConfig->batteryHealthStatusPath); - if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty()) - mHealthInfo->batteryHealthData->batteryStateOfHealth = - getIntField(mHealthdConfig->batteryStateOfHealthPath); - if (!mHealthdConfig->batteryManufacturingDatePath.isEmpty()) mHealthInfo->batteryHealthData->batteryManufacturingDateSeconds = getIntField(mHealthdConfig->batteryManufacturingDatePath); @@ -592,10 +591,6 @@ int BatteryMonitor::getBatteryHealthData(int id) { if (!mHealthdConfig->batteryFirstUsageDatePath.isEmpty()) return getIntField(mHealthdConfig->batteryFirstUsageDatePath); } - if (id == BATTERY_PROP_STATE_OF_HEALTH) { - if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty()) - return getIntField(mHealthdConfig->batteryStateOfHealthPath); - } return 0; } @@ -674,11 +669,6 @@ status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { ret = OK; break; - case BATTERY_PROP_STATE_OF_HEALTH: - val->valueInt64 = getBatteryHealthData(BATTERY_PROP_STATE_OF_HEALTH); - ret = OK; - break; - default: break; } From 65d8e53b606e4ae7387f421c5277a942f8e729d8 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Thu, 2 Mar 2023 14:12:49 -0800 Subject: [PATCH 0027/1487] libprocessgroup: fix boot time performance regression The way processes are accounted in DoKillProcessGroupOnce has been changed recently, which affects retries in KillProcessGroup. More specifically, initialPid was not counted before and would not cause a retry with 5ms sleep. Restore previous behavior to avoid boot time regressions. Bug: 271198843 Signed-off-by: Suren Baghdasaryan Change-Id: Ibc1bdd855898688a4a03806671e6ac31570aedf9 (cherry picked from commit on android-review.googlesource.com host: 4f7cc8c3455b2a28984e2682c1b8075cb57d67fe) Merged-In: Ibc1bdd855898688a4a03806671e6ac31570aedf9 --- libprocessgroup/processgroup.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index 92a27efb70d7..71ba7ced2b25 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -377,6 +377,7 @@ static int DoKillProcessGroupOnce(const char* cgroup, uid_t uid, int initialPid, std::set pgids; pgids.emplace(initialPid); std::set pids; + int processes = 0; std::unique_ptr fd(nullptr, fclose); @@ -395,6 +396,7 @@ static int DoKillProcessGroupOnce(const char* cgroup, uid_t uid, int initialPid, pid_t pid; bool file_is_empty = true; while (fscanf(fd.get(), "%d\n", &pid) == 1 && pid >= 0) { + processes++; file_is_empty = false; if (pid == 0) { // Should never happen... but if it does, trying to kill this @@ -424,15 +426,12 @@ static int DoKillProcessGroupOnce(const char* cgroup, uid_t uid, int initialPid, } } - int processes = 0; // Kill all process groups. for (const auto pgid : pgids) { LOG(VERBOSE) << "Killing process group " << -pgid << " in uid " << uid << " as part of process cgroup " << initialPid; - if (kill(-pgid, signal) == 0) { - processes++; - } else if (errno != ESRCH) { + if (kill(-pgid, signal) == -1 && errno != ESRCH) { PLOG(WARNING) << "kill(" << -pgid << ", " << signal << ") failed"; } } @@ -442,9 +441,7 @@ static int DoKillProcessGroupOnce(const char* cgroup, uid_t uid, int initialPid, LOG(VERBOSE) << "Killing pid " << pid << " in uid " << uid << " as part of process cgroup " << initialPid; - if (kill(pid, signal) == 0) { - processes++; - } else if (errno != ESRCH) { + if (kill(pid, signal) == -1 && errno != ESRCH) { PLOG(WARNING) << "kill(" << pid << ", " << signal << ") failed"; } } From 8301b33dad51cafd9d08876fc91a7e5fa556dcd3 Mon Sep 17 00:00:00 2001 From: Pete Bentley Date: Thu, 7 Jul 2022 15:18:55 +0100 Subject: [PATCH 0028/1487] Move boringssl self tests from early-init to init. In previous releases, these self tests had a secondary purpose of writing a flag file to save future processes from running some slow self checks. This is no longer true in T. However running the tests from early-init has caused issues on some devices as the kernel's entropy pool is not yet initialised, causing the process to block for a second or more. Bug: 231946889 Bug: 249037600 Test: m && flashall Change-Id: I2116f2029ca6a21e4359407dfff4dc79edd39084 Merged-In: I2116f2029ca6a21e4359407dfff4dc79edd39084 --- rootdir/init.rc | 53 +++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index c3216da52c2c..2b53d883eade 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -86,32 +86,6 @@ on early-init mkdir /dev/sys/fs 0755 system system mkdir /dev/sys/block 0755 system system -# Run boringssl self test for each ABI so that later processes can skip it. http://b/139348610 -on early-init && property:ro.product.cpu.abilist32=* - exec_start boringssl_self_test32 -on early-init && property:ro.product.cpu.abilist64=* - exec_start boringssl_self_test64 -on property:apexd.status=ready && property:ro.product.cpu.abilist32=* - exec_start boringssl_self_test_apex32 -on property:apexd.status=ready && property:ro.product.cpu.abilist64=* - exec_start boringssl_self_test_apex64 - -service boringssl_self_test32 /system/bin/boringssl_self_test32 - reboot_on_failure reboot,boringssl-self-check-failed - stdio_to_kmsg - -service boringssl_self_test64 /system/bin/boringssl_self_test64 - reboot_on_failure reboot,boringssl-self-check-failed - stdio_to_kmsg - -service boringssl_self_test_apex32 /apex/com.android.conscrypt/bin/boringssl_self_test32 - reboot_on_failure reboot,boringssl-self-check-failed - stdio_to_kmsg - -service boringssl_self_test_apex64 /apex/com.android.conscrypt/bin/boringssl_self_test64 - reboot_on_failure reboot,boringssl-self-check-failed - stdio_to_kmsg - on init sysclktz 0 @@ -502,6 +476,33 @@ on init start hwservicemanager start vndservicemanager +# Run boringssl self test for each ABI. Any failures trigger reboot to firmware. +on init && property:ro.product.cpu.abilist32=* + exec_start boringssl_self_test32 +on init && property:ro.product.cpu.abilist64=* + exec_start boringssl_self_test64 +on property:apexd.status=ready && property:ro.product.cpu.abilist32=* + exec_start boringssl_self_test_apex32 +on property:apexd.status=ready && property:ro.product.cpu.abilist64=* + exec_start boringssl_self_test_apex64 + +service boringssl_self_test32 /system/bin/boringssl_self_test32 + reboot_on_failure reboot,boringssl-self-check-failed + stdio_to_kmsg + +service boringssl_self_test64 /system/bin/boringssl_self_test64 + reboot_on_failure reboot,boringssl-self-check-failed + stdio_to_kmsg + +service boringssl_self_test_apex32 /apex/com.android.conscrypt/bin/boringssl_self_test32 + reboot_on_failure reboot,boringssl-self-check-failed + stdio_to_kmsg + +service boringssl_self_test_apex64 /apex/com.android.conscrypt/bin/boringssl_self_test64 + reboot_on_failure reboot,boringssl-self-check-failed + stdio_to_kmsg + + # Healthd can trigger a full boot from charger mode by signaling this # property when the power button is held. on property:sys.boot_from_charger_mode=1 From 691d805d30548dc8010a6aad24ef5365fbdf5775 Mon Sep 17 00:00:00 2001 From: David Tracy Date: Thu, 23 Mar 2023 17:51:11 -0700 Subject: [PATCH 0029/1487] bootstat: Adds additional reboot reason patterns - Adding allowance for arbitrary ota subreason details, such as success or failure conditions - Adding the new subreason "periodic", which is useful for POS devices which require e.g. daily reboots as part of security requirements Test: Full Android build Change-Id: Id0a6d38ed902e2b25fbb050980c763912c948f27 Signed-off-by: David Tracy --- bootstat/bootstat.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp index 844357cfcb63..3b8866e51afb 100644 --- a/bootstat/bootstat.cpp +++ b/bootstat/bootstat.cpp @@ -459,6 +459,8 @@ const std::map kBootReasonMap = { {"reboot,sys_ldo_ok,pmic,main", 227}, {"reboot,sys_ldo_ok,pmic,sub", 228}, {"reboot,smpl_timeout,pmic,main", 229}, + {"reboot,ota,.*", 230}, + {"reboot,periodic,.*", 231}, }; // Converts a string value representing the reason the system booted to an From 606afc7b7451aba90e3634076d9b59a5ef08186b Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Fri, 24 Mar 2023 14:31:57 -0700 Subject: [PATCH 0030/1487] Fix deadlock caused by two-threaded property controls Two threaded property controls were introduced in ag/21063815 to prevent DOS for power controls. However, this causes deadlocks, so limit the second thread to just sys.powerctl messages. Bug: 273785601 Test: Boots, power messages work Ignore-AOSP-First: Security fix Change-Id: Ie27dc3b0cd9e2d28e94f2ad398c55ee27bc35835 --- init/property_service.cpp | 50 +++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/init/property_service.cpp b/init/property_service.cpp index 2d084db46d2a..4242912ed0af 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -117,7 +117,6 @@ static bool accept_messages = false; static std::mutex accept_messages_lock; static std::thread property_service_thread; static std::thread property_service_for_system_thread; -static std::mutex set_property_lock; static std::unique_ptr persist_write_thread; @@ -395,32 +394,37 @@ static std::optional PropertySet(const std::string& name, const std::s return {PROP_ERROR_INVALID_VALUE}; } - auto lock = std::lock_guard{set_property_lock}; - prop_info* pi = (prop_info*)__system_property_find(name.c_str()); - if (pi != nullptr) { - // ro.* properties are actually "write-once". - if (StartsWith(name, "ro.")) { - *error = "Read-only property was already set"; - return {PROP_ERROR_READ_ONLY_PROPERTY}; - } - - __system_property_update(pi, value.c_str(), valuelen); + if (name == "sys.powerctl") { + // No action here - NotifyPropertyChange will trigger the appropriate action, and since this + // can come to the second thread, we mustn't call out to the __system_property_* functions + // which support multiple readers but only one mutator. } else { - int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen); - if (rc < 0) { - *error = "__system_property_add failed"; - return {PROP_ERROR_SET_FAILED}; + prop_info* pi = (prop_info*)__system_property_find(name.c_str()); + if (pi != nullptr) { + // ro.* properties are actually "write-once". + if (StartsWith(name, "ro.")) { + *error = "Read-only property was already set"; + return {PROP_ERROR_READ_ONLY_PROPERTY}; + } + + __system_property_update(pi, value.c_str(), valuelen); + } else { + int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen); + if (rc < 0) { + *error = "__system_property_add failed"; + return {PROP_ERROR_SET_FAILED}; + } } - } - // Don't write properties to disk until after we have read all default - // properties to prevent them from being overwritten by default values. - if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) { - if (persist_write_thread) { - persist_write_thread->Write(name, value, std::move(*socket)); - return {}; + // Don't write properties to disk until after we have read all default + // properties to prevent them from being overwritten by default values. + if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) { + if (persist_write_thread) { + persist_write_thread->Write(name, value, std::move(*socket)); + return {}; + } + WritePersistentProperty(name, value); } - WritePersistentProperty(name, value); } NotifyPropertyChange(name, value); From 763e869b381bbcec58e799670344e859292f2db2 Mon Sep 17 00:00:00 2001 From: "Chung-Kai (Michael) Mei" Date: Wed, 1 Mar 2023 04:24:10 +0000 Subject: [PATCH 0031/1487] Revert "Revert "libmodprobe: LPM: Load all modules in *.load with *.dep satisfied"" This reverts commit a0e6703f738bcf863847088cdcd4b3689e8c9ae6. Reason for revert: the failed devices has disabled the feature now, we'll fixed the problem later so releand this patch first Change-Id: Ib12b84edbd9489d769a4988908bb89f45c13ca43 --- libmodprobe/libmodprobe.cpp | 81 ++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp index e071c96d97f8..4fbb19d1af5c 100644 --- a/libmodprobe/libmodprobe.cpp +++ b/libmodprobe/libmodprobe.cpp @@ -439,54 +439,58 @@ bool Modprobe::IsBlocklisted(const std::string& module_name) { return module_blocklist_.count(canonical_name) > 0; } -// Another option to load kernel modules. load in independent modules in parallel -// and then update dependency list of other remaining modules, repeat these steps -// until all modules are loaded. +// Another option to load kernel modules. load independent modules dependencies +// in parallel and then update dependency list of other remaining modules, +// repeat these steps until all modules are loaded. +// Discard all blocklist. +// Softdeps are taken care in InsmodWithDeps(). bool Modprobe::LoadModulesParallel(int num_threads) { bool ret = true; - int count = -1; - std::map> mod_with_deps; + std::unordered_map> mod_with_deps; // Get dependencies for (const auto& module : module_load_) { - auto dependencies = GetDependencies(MakeCanonical(module)); - - for (auto dep = dependencies.rbegin(); dep != dependencies.rend(); dep++) { - mod_with_deps[module].emplace(*dep); - } - } - - // Get soft dependencies - for (const auto& [it_mod, it_softdep] : module_pre_softdep_) { - if (mod_with_deps.find(MakeCanonical(it_softdep)) != mod_with_deps.end()) { - mod_with_deps[MakeCanonical(it_mod)].emplace( - GetDependencies(MakeCanonical(it_softdep))[0]); + // Skip blocklist modules + if (IsBlocklisted(module)) { + LOG(VERBOSE) << "LMP: Blocklist: Module " << module << " skipping..."; + continue; } - } - - // Get soft post dependencies - for (const auto& [it_mod, it_softdep] : module_post_softdep_) { - if (mod_with_deps.find(MakeCanonical(it_softdep)) != mod_with_deps.end()) { - mod_with_deps[MakeCanonical(it_softdep)].emplace( - GetDependencies(MakeCanonical(it_mod))[0]); + auto dependencies = GetDependencies(MakeCanonical(module)); + if (dependencies.empty()) { + LOG(ERROR) << "LMP: Hard-dep: Module " << module + << " not in .dep file"; + return false; } + mod_with_deps[MakeCanonical(module)] = dependencies; } - while (!mod_with_deps.empty() && count != module_loaded_.size()) { + while (!mod_with_deps.empty()) { std::vector threads; std::vector mods_path_to_load; std::mutex vector_lock; - count = module_loaded_.size(); // Find independent modules for (const auto& [it_mod, it_dep] : mod_with_deps) { - if (it_dep.size() == 1) { - if (module_options_[it_mod].find("load_sequential=1") != std::string::npos) { - if (!LoadWithAliases(it_mod, true) && !IsBlocklisted(it_mod)) { - return false; - } - } else { - mods_path_to_load.emplace_back(it_mod); + auto itd_last = it_dep.rbegin(); + if (itd_last == it_dep.rend()) + continue; + + auto cnd_last = MakeCanonical(*itd_last); + // Hard-dependencies cannot be blocklisted + if (IsBlocklisted(cnd_last)) { + LOG(ERROR) << "LMP: Blocklist: Module-dep " << cnd_last + << " : failed to load module " << it_mod; + return false; + } + + if (module_options_[cnd_last].find("load_sequential=1") != std::string::npos) { + if (!LoadWithAliases(cnd_last, true)) { + return false; + } + } else { + if (std::find(mods_path_to_load.begin(), mods_path_to_load.end(), + cnd_last) == mods_path_to_load.end()) { + mods_path_to_load.emplace_back(cnd_last); } } } @@ -502,7 +506,7 @@ bool Modprobe::LoadModulesParallel(int num_threads) { lk.unlock(); ret_load &= LoadWithAliases(mod_to_load, true); lk.lock(); - if (!ret_load && !IsBlocklisted(mod_to_load)) { + if (!ret_load) { ret &= ret_load; } } @@ -521,13 +525,18 @@ bool Modprobe::LoadModulesParallel(int num_threads) { std::lock_guard guard(module_loaded_lock_); // Remove loaded module form mod_with_deps and soft dependencies of other modules for (const auto& module_loaded : module_loaded_) { - mod_with_deps.erase(module_loaded); + if (mod_with_deps.find(module_loaded) != mod_with_deps.end()) { + mod_with_deps.erase(module_loaded); + } } // Remove loaded module form dependencies of other modules which are not loaded yet for (const auto& module_loaded_path : module_loaded_paths_) { for (auto& [mod, deps] : mod_with_deps) { - deps.erase(module_loaded_path); + auto it = std::find(deps.begin(), deps.end(), module_loaded_path); + if (it != deps.end()) { + deps.erase(it); + } } } } From ecd154e702aaf7896739c1c2b2b0c796ae872030 Mon Sep 17 00:00:00 2001 From: Wasim Nazir Date: Thu, 6 Apr 2023 15:07:22 +0530 Subject: [PATCH 0032/1487] libmodprobe: LPM: Cleanup of redundant check Removing find-check while removing modules in loop. Test: Normal/Recovery Boot to home Bug: 261678056 Change-Id: I5ff41b3e8cf633dc687f819a146404b863d2ae0a Signed-off-by: Wasim Nazir --- libmodprobe/libmodprobe.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp index 4fbb19d1af5c..6c5ca99b94d7 100644 --- a/libmodprobe/libmodprobe.cpp +++ b/libmodprobe/libmodprobe.cpp @@ -524,11 +524,8 @@ bool Modprobe::LoadModulesParallel(int num_threads) { std::lock_guard guard(module_loaded_lock_); // Remove loaded module form mod_with_deps and soft dependencies of other modules - for (const auto& module_loaded : module_loaded_) { - if (mod_with_deps.find(module_loaded) != mod_with_deps.end()) { - mod_with_deps.erase(module_loaded); - } - } + for (const auto& module_loaded : module_loaded_) + mod_with_deps.erase(module_loaded); // Remove loaded module form dependencies of other modules which are not loaded yet for (const auto& module_loaded_path : module_loaded_paths_) { From d87b6018d25cbbd33b345dc58c634718bf5d0def Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Tue, 4 Apr 2023 18:41:13 +0000 Subject: [PATCH 0033/1487] libprocessgroup: Add sendSignalToProcessGroup Add a function which sends signals to all members of a process group, but does not wait for the processes to exit, or for the associated cgroup to be removed. Bug: 274646058 Ignore-AOSP-First: Dependency of ActivityManager change which developed on interal git_master Test: Force-stop of chrome with 15 tabs completes ~500ms faster Test: Full Play store update causes no ANR Change-Id: I37dbdecb3394101abbee8495e71f6912b3c031f5 --- libprocessgroup/include/processgroup/processgroup.h | 5 +++++ libprocessgroup/processgroup.cpp | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index 8fa9fd552328..48bc0b7f32e1 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -76,6 +76,11 @@ int killProcessGroup(uid_t uid, int initialPid, int signal, int* max_processes = // 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 ae9914d645ee..a02159401f88 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -542,6 +542,15 @@ int killProcessGroupOnce(uid_t uid, int initialPid, int signal, int* max_process 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); From d3dc653d22f97820742c86b4bc4edb627a0dfd21 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Tue, 4 Apr 2023 18:41:13 +0000 Subject: [PATCH 0034/1487] libprocessgroup: Add sendSignalToProcessGroup Add a function which sends signals to all members of a process group, but does not wait for the processes to exit, or for the associated cgroup to be removed. Bug: 274646058 Ignore-AOSP-First: Dependency of ActivityManager change which developed on interal git_master Test: Force-stop of chrome with 15 tabs completes ~500ms faster Test: Full Play store update causes no ANR (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d87b6018d25cbbd33b345dc58c634718bf5d0def) Merged-In: I37dbdecb3394101abbee8495e71f6912b3c031f5 Change-Id: I37dbdecb3394101abbee8495e71f6912b3c031f5 --- libprocessgroup/include/processgroup/processgroup.h | 5 +++++ libprocessgroup/processgroup.cpp | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index 8fa9fd552328..48bc0b7f32e1 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -76,6 +76,11 @@ int killProcessGroup(uid_t uid, int initialPid, int signal, int* max_processes = // 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 ae9914d645ee..a02159401f88 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -542,6 +542,15 @@ int killProcessGroupOnce(uid_t uid, int initialPid, int signal, int* max_process 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); From 3a81dda861c85b15b1ea614b6c15b2274105d113 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Mon, 24 Apr 2023 18:14:53 -0700 Subject: [PATCH 0035/1487] Re-add code to skip gettings logs on logd crashes. Also add new unit tests to verify this behavior. Bug: 276934420 Test: New unit tests pass. Test: Ran new unit tests without pthread_setname_np call and verified Test: the tests fail. Test: Force crash logd and verify log messages are not gathered. Test: Force crash a logd thread and verify log messages are not gathered. Change-Id: If8effef68f629432923cdc89e57d28ef5b8b4ce2 Merged-In: If8effef68f629432923cdc89e57d28ef5b8b4ce2 (cherry picked from commit bda106416096d51d872bffacfd251e586f982004) --- debuggerd/debuggerd_test.cpp | 56 ++++++++++++++++++++++ debuggerd/libdebuggerd/tombstone_proto.cpp | 9 +++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index a00a2026f520..39d7fff1ca86 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -2703,3 +2704,58 @@ TEST_F(CrasherTest, verify_build_id) { } ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check."; } + +const char kLogMessage[] = "Should not see this log message."; + +// Verify that the logd process does not read the log. +TEST_F(CrasherTest, logd_skips_reading_logs) { + StartProcess([]() { + pthread_setname_np(pthread_self(), "logd"); + LOG(INFO) << kLogMessage; + abort(); + }); + + unique_fd output_fd; + StartIntercept(&output_fd); + FinishCrasher(); + AssertDeath(SIGABRT); + int intercept_result; + FinishIntercept(&intercept_result); + ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; + + std::string result; + ConsumeFd(std::move(output_fd), &result); + // logd should not contain our log message. + ASSERT_NOT_MATCH(result, kLogMessage); +} + +// Verify that the logd process does not read the log when the non-main +// thread crashes. +TEST_F(CrasherTest, logd_skips_reading_logs_not_main_thread) { + StartProcess([]() { + pthread_setname_np(pthread_self(), "logd"); + LOG(INFO) << kLogMessage; + + std::thread thread([]() { + pthread_setname_np(pthread_self(), "not_logd_thread"); + // Raise the signal on the side thread. + raise_debugger_signal(kDebuggerdTombstone); + }); + thread.join(); + _exit(0); + }); + + unique_fd output_fd; + StartIntercept(&output_fd, kDebuggerdTombstone); + FinishCrasher(); + AssertDeath(0); + + int intercept_result; + FinishIntercept(&intercept_result); + ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; + + std::string result; + ConsumeFd(std::move(output_fd), &result); + ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal"); + ASSERT_NOT_MATCH(result, kLogMessage); +} diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp index 9a565deb669e..acd814efa68b 100644 --- a/debuggerd/libdebuggerd/tombstone_proto.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto.cpp @@ -690,7 +690,14 @@ void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::AndroidUnwinder* // Only dump logs on debuggable devices. if (android::base::GetBoolProperty("ro.debuggable", false)) { - dump_logcat(&result, main_thread.pid); + // Get the thread that corresponds to the main pid of the process. + const ThreadInfo& thread = threads.at(main_thread.pid); + + // Do not attempt to dump logs of the logd process because the gathering + // of logs can hang until a timeout occurs. + if (thread.thread_name != "logd") { + dump_logcat(&result, main_thread.pid); + } } dump_open_fds(&result, open_files); From 4a8c1461ff2135e29bb00bcd32989567108e776a Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Wed, 12 Apr 2023 01:24:23 +0000 Subject: [PATCH 0036/1487] libprocessgroup: implement task profile validity checks Provide profile validity check functions for cases when user wants to check whether a profile can be successfully applied before actually applying it. Add test cases to cover new APIs. Also add a wrapper function for framework code to call it. Bug: 277233783 Test: atest task_profiles_test Test: manually verify freezer with outdated cgroup configuration Signed-off-by: Suren Baghdasaryan Signed-off-by: Li Li Change-Id: Iefb321dead27adbe67721972f164efea213c06cb Merged-In: Iefb321dead27adbe67721972f164efea213c06cb --- .../include/processgroup/processgroup.h | 4 + libprocessgroup/processgroup.cpp | 10 ++ libprocessgroup/task_profiles.cpp | 121 ++++++++++++++++++ libprocessgroup/task_profiles.h | 20 ++- libprocessgroup/task_profiles_test.cpp | 50 ++++++++ 5 files changed, 202 insertions(+), 3 deletions(-) diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index 48bc0b7f32e1..dbaeb93977bf 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -96,6 +96,10 @@ void removeAllEmptyProcessGroups(void); // Returns false in case of error, true in case of success bool getAttributePathForTask(const std::string& attr_name, int tid, std::string* path); +// Check if a profile can be applied without failing. +// Returns true if it can be applied without failing, false otherwise +bool isProfileValidForProcess(const std::string& profile_name, int uid, int pid); + #endif // __ANDROID_VNDK__ __END_DECLS diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index a02159401f88..234b793d4a00 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -657,3 +657,13 @@ bool setProcessGroupLimit(uid_t, int pid, int64_t limit_in_bytes) { bool getAttributePathForTask(const std::string& attr_name, int tid, std::string* path) { return CgroupGetAttributePathForTask(attr_name, tid, path); } + +bool isProfileValidForProcess(const std::string& profile_name, int uid, int pid) { + const TaskProfile* tp = TaskProfiles::GetInstance().GetProfile(profile_name); + + if (tp == nullptr) { + return false; + } + + return tp->IsValidForProcess(uid, pid); +} \ No newline at end of file diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 17318289fb99..44dba2a16694 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -259,6 +259,31 @@ bool SetAttributeAction::ExecuteForUID(uid_t uid) const { return true; } +bool SetAttributeAction::IsValidForProcess(uid_t, pid_t pid) const { + return IsValidForTask(pid); +} + +bool SetAttributeAction::IsValidForTask(int tid) const { + std::string path; + + if (!attribute_->GetPathForTask(tid, &path)) { + return false; + } + + if (!access(path.c_str(), W_OK)) { + // operation will succeed + return true; + } + + if (!access(path.c_str(), F_OK)) { + // file exists but not writable + return false; + } + + // file does not exist, ignore if optional + return optional_; +} + SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p) : controller_(c), path_(p) { FdCacheHelper::Init(controller_.GetTasksFilePath(path_), fd_[ProfileAction::RCT_TASK]); @@ -396,6 +421,39 @@ void SetCgroupAction::DropResourceCaching(ResourceCacheType cache_type) { FdCacheHelper::Drop(fd_[cache_type]); } +bool SetCgroupAction::IsValidForProcess(uid_t uid, pid_t pid) const { + std::lock_guard lock(fd_mutex_); + if (FdCacheHelper::IsCached(fd_[ProfileAction::RCT_PROCESS])) { + return true; + } + + if (fd_[ProfileAction::RCT_PROCESS] == FdCacheHelper::FDS_INACCESSIBLE) { + return false; + } + + std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid); + return access(procs_path.c_str(), W_OK) == 0; +} + +bool SetCgroupAction::IsValidForTask(int) const { + std::lock_guard lock(fd_mutex_); + if (FdCacheHelper::IsCached(fd_[ProfileAction::RCT_TASK])) { + return true; + } + + if (fd_[ProfileAction::RCT_TASK] == FdCacheHelper::FDS_INACCESSIBLE) { + return false; + } + + if (fd_[ProfileAction::RCT_TASK] == FdCacheHelper::FDS_APP_DEPENDENT) { + // application-dependent path can't be used with tid + return false; + } + + std::string tasks_path = controller()->GetTasksFilePath(path_); + return access(tasks_path.c_str(), W_OK) == 0; +} + WriteFileAction::WriteFileAction(const std::string& task_path, const std::string& proc_path, const std::string& value, bool logfailures) : task_path_(task_path), proc_path_(proc_path), value_(value), logfailures_(logfailures) { @@ -532,6 +590,37 @@ void WriteFileAction::DropResourceCaching(ResourceCacheType cache_type) { FdCacheHelper::Drop(fd_[cache_type]); } +bool WriteFileAction::IsValidForProcess(uid_t, pid_t) const { + std::lock_guard lock(fd_mutex_); + if (FdCacheHelper::IsCached(fd_[ProfileAction::RCT_PROCESS])) { + return true; + } + + if (fd_[ProfileAction::RCT_PROCESS] == FdCacheHelper::FDS_INACCESSIBLE) { + return false; + } + + return access(proc_path_.empty() ? task_path_.c_str() : proc_path_.c_str(), W_OK) == 0; +} + +bool WriteFileAction::IsValidForTask(int) const { + std::lock_guard lock(fd_mutex_); + if (FdCacheHelper::IsCached(fd_[ProfileAction::RCT_TASK])) { + return true; + } + + if (fd_[ProfileAction::RCT_TASK] == FdCacheHelper::FDS_INACCESSIBLE) { + return false; + } + + if (fd_[ProfileAction::RCT_TASK] == FdCacheHelper::FDS_APP_DEPENDENT) { + // application-dependent path can't be used with tid + return false; + } + + return access(task_path_.c_str(), W_OK) == 0; +} + bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const { for (const auto& profile : profiles_) { profile->ExecuteForProcess(uid, pid); @@ -558,6 +647,24 @@ void ApplyProfileAction::DropResourceCaching(ResourceCacheType cache_type) { } } +bool ApplyProfileAction::IsValidForProcess(uid_t uid, pid_t pid) const { + for (const auto& profile : profiles_) { + if (!profile->IsValidForProcess(uid, pid)) { + return false; + } + } + return true; +} + +bool ApplyProfileAction::IsValidForTask(int tid) const { + for (const auto& profile : profiles_) { + if (!profile->IsValidForTask(tid)) { + return false; + } + } + return true; +} + void TaskProfile::MoveTo(TaskProfile* profile) { profile->elements_ = std::move(elements_); profile->res_cached_ = res_cached_; @@ -620,6 +727,20 @@ void TaskProfile::DropResourceCaching(ProfileAction::ResourceCacheType cache_typ res_cached_ = false; } +bool TaskProfile::IsValidForProcess(uid_t uid, pid_t pid) const { + for (const auto& element : elements_) { + if (!element->IsValidForProcess(uid, pid)) return false; + } + return true; +} + +bool TaskProfile::IsValidForTask(int tid) const { + for (const auto& element : elements_) { + if (!element->IsValidForTask(tid)) return false; + } + return true; +} + void TaskProfiles::DropResourceCaching(ProfileAction::ResourceCacheType cache_type) const { for (auto& iter : profiles_) { iter.second->DropResourceCaching(cache_type); diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index a8ecb873d88e..a62c5b0a9e8c 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -72,12 +72,14 @@ class ProfileAction { virtual const char* Name() const = 0; // 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 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) {} + virtual bool IsValidForProcess(uid_t uid, pid_t pid) const { return false; } + virtual bool IsValidForTask(int tid) const { return false; } protected: enum CacheUseResult { SUCCESS, FAIL, UNUSED }; @@ -103,6 +105,8 @@ class SetTimerSlackAction : public ProfileAction { const char* Name() const override { return "SetTimerSlack"; } bool ExecuteForTask(int tid) const override; + bool IsValidForProcess(uid_t uid, pid_t pid) const override { return true; } + bool IsValidForTask(int tid) const override { return true; } private: unsigned long slack_; @@ -120,6 +124,8 @@ class SetAttributeAction : public ProfileAction { bool ExecuteForProcess(uid_t uid, pid_t pid) const override; bool ExecuteForTask(int tid) const override; bool ExecuteForUID(uid_t uid) const override; + bool IsValidForProcess(uid_t uid, pid_t pid) const override; + bool IsValidForTask(int tid) const override; private: const IProfileAttribute* attribute_; @@ -137,6 +143,8 @@ class SetCgroupAction : public ProfileAction { bool ExecuteForTask(int tid) const override; void EnableResourceCaching(ResourceCacheType cache_type) override; void DropResourceCaching(ResourceCacheType cache_type) override; + bool IsValidForProcess(uid_t uid, pid_t pid) const override; + bool IsValidForTask(int tid) const override; const CgroupController* controller() const { return &controller_; } @@ -161,6 +169,8 @@ class WriteFileAction : public ProfileAction { bool ExecuteForTask(int tid) const override; void EnableResourceCaching(ResourceCacheType cache_type) override; void DropResourceCaching(ResourceCacheType cache_type) override; + bool IsValidForProcess(uid_t uid, pid_t pid) const override; + bool IsValidForTask(int tid) const override; private: std::string task_path_, proc_path_, value_; @@ -186,6 +196,8 @@ class TaskProfile { bool ExecuteForUID(uid_t uid) const; void EnableResourceCaching(ProfileAction::ResourceCacheType cache_type); void DropResourceCaching(ProfileAction::ResourceCacheType cache_type); + bool IsValidForProcess(uid_t uid, pid_t pid) const; + bool IsValidForTask(int tid) const; private: const std::string name_; @@ -204,6 +216,8 @@ class ApplyProfileAction : public ProfileAction { bool ExecuteForTask(int tid) const override; void EnableResourceCaching(ProfileAction::ResourceCacheType cache_type) override; void DropResourceCaching(ProfileAction::ResourceCacheType cache_type) override; + bool IsValidForProcess(uid_t uid, pid_t pid) const override; + bool IsValidForTask(int tid) const override; private: std::vector> profiles_; diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp index 6a5b48bf3fd1..eadbe7697b07 100644 --- a/libprocessgroup/task_profiles_test.cpp +++ b/libprocessgroup/task_profiles_test.cpp @@ -175,6 +175,32 @@ TEST_P(SetAttributeFixture, SetAttribute) { } } +class TaskProfileFixture : public TestWithParam { + public: + ~TaskProfileFixture() = default; +}; + +TEST_P(TaskProfileFixture, TaskProfile) { + // Treehugger runs host tests inside a container without cgroupv2 support. + if (!IsCgroupV2MountedRw()) { + GTEST_SKIP(); + return; + } + const TestParam params = GetParam(); + ProfileAttributeMock pa(params.attr_name); + // Test simple profile with one action + std::shared_ptr tp = std::make_shared("test_profile"); + tp->Add(std::make_unique(&pa, params.attr_value, params.optional_attr)); + EXPECT_EQ(tp->IsValidForProcess(getuid(), getpid()), params.result); + EXPECT_EQ(tp->IsValidForTask(getpid()), params.result); + // Test aggregate profile + TaskProfile tp2("meta_profile"); + std::vector> profiles = {tp}; + tp2.Add(std::make_unique(profiles)); + EXPECT_EQ(tp2.IsValidForProcess(getuid(), getpid()), params.result); + EXPECT_EQ(tp2.IsValidForTask(getpid()), params.result); +} + // Test the four combinations of optional_attr {false, true} and cgroup attribute { does not exist, // exists }. INSTANTIATE_TEST_SUITE_P( @@ -215,4 +241,28 @@ INSTANTIATE_TEST_SUITE_P( .log_prefix = "Failed to write", .log_suffix = geteuid() == 0 ? "Invalid argument" : "Permission denied"})); +// Test TaskProfile IsValid calls. +INSTANTIATE_TEST_SUITE_P( + TaskProfileTestSuite, TaskProfileFixture, + Values( + // Test operating on non-existing cgroup attribute fails. + TestParam{.attr_name = "no-such-attribute", + .attr_value = ".", + .optional_attr = false, + .result = false}, + // Test operating on optional non-existing cgroup attribute succeeds. + TestParam{.attr_name = "no-such-attribute", + .attr_value = ".", + .optional_attr = true, + .result = true}, + // Test operating on existing cgroup attribute succeeds. + TestParam{.attr_name = "cgroup.procs", + .attr_value = ".", + .optional_attr = false, + .result = true}, + // Test operating on optional existing cgroup attribute succeeds. + TestParam{.attr_name = "cgroup.procs", + .attr_value = ".", + .optional_attr = true, + .result = true})); } // namespace From e80a6b6dd403ef0cabb35dfefa798a6e72d775d3 Mon Sep 17 00:00:00 2001 From: Vincent Donnefort Date: Fri, 28 Apr 2023 09:30:23 +0100 Subject: [PATCH 0037/1487] ramdisk_node_list: Add urandom node Bionic requires random numbers to init the shadow call stack. Those numbers are obtained via the syscall getrandom (non-blocking) and will fallback to /dev/urandom if the former fails. When loading pKVM modules, we are so early in the boot process that the only source of entropy for the linux RNG are the architecture random number generators... which might be available on some platforms. Without any source of entropy, the only way of generating a random number is to try to generate some, which is what the bionic fallback expects via urandom. As a consequence, add the urandom node to the initramfs. Bug: 274876849 Merged-In: I111e2db53fabd63d070b8e9ab9c52faebf484ab3 Change-Id: I34a0e3f7c72de7344512366d4a96183b445edc2e --- rootdir/ramdisk_node_list | 1 + 1 file changed, 1 insertion(+) diff --git a/rootdir/ramdisk_node_list b/rootdir/ramdisk_node_list index d3ab8a66ea89..4f45faaec47e 100644 --- a/rootdir/ramdisk_node_list +++ b/rootdir/ramdisk_node_list @@ -1,3 +1,4 @@ dir dev 0755 0 0 nod dev/null 0600 0 0 c 1 3 nod dev/console 0600 0 0 c 5 1 +nod dev/urandom 0600 0 0 c 1 9 From ac9fbbcb05254d00d5b4f5c8d3d2827c28370ef6 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Tue, 2 May 2023 22:09:32 +0000 Subject: [PATCH 0038/1487] libsnapshot: Turn off vabc_legacy_tests on presubmit Temporarily turn off these tests until root cause is found. Bug: 279009697 Test: presubmit Signed-off-by: Akilesh Kailash (cherry picked from https://android-review.googlesource.com/q/commit:defe8381aac9d461f6de8690b5917771b5f6752f) Merged-In: I90f695fac318b71871ff60c1f74c90265437687d Change-Id: I90f695fac318b71871ff60c1f74c90265437687d --- fs_mgr/TEST_MAPPING | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING index db27cf000322..d357e4571dcf 100644 --- a/fs_mgr/TEST_MAPPING +++ b/fs_mgr/TEST_MAPPING @@ -24,9 +24,8 @@ { "name": "vab_legacy_tests" }, - { - "name": "vabc_legacy_tests" - }, + // TODO: b/279009697 + //{"name": "vabc_legacy_tests"}, { "name": "cow_api_test" } @@ -43,9 +42,8 @@ }, { "name": "vab_legacy_tests" - }, - { - "name": "vabc_legacy_tests" } + // TODO: b/279009697 + //{"name": "vabc_legacy_tests"} ] } From 3f96053b3895f09b2887ee08ceda2bfcb857053d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 3 May 2023 11:26:13 -0700 Subject: [PATCH 0039/1487] DO NOT MERGE: libsnapshot: Fix test failures on certain configurations. Due to how CF is built and tested, VABC is enabled even when not supported by the kernel. To work around this add some logic in libsnapshot and the test harness to recognize this situation and silently flip off the VABC flag. This also fixes the -force_mode option to vts_libsnapshot_test, so that it will skip tests that aren't supported by the device. Bug: 264279496 Test: vts_libsnapshot_test on android13-gsi with 11-5.4 kernel Change-Id: I9279d8d400cac5cd504a7ae91f254aae57fa856d --- fs_mgr/libsnapshot/snapshot.cpp | 3 ++- fs_mgr/libsnapshot/snapshot_test.cpp | 4 ++-- fs_mgr/libsnapshot/utility.cpp | 7 +++++++ fs_mgr/libsnapshot/utility.h | 1 + 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index 019b64a44392..cd4c56048c20 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -3166,7 +3166,8 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife << " writer.GetCowVersion(): " << writer.GetCowVersion(); bool use_compression = IsCompressionEnabled() && dap_metadata.vabc_enabled() && - !device_->IsRecovery() && cow_format_support; + !device_->IsRecovery() && cow_format_support && + KernelSupportsCompressedSnapshots(); std::string compression_algorithm; if (use_compression) { diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index e7ffb1600cd1..a741134b8b6d 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -2760,7 +2760,7 @@ bool IsDaemonRequired() { return true; } - return IsUserspaceSnapshotsEnabled(); + return IsUserspaceSnapshotsEnabled() && KernelSupportsCompressedSnapshots(); } bool ShouldUseCompression() { @@ -2770,7 +2770,7 @@ bool ShouldUseCompression() { if (FLAGS_force_config == "vabc") { return true; } - return IsCompressionEnabled(); + return IsCompressionEnabled() && KernelSupportsCompressedSnapshots(); } } // namespace snapshot diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp index f01bec938788..841acf459168 100644 --- a/fs_mgr/libsnapshot/utility.cpp +++ b/fs_mgr/libsnapshot/utility.cpp @@ -26,7 +26,9 @@ #include #include #include +#include +using android::dm::DeviceMapper; using android::dm::kSectorSize; using android::fiemap::FiemapStatus; using android::fs_mgr::EnsurePathMounted; @@ -208,5 +210,10 @@ bool IsDmSnapshotTestingEnabled() { return android::base::GetBoolProperty("snapuserd.test.dm.snapshots", false); } +bool KernelSupportsCompressedSnapshots() { + auto& dm = DeviceMapper::Instance(); + return dm.GetTargetByName("user", nullptr); +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h index 0ef3234fd8ac..0794154c02c2 100644 --- a/fs_mgr/libsnapshot/utility.h +++ b/fs_mgr/libsnapshot/utility.h @@ -129,6 +129,7 @@ std::ostream& operator<<(std::ostream& os, const Now&); void AppendExtent(google::protobuf::RepeatedPtrField* extents, uint64_t start_block, uint64_t num_blocks); +bool KernelSupportsCompressedSnapshots(); bool IsCompressionEnabled(); bool IsUserspaceSnapshotsEnabled(); From 778d7e80a6d9967a874944e3f02f0c04213bf31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 27 Apr 2023 19:27:23 +0000 Subject: [PATCH 0040/1487] remove inprocess tethering Test: TreeHugger Bug: 279942846 (cherry picked from https://android-review.googlesource.com/q/commit:e37468b295851b97db07936e15f53af660607cb4) Merged-In: Ia3a5d289cceac96d310e04fbae3588789cc859ca Change-Id: Ia3a5d289cceac96d310e04fbae3588789cc859ca --- libcutils/fs_config.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp index 79d79dd4466f..f90a1bc3ca98 100644 --- a/libcutils/fs_config.cpp +++ b/libcutils/fs_config.cpp @@ -84,14 +84,12 @@ static const struct fs_path_config android_dirs[] = { { 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" }, @@ -199,9 +197,7 @@ static const struct fs_path_config android_files[] = { // 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) | From 7c9c8f52e75daf30ae0cc6130c321769a23e320d Mon Sep 17 00:00:00 2001 From: Martin Stjernholm Date: Thu, 11 May 2023 16:02:30 +0100 Subject: [PATCH 0041/1487] Run art_boot before odsign. It's necessary to have the right dalvik.vm.* flags in place when they are validated by odrefresh. Test: See the other CL in the topic. Bug: 281850017 Ignore-AOSP-First: Will cherry-pick to AOSP later Change-Id: Ib64790dde97faaa6b62ead2c1c8dd53c97f97f9c --- rootdir/init.rc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rootdir/init.rc b/rootdir/init.rc index 7326783c838a..41c60a7f9dda 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -1024,6 +1024,11 @@ on post-fs-data exec_start derive_classpath load_exports /data/system/environ/classpath + # Start ART's oneshot boot service to propagate boot experiment flags to + # dalvik.vm.*. This needs to be done before odsign since odrefresh uses and + # validates those properties against the signed cache-info.xml. + exec_start art_boot + # Start the on-device signing daemon, and wait for it to finish, to ensure # ART artifacts are generated if needed. # Must start after 'derive_classpath' to have *CLASSPATH variables set. From 6f742376bc81df0f281579ca5ef1824ea798e08b Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Tue, 18 Apr 2023 18:01:30 -0700 Subject: [PATCH 0042/1487] Add support for reading modules.load.charger when booting into charger mode When booting up, Android can boot into one of three modes: normal, recovery, and charger mode. The set of modules that should be loaded during first stage init in each mode can differ, which is why init reads the list of modules to load from modules.load.recovery when booting into recovery, and modules.load otherwise. This means that init will read the list of modules to load during first stage init from modules.load even when booting into charger mode. This is not ideal, as it causes modules that need to be loaded during first stage init only when booting into charger mode to also be loaded during first stage init of normal boot, which can degrade boot time. Thus, add support for reading modules.load.charger, which contains the list of modules that need to be loaded during first stage init when booting into charger mode. Bug: 266752750 Change-Id: Ib9178bdfe5a6aac57b86b6d453b03625e95d5b48 Signed-off-by: Isaac J. Manjarres --- init/first_stage_init.cpp | 57 ++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index 107e99a31554..bff80c5c731f 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -58,6 +58,12 @@ namespace init { namespace { +enum class BootMode { + NORMAL_MODE, + RECOVERY_MODE, + CHARGER_MODE, +}; + void FreeRamdisk(DIR* dir, dev_t dev) { int dfd = dirfd(dir); @@ -149,13 +155,27 @@ void PrepareSwitchRoot() { } } // namespace -std::string GetModuleLoadList(bool recovery, const std::string& dir_path) { - auto module_load_file = "modules.load"; - if (recovery) { - struct stat fileStat; - std::string recovery_load_path = dir_path + "/modules.load.recovery"; - if (!stat(recovery_load_path.c_str(), &fileStat)) { +std::string GetModuleLoadList(BootMode boot_mode, const std::string& dir_path) { + std::string module_load_file; + + switch (boot_mode) { + case BootMode::NORMAL_MODE: + module_load_file = "modules.load"; + break; + case BootMode::RECOVERY_MODE: module_load_file = "modules.load.recovery"; + break; + case BootMode::CHARGER_MODE: + module_load_file = "modules.load.charger"; + break; + } + + if (module_load_file != "modules.load") { + struct stat fileStat; + std::string load_path = dir_path + "/" + module_load_file; + // Fall back to modules.load if the other files aren't accessible + if (stat(load_path.c_str(), &fileStat)) { + module_load_file = "modules.load"; } } @@ -163,7 +183,8 @@ std::string GetModuleLoadList(bool recovery, const std::string& dir_path) { } #define MODULE_BASE_DIR "/lib/modules" -bool LoadKernelModules(bool recovery, bool want_console, bool want_parallel, int& modules_loaded) { +bool LoadKernelModules(BootMode boot_mode, bool want_console, bool want_parallel, + int& modules_loaded) { struct utsname uts; if (uname(&uts)) { LOG(FATAL) << "Failed to get kernel version."; @@ -203,7 +224,7 @@ bool LoadKernelModules(bool recovery, bool want_console, bool want_parallel, int for (const auto& module_dir : module_dirs) { std::string dir_path = MODULE_BASE_DIR "/"; dir_path.append(module_dir); - Modprobe m({dir_path}, GetModuleLoadList(recovery, dir_path)); + Modprobe m({dir_path}, GetModuleLoadList(boot_mode, dir_path)); bool retval = m.LoadListedModules(!want_console); modules_loaded = m.GetModuleCount(); if (modules_loaded > 0) { @@ -211,7 +232,7 @@ bool LoadKernelModules(bool recovery, bool want_console, bool want_parallel, int } } - Modprobe m({MODULE_BASE_DIR}, GetModuleLoadList(recovery, MODULE_BASE_DIR)); + Modprobe m({MODULE_BASE_DIR}, GetModuleLoadList(boot_mode, MODULE_BASE_DIR)); bool retval = (want_parallel) ? m.LoadModulesParallel(std::thread::hardware_concurrency()) : m.LoadListedModules(!want_console); modules_loaded = m.GetModuleCount(); @@ -221,6 +242,21 @@ bool LoadKernelModules(bool recovery, bool want_console, bool want_parallel, int return true; } +static bool IsChargerMode(const std::string& cmdline, const std::string& bootconfig) { + return bootconfig.find("androidboot.mode = \"charger\"") != std::string::npos || + cmdline.find("androidboot.mode=charger") != std::string::npos; +} + +static BootMode GetBootMode(const std::string& cmdline, const std::string& bootconfig) +{ + if (IsChargerMode(cmdline, bootconfig)) + return BootMode::CHARGER_MODE; + else if (IsRecoveryMode() && !ForceNormalBoot(cmdline, bootconfig)) + return BootMode::RECOVERY_MODE; + + return BootMode::NORMAL_MODE; +} + int FirstStageMain(int argc, char** argv) { if (REBOOT_BOOTLOADER_ON_PANIC) { InstallRebootSignalHandlers(); @@ -328,7 +364,8 @@ int FirstStageMain(int argc, char** argv) { boot_clock::time_point module_start_time = boot_clock::now(); int module_count = 0; - if (!LoadKernelModules(IsRecoveryMode() && !ForceNormalBoot(cmdline, bootconfig), want_console, + BootMode boot_mode = GetBootMode(cmdline, bootconfig); + if (!LoadKernelModules(boot_mode, want_console, want_parallel, module_count)) { if (want_console != FirstStageConsoleParam::DISABLED) { LOG(ERROR) << "Failed to load kernel modules, starting console"; From 878406e7f1d6ecec51bca80f834011e0ba2f1126 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 12 May 2023 16:29:02 -0700 Subject: [PATCH 0043/1487] Revert "task_profiles.json: Convert tabs into spaces" This reverts commit 6ad747ac2d3d0508a9a9223c8d0a2acbad513c29. Bug: 261857030 Ignore-AOSP-First: this change is for the U branch only. Change-Id: I93447b71146e6e9297ef49026d90dc4c35b91244 Signed-off-by: Bart Van Assche --- libprocessgroup/profiles/task_profiles.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json index e44d3bf727df..4b8fc19db7c6 100644 --- a/libprocessgroup/profiles/task_profiles.json +++ b/libprocessgroup/profiles/task_profiles.json @@ -462,7 +462,7 @@ { "Controller": "blkio", "Path": "background" - } + } }, { "Name": "SetAttribute", @@ -502,7 +502,7 @@ { "Controller": "blkio", "Path": "" - } + } }, { "Name": "SetAttribute", @@ -542,7 +542,7 @@ { "Controller": "blkio", "Path": "" - } + } }, { "Name": "SetAttribute", @@ -582,7 +582,7 @@ { "Controller": "blkio", "Path": "" - } + } }, { "Name": "SetAttribute", From f4a3d72ee8f35fb7bd8e750c1d7b3bd182bb3c3e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 12 May 2023 16:29:39 -0700 Subject: [PATCH 0044/1487] Revert "Updating Attributes on task_profiles.json" This reverts commit 92153fb955cd2c59cf9eba07461ddaba1c3d7792. Bug: 261857030 Ignore-AOSP-First: this change is for the U branch only. Change-Id: I99417707f0d0b8c7dca3927b6ce9d52436621f4e Signed-off-by: Bart Van Assche --- libprocessgroup/profiles/task_profiles.json | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json index 4b8fc19db7c6..c485097882fc 100644 --- a/libprocessgroup/profiles/task_profiles.json +++ b/libprocessgroup/profiles/task_profiles.json @@ -80,20 +80,17 @@ { "Name": "BfqWeight", "Controller": "io", - "File": "blkio.bfq.weight", - "FileV2": "io.bfq.weight" + "File": "io.bfq.weight" }, { "Name": "CfqGroupIdle", "Controller": "io", - "File": "blkio.group_idle", - "FileV2": "io.group_idle" + "File": "io.group_idle" }, { "Name": "CfqWeight", "Controller": "io", - "File": "blkio.weight", - "FileV2": "io.weight" + "File": "io.weight" } ], From 9fe04000806f9f4d74771e6421e8d3c078fe1887 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 12 May 2023 16:29:43 -0700 Subject: [PATCH 0045/1487] Revert "libprocessgroup: Add I/O scheduler attributes to task_profiles.json" This reverts commit 9c0fcbb0f7107d455a004719f40435a2a2318fda. Bug: 261857030 Ignore-AOSP-First: this change is for the U branch only. Change-Id: Id4bd3494b33dd6bc0644406d599c9bfd597c7435 Signed-off-by: Bart Van Assche --- libprocessgroup/profiles/task_profiles.json | 123 -------------------- 1 file changed, 123 deletions(-) diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json index c485097882fc..1fc66ba10a64 100644 --- a/libprocessgroup/profiles/task_profiles.json +++ b/libprocessgroup/profiles/task_profiles.json @@ -76,21 +76,6 @@ "Name": "FreezerState", "Controller": "freezer", "File": "cgroup.freeze" - }, - { - "Name": "BfqWeight", - "Controller": "io", - "File": "io.bfq.weight" - }, - { - "Name": "CfqGroupIdle", - "Controller": "io", - "File": "io.group_idle" - }, - { - "Name": "CfqWeight", - "Controller": "io", - "File": "io.weight" } ], @@ -459,33 +444,6 @@ { "Controller": "blkio", "Path": "background" - } - }, - { - "Name": "SetAttribute", - "Params": - { - "Name": "BfqWeight", - "Value": "10", - "Optional": "true" - } - }, - { - "Name": "SetAttribute", - "Params": - { - "Name": "CfqGroupIdle", - "Value": "0", - "Optional": "true" - } - }, - { - "Name": "SetAttribute", - "Params": - { - "Name": "CfqWeight", - "Value": "200", - "Optional": "true" } } ] @@ -499,33 +457,6 @@ { "Controller": "blkio", "Path": "" - } - }, - { - "Name": "SetAttribute", - "Params": - { - "Name": "BfqWeight", - "Value": "100", - "Optional": "true" - } - }, - { - "Name": "SetAttribute", - "Params": - { - "Name": "CfqGroupIdle", - "Value": "0", - "Optional": "true" - } - }, - { - "Name": "SetAttribute", - "Params": - { - "Name": "CfqWeight", - "Value": "1000", - "Optional": "true" } } ] @@ -539,33 +470,6 @@ { "Controller": "blkio", "Path": "" - } - }, - { - "Name": "SetAttribute", - "Params": - { - "Name": "BfqWeight", - "Value": "100", - "Optional": "true" - } - }, - { - "Name": "SetAttribute", - "Params": - { - "Name": "CfqGroupIdle", - "Value": "0", - "Optional": "true" - } - }, - { - "Name": "SetAttribute", - "Params": - { - "Name": "CfqWeight", - "Value": "1000", - "Optional": "true" } } ] @@ -579,33 +483,6 @@ { "Controller": "blkio", "Path": "" - } - }, - { - "Name": "SetAttribute", - "Params": - { - "Name": "BfqWeight", - "Value": "100", - "Optional": "true" - } - }, - { - "Name": "SetAttribute", - "Params": - { - "Name": "CfqGroupIdle", - "Value": "0", - "Optional": "true" - } - }, - { - "Name": "SetAttribute", - "Params": - { - "Name": "CfqWeight", - "Value": "1000", - "Optional": "true" } } ] From a37c4d2796779444a59f6cac8384b62e66e78f1e Mon Sep 17 00:00:00 2001 From: JW Wang Date: Sat, 18 Feb 2023 15:16:17 +0800 Subject: [PATCH 0046/1487] Export active dsu slot to system prop The prop can be consumed by init scripts to do customized setup: on property:ro.gsid.dsu_slot=oemtest # Do setup for test on property:ro.gsid.dsu_slot=oemdemo # Do setup for demo Bug: 277691885 Test: m Change-Id: I7bd78b9ba31021b27d57c6f092dad5d7ebf6e59b --- init/init.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/init/init.cpp b/init/init.cpp index be1ebeed7cc0..da63fdc3bda5 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -1043,6 +1043,12 @@ int SecondStageMain(int argc, char** argv) { SetProperty(gsi::kGsiBootedProp, is_running); auto is_installed = android::gsi::IsGsiInstalled() ? "1" : "0"; SetProperty(gsi::kGsiInstalledProp, is_installed); + if (android::gsi::IsGsiRunning()) { + std::string dsu_slot; + if (android::gsi::GetActiveDsu(&dsu_slot)) { + SetProperty(gsi::kDsuSlotProp, dsu_slot); + } + } am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups"); am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict"); From 655a03f7c2126e34fb7854840ade17a0380adb69 Mon Sep 17 00:00:00 2001 From: Martin Stjernholm Date: Mon, 15 May 2023 19:29:00 +0000 Subject: [PATCH 0047/1487] Run art_boot before odsign. It's necessary to have the right dalvik.vm.* flags in place when they are validated by odrefresh. Test: See the other CL in the topic. Bug: 281850017 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:7c9c8f52e75daf30ae0cc6130c321769a23e320d) Merged-In: Ib64790dde97faaa6b62ead2c1c8dd53c97f97f9c Change-Id: Ib64790dde97faaa6b62ead2c1c8dd53c97f97f9c --- rootdir/init.rc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rootdir/init.rc b/rootdir/init.rc index d755b503d670..fdad27397473 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -1004,6 +1004,11 @@ on post-fs-data exec_start derive_classpath load_exports /data/system/environ/classpath + # Start ART's oneshot boot service to propagate boot experiment flags to + # dalvik.vm.*. This needs to be done before odsign since odrefresh uses and + # validates those properties against the signed cache-info.xml. + exec_start art_boot + # Start the on-device signing daemon, and wait for it to finish, to ensure # ART artifacts are generated if needed. # Must start after 'derive_classpath' to have *CLASSPATH variables set. From d2d320ab0b442a887a0ef2457d28ab4cdd214f28 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Mon, 15 May 2023 22:25:55 +0000 Subject: [PATCH 0048/1487] Return error from gatekeeperd Instead of crashing the gatekeeperd on incorrect inputs to AIDL interface, return errors from the service. Test: m gatekeeperd, booted device Bug: 279970163 Change-Id: Ifd3330e749f4ce147db5886f1f2dbb00c322bed2 --- gatekeeperd/gatekeeperd.cpp | 39 +++++++++++++++++++++++++++++-------- gatekeeperd/gatekeeperd.h | 2 +- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp index e5241b5842a7..7987167662dc 100644 --- a/gatekeeperd/gatekeeperd.cpp +++ b/gatekeeperd/gatekeeperd.cpp @@ -144,14 +144,22 @@ void GateKeeperProxy::clear_sid(uint32_t userId) { } } -uint32_t GateKeeperProxy::adjust_userId(uint32_t userId) { +Status GateKeeperProxy::adjust_userId(uint32_t userId, uint32_t* hw_userId) { static constexpr uint32_t kGsiOffset = 1000000; - CHECK(userId < kGsiOffset); - CHECK((aidl_hw_device != nullptr) || (hw_device != nullptr)); + if (userId >= kGsiOffset) { + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); + } + + if ((aidl_hw_device == nullptr) && (hw_device == nullptr)) { + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); + } + if (is_running_gsi) { - return userId + kGsiOffset; + *hw_userId = userId + kGsiOffset; + return Status::ok(); } - return userId; + *hw_userId = userId; + return Status::ok(); } #define GK_ERROR *gkResponse = GKResponse::error(), Status::ok() @@ -201,7 +209,12 @@ Status GateKeeperProxy::enroll(int32_t userId, android::hardware::hidl_vec newPwd; newPwd.setToExternal(const_cast(desiredPassword.data()), desiredPassword.size()); - uint32_t hw_userId = adjust_userId(userId); + uint32_t hw_userId = 0; + Status result = adjust_userId(userId, &hw_userId); + if (!result.isOk()) { + return result; + } + uint64_t secureUserId = 0; if (aidl_hw_device) { // AIDL gatekeeper service @@ -300,7 +313,12 @@ Status GateKeeperProxy::verifyChallenge(int32_t userId, int64_t challenge, } } - uint32_t hw_userId = adjust_userId(userId); + uint32_t hw_userId = 0; + Status result = adjust_userId(userId, &hw_userId); + if (!result.isOk()) { + return result; + } + android::hardware::hidl_vec curPwdHandle; curPwdHandle.setToExternal(const_cast(enrolledPasswordHandle.data()), enrolledPasswordHandle.size()); @@ -410,7 +428,12 @@ Status GateKeeperProxy::clearSecureUserId(int32_t userId) { } clear_sid(userId); - uint32_t hw_userId = adjust_userId(userId); + uint32_t hw_userId = 0; + Status result = adjust_userId(userId, &hw_userId); + if (!result.isOk()) { + return result; + } + if (aidl_hw_device) { aidl_hw_device->deleteUser(hw_userId); } else if (hw_device) { diff --git a/gatekeeperd/gatekeeperd.h b/gatekeeperd/gatekeeperd.h index 29873da29381..b1f08c6113b9 100644 --- a/gatekeeperd/gatekeeperd.h +++ b/gatekeeperd/gatekeeperd.h @@ -47,7 +47,7 @@ class GateKeeperProxy : public BnGateKeeperService { // This should only be called on userIds being passed to the GateKeeper HAL. It ensures that // secure storage shared across a GSI image and a host image will not overlap. - uint32_t adjust_userId(uint32_t userId); + Status adjust_userId(uint32_t userId, uint32_t* hw_userId); #define GK_ERROR *gkResponse = GKResponse::error(), Status::ok() From ce09cdff6213522f4429cabf72950bffaf0f6c1e Mon Sep 17 00:00:00 2001 From: JW Wang Date: Sat, 18 Feb 2023 15:16:17 +0800 Subject: [PATCH 0049/1487] Export active dsu slot to system prop The prop can be consumed by init scripts to do customized setup: on property:ro.gsid.dsu_slot=oemtest # Do setup for test on property:ro.gsid.dsu_slot=oemdemo # Do setup for demo Bug: 277691885 Test: m Change-Id: I7bd78b9ba31021b27d57c6f092dad5d7ebf6e59b Merged-In: I7bd78b9ba31021b27d57c6f092dad5d7ebf6e59b Cherry-picked from aosp/2588465 --- init/init.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/init/init.cpp b/init/init.cpp index be1ebeed7cc0..da63fdc3bda5 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -1043,6 +1043,12 @@ int SecondStageMain(int argc, char** argv) { SetProperty(gsi::kGsiBootedProp, is_running); auto is_installed = android::gsi::IsGsiInstalled() ? "1" : "0"; SetProperty(gsi::kGsiInstalledProp, is_installed); + if (android::gsi::IsGsiRunning()) { + std::string dsu_slot; + if (android::gsi::GetActiveDsu(&dsu_slot)) { + SetProperty(gsi::kDsuSlotProp, dsu_slot); + } + } am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups"); am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict"); From 4066926374ef7cadbd29789c8ddf6698801557ab Mon Sep 17 00:00:00 2001 From: Mike McTernan Date: Tue, 16 May 2023 09:05:29 +0100 Subject: [PATCH 0050/1487] confirmationui:fuzzer: update contact details Bug: None Test: make trusty_confirmationui_tipc_fuzzer Change-Id: Ie81bf916c41498abc226389f63b22b57da55d446 --- trusty/confirmationui/fuzz/Android.bp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/trusty/confirmationui/fuzz/Android.bp b/trusty/confirmationui/fuzz/Android.bp index 47809433a449..96804bd4bdad 100644 --- a/trusty/confirmationui/fuzz/Android.bp +++ b/trusty/confirmationui/fuzz/Android.bp @@ -26,7 +26,8 @@ cc_fuzz { "-DTRUSTY_APP_FILENAME=\"confirmationui.syms.elf\"", ], fuzz_config: { - cc: ["trong@google.com"], + cc: ["mikemcternan@google.com"], + componentid: 1290237, }, } @@ -40,7 +41,8 @@ cc_fuzz { "libdmabufheap", ], fuzz_config: { - cc: ["trong@google.com"], + cc: ["mikemcternan@google.com"], + componentid: 1290237, }, // The initial corpus for this fuzzer was derived by dumping messages from/to From 880656af8191a3bb906134dd23cd5ea680f9087a Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Tue, 16 May 2023 10:41:36 +0100 Subject: [PATCH 0051/1487] Add tipc fuzzer for KeyMint/Rust Also update fuzz config for the KeyMint/C++ fuzzer Test: trusty_keymint_fuzzer Change-Id: Ic96c572ff6d154afefba280667c23e4e324d7751 --- trusty/keymaster/fuzz/Android.bp | 4 +- trusty/keymint/fuzz/Android.bp | 37 ++++++++++++++++++ .../keymint/fuzz/corpus/keymint-reqs-821180-0 | 1 + .../fuzz/corpus/keymint-reqs-82128140-0 | 1 + .../fuzz/corpus/keymint-reqs-82128143-0 | 1 + .../fuzz/corpus/keymint-reqs-82128158-0 | 1 + .../fuzz/corpus/keymint-reqs-82128158-1 | 2 + .../fuzz/corpus/keymint-reqs-82138285-0 | Bin 0 -> 48 bytes .../fuzz/corpus/keymint-reqs-82138285-1 | Bin 0 -> 48 bytes .../fuzz/corpus/keymint-reqs-82138285-2 | Bin 0 -> 48 bytes .../fuzz/corpus/keymint-reqs-82138285-3 | Bin 0 -> 48 bytes .../fuzz/corpus/keymint-reqs-82138286-0 | Bin 0 -> 61 bytes .../fuzz/corpus/keymint-reqs-82138286-1 | Bin 0 -> 61 bytes .../fuzz/corpus/keymint-reqs-82138286-2 | Bin 0 -> 61 bytes .../fuzz/corpus/keymint-reqs-82138286-3 | Bin 0 -> 55 bytes .../fuzz/corpus/keymint-reqs-82138287-0 | Bin 0 -> 68 bytes .../fuzz/corpus/keymint-reqs-82138287-1 | Bin 0 -> 68 bytes .../fuzz/corpus/keymint-reqs-82138287-2 | Bin 0 -> 68 bytes .../fuzz/corpus/keymint-reqs-82138287-3 | Bin 0 -> 67 bytes .../fuzz/corpus/keymint-reqs-82138288-0 | Bin 0 -> 1481 bytes .../fuzz/corpus/keymint-reqs-82138288-1 | Bin 0 -> 75 bytes .../fuzz/corpus/keymint-reqs-82138288-2 | Bin 0 -> 65 bytes .../fuzz/corpus/keymint-reqs-82138288-3 | Bin 0 -> 73 bytes .../fuzz/corpus/keymint-reqs-82138289-0 | Bin 0 -> 80 bytes .../fuzz/corpus/keymint-reqs-82138289-1 | Bin 0 -> 392 bytes .../fuzz/corpus/keymint-reqs-82138289-2 | Bin 0 -> 407 bytes .../fuzz/corpus/keymint-reqs-82138289-3 | Bin 0 -> 1494 bytes .../fuzz/corpus/keymint-reqs-8213828a-0 | Bin 0 -> 466 bytes .../fuzz/corpus/keymint-reqs-8213828a-1 | Bin 0 -> 1504 bytes .../fuzz/corpus/keymint-reqs-8213828a-2 | Bin 0 -> 1502 bytes .../fuzz/corpus/keymint-reqs-8213828a-3 | Bin 0 -> 130 bytes .../fuzz/corpus/keymint-reqs-8213828b-0 | Bin 0 -> 139 bytes .../fuzz/corpus/keymint-reqs-8213828b-1 | Bin 0 -> 1555 bytes .../fuzz/corpus/keymint-reqs-8213828b-2 | Bin 0 -> 130 bytes .../fuzz/corpus/keymint-reqs-8213828b-3 | Bin 0 -> 1553 bytes .../fuzz/corpus/keymint-reqs-8213828c-0 | Bin 0 -> 137 bytes .../fuzz/corpus/keymint-reqs-8213828c-1 | Bin 0 -> 1518 bytes .../fuzz/corpus/keymint-reqs-8213828c-2 | Bin 0 -> 146 bytes .../fuzz/corpus/keymint-reqs-8213828c-3 | Bin 0 -> 1542 bytes .../fuzz/corpus/keymint-reqs-8213828d-0 | Bin 0 -> 140 bytes .../fuzz/corpus/keymint-reqs-8213828d-1 | Bin 0 -> 124 bytes .../fuzz/corpus/keymint-reqs-8213828d-2 | Bin 0 -> 139 bytes .../fuzz/corpus/keymint-reqs-8213828d-3 | Bin 0 -> 139 bytes .../fuzz/corpus/keymint-reqs-8213828e-0 | Bin 0 -> 129 bytes .../fuzz/corpus/keymint-reqs-8213828e-1 | Bin 0 -> 151 bytes .../fuzz/corpus/keymint-reqs-8213828e-2 | Bin 0 -> 151 bytes .../fuzz/corpus/keymint-reqs-8213828e-3 | Bin 0 -> 151 bytes .../fuzz/corpus/keymint-reqs-8213828f-0 | Bin 0 -> 370 bytes .../fuzz/corpus/keymint-reqs-8213828f-1 | Bin 0 -> 370 bytes .../fuzz/corpus/keymint-reqs-8213828f-2 | Bin 0 -> 286 bytes .../fuzz/corpus/keymint-reqs-8213828f-3 | Bin 0 -> 280 bytes .../fuzz/corpus/keymint-reqs-82138290-0 | Bin 0 -> 131 bytes .../fuzz/corpus/keymint-reqs-82138290-1 | Bin 0 -> 131 bytes .../fuzz/corpus/keymint-reqs-82138292-0 | Bin 0 -> 145 bytes .../fuzz/corpus/keymint-reqs-82148485-0 | Bin 0 -> 83 bytes .../fuzz/corpus/keymint-reqs-82148485-1 | Bin 0 -> 59 bytes .../fuzz/corpus/keymint-reqs-82148485-2 | Bin 0 -> 83 bytes .../fuzz/corpus/keymint-reqs-82148485-3 | Bin 0 -> 59 bytes .../fuzz/corpus/keymint-reqs-82148486-0 | Bin 0 -> 106 bytes .../fuzz/corpus/keymint-reqs-82148486-1 | Bin 0 -> 90 bytes .../fuzz/corpus/keymint-reqs-82148486-2 | Bin 0 -> 106 bytes .../fuzz/corpus/keymint-reqs-82148486-3 | Bin 0 -> 106 bytes .../fuzz/corpus/keymint-reqs-82148487-0 | Bin 0 -> 79 bytes .../fuzz/corpus/keymint-reqs-82148487-1 | Bin 0 -> 80 bytes .../fuzz/corpus/keymint-reqs-82148487-2 | Bin 0 -> 80 bytes .../fuzz/corpus/keymint-reqs-82148487-3 | Bin 0 -> 80 bytes .../fuzz/corpus/keymint-reqs-82148488-0 | Bin 0 -> 222 bytes .../fuzz/corpus/keymint-reqs-82148488-1 | Bin 0 -> 210 bytes .../fuzz/corpus/keymint-reqs-82148488-2 | Bin 0 -> 107 bytes .../fuzz/corpus/keymint-reqs-82148488-3 | Bin 0 -> 706 bytes .../fuzz/corpus/keymint-reqs-82148489-0 | Bin 0 -> 715 bytes .../fuzz/corpus/keymint-reqs-82148489-1 | Bin 0 -> 719 bytes .../fuzz/corpus/keymint-reqs-82148489-2 | Bin 0 -> 217 bytes .../fuzz/corpus/keymint-reqs-82148489-3 | Bin 0 -> 217 bytes .../fuzz/corpus/keymint-reqs-8214848a-0 | Bin 0 -> 1310 bytes .../fuzz/corpus/keymint-reqs-8214848a-1 | Bin 0 -> 104 bytes .../fuzz/corpus/keymint-reqs-8214848a-2 | Bin 0 -> 726 bytes .../fuzz/corpus/keymint-reqs-8214848a-3 | Bin 0 -> 1311 bytes .../fuzz/corpus/keymint-reqs-8214848b-0 | Bin 0 -> 1317 bytes .../fuzz/corpus/keymint-reqs-82158659-0 | Bin 0 -> 1837 bytes .../fuzz/corpus/keymint-reqs-82158659-1 | Bin 0 -> 1839 bytes .../fuzz/corpus/keymint-reqs-82158659-2 | Bin 0 -> 1837 bytes .../fuzz/corpus/keymint-reqs-82158659-3 | Bin 0 -> 1837 bytes .../fuzz/corpus/keymint-reqs-82168258-0 | 1 + .../fuzz/corpus/keymint-reqs-82168258-1 | Bin 0 -> 206 bytes .../fuzz/corpus/keymint-reqs-82178158-0 | Bin 0 -> 206 bytes .../fuzz/corpus/keymint-reqs-82178158-1 | Bin 0 -> 205 bytes .../fuzz/corpus/keymint-reqs-82178158-2 | Bin 0 -> 205 bytes .../fuzz/corpus/keymint-reqs-82178158-3 | Bin 0 -> 201 bytes .../fuzz/corpus/keymint-reqs-82178159-0 | Bin 0 -> 314 bytes .../fuzz/corpus/keymint-reqs-82178159-1 | Bin 0 -> 314 bytes .../fuzz/corpus/keymint-reqs-82178159-2 | Bin 0 -> 314 bytes .../fuzz/corpus/keymint-reqs-82178159-3 | Bin 0 -> 314 bytes .../fuzz/corpus/keymint-reqs-82181a84-0 | Bin 0 -> 326 bytes .../fuzz/corpus/keymint-reqs-82181a84-1 | Bin 0 -> 272 bytes .../fuzz/corpus/keymint-reqs-82181a84-2 | Bin 0 -> 326 bytes .../fuzz/corpus/keymint-reqs-82181a84-3 | Bin 0 -> 326 bytes .../fuzz/corpus/keymint-reqs-82181e83-0 | Bin 0 -> 208 bytes .../fuzz/corpus/keymint-reqs-82181e83-1 | Bin 0 -> 308 bytes .../fuzz/corpus/keymint-reqs-82181e83-2 | Bin 0 -> 308 bytes .../fuzz/corpus/keymint-reqs-82181e83-3 | Bin 0 -> 308 bytes .../fuzz/corpus/keymint-reqs-82183184-0 | 1 + .../fuzz/corpus/keymint-reqs-82183184-1 | 1 + .../fuzz/corpus/keymint-reqs-82183184-2 | 1 + .../fuzz/corpus/keymint-reqs-82183184-3 | 1 + .../fuzz/corpus/keymint-reqs-82183284-0 | 1 + .../fuzz/corpus/keymint-reqs-82183284-1 | Bin 0 -> 17 bytes .../fuzz/corpus/keymint-reqs-82183284-2 | 1 + .../fuzz/corpus/keymint-reqs-82183284-3 | 2 + .../fuzz/corpus/keymint-reqs-82183386-0 | Bin 0 -> 86 bytes .../fuzz/corpus/keymint-reqs-82183386-1 | 1 + .../fuzz/corpus/keymint-reqs-82183386-2 | Bin 0 -> 86 bytes .../fuzz/corpus/keymint-reqs-82183386-3 | Bin 0 -> 90 bytes .../fuzz/corpus/keymint-reqs-82183481-0 | 1 + .../fuzz/corpus/keymint-reqs-82183481-1 | 1 + .../fuzz/corpus/keymint-reqs-82183481-2 | 1 + .../fuzz/corpus/keymint-reqs-82183481-3 | 1 + .../fuzz/corpus/keymint-reqs-82184180-0 | 1 + .../fuzz/corpus/keymint-reqs-82184281-0 | 1 + .../fuzz/corpus/keymint-rsps-00035504-0 | Bin 0 -> 1975 bytes .../fuzz/corpus/keymint-rsps-001e170d-0 | Bin 0 -> 1975 bytes .../fuzz/corpus/keymint-rsps-00303031-0 | Bin 0 -> 1975 bytes .../fuzz/corpus/keymint-rsps-00313563-0 | Bin 0 -> 1975 bytes .../fuzz/corpus/keymint-rsps-00333233-0 | Bin 0 -> 1975 bytes .../fuzz/corpus/keymint-rsps-00365a17-0 | Bin 0 -> 1975 bytes .../fuzz/corpus/keymint-rsps-003cc0cc-0 | Bin 0 -> 1975 bytes .../fuzz/corpus/keymint-rsps-003e7b1a-0 | Bin 0 -> 1975 bytes .../keymint/fuzz/corpus/keymint-rsps-0042-0 | Bin 0 -> 2 bytes .../fuzz/corpus/keymint-rsps-00646630-0 | Bin 0 -> 1975 bytes .../fuzz/corpus/keymint-rsps-00820081-0 | Bin 0 -> 361 bytes .../fuzz/corpus/keymint-rsps-00820081-1 | Bin 0 -> 1975 bytes .../fuzz/corpus/keymint-rsps-00820081-2 | Bin 0 -> 35 bytes .../fuzz/corpus/keymint-rsps-00820081-3 | Bin 0 -> 381 bytes .../fuzz/corpus/keymint-rsps-00822180-0 | Bin 0 -> 4 bytes .../fuzz/corpus/keymint-rsps-00822280-0 | Bin 0 -> 4 bytes .../fuzz/corpus/keymint-rsps-00822580-0 | Bin 0 -> 4 bytes .../fuzz/corpus/keymint-rsps-00822680-0 | Bin 0 -> 4 bytes .../fuzz/corpus/keymint-rsps-00822780-0 | Bin 0 -> 4 bytes .../fuzz/corpus/keymint-rsps-00822880-0 | Bin 0 -> 4 bytes .../fuzz/corpus/keymint-rsps-00822980-0 | Bin 0 -> 4 bytes .../fuzz/corpus/keymint-rsps-00822a80-0 | Bin 0 -> 4 bytes .../fuzz/corpus/keymint-rsps-00822b80-0 | Bin 0 -> 4 bytes .../fuzz/corpus/keymint-rsps-00822c80-0 | Bin 0 -> 4 bytes .../fuzz/corpus/keymint-rsps-00823080-0 | Bin 0 -> 4 bytes .../fuzz/corpus/keymint-rsps-00823480-0 | Bin 0 -> 4 bytes .../fuzz/corpus/keymint-rsps-00823819-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-0082381d-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-0082381e-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-00823820-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-00823825-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-00823827-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-0082382b-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-00823833-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-00823836-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-00823837-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-00823838-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-00823839-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-0082383a-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-0082383e-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-00823840-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-00823841-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-00823846-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-0082384d-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-0082384e-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-0082384f-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-00823850-0 | Bin 0 -> 5 bytes .../fuzz/corpus/keymint-rsps-00823903-0 | Bin 0 -> 6 bytes .../fuzz/corpus/keymint-rsps-009a81fa-0 | Bin 0 -> 1975 bytes .../fuzz/corpus/keymint-rsps-00b5ae79-0 | Bin 0 -> 1975 bytes .../fuzz/corpus/keymint-rsps-01820081-0 | Bin 0 -> 1975 bytes .../fuzz/corpus/keymint-rsps-01820081-1 | Bin 0 -> 1975 bytes .../fuzz/corpus/keymint-rsps-01820081-2 | Bin 0 -> 1975 bytes .../fuzz/corpus/keymint-rsps-01820081-3 | Bin 0 -> 1975 bytes 173 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 trusty/keymint/fuzz/Android.bp create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-821180-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82128140-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82128143-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82128158-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82128158-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138285-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138285-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138285-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138285-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138286-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138286-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138286-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138286-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138287-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138287-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138287-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138287-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138288-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138288-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138288-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138288-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138289-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138289-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138289-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138289-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828a-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828a-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828a-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828a-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828b-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828b-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828b-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828b-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828c-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828c-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828c-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828c-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828d-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828d-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828d-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828d-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828e-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828e-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828e-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828e-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828f-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828f-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828f-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8213828f-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138290-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138290-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82138292-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148485-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148485-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148485-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148485-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148486-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148486-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148486-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148486-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148487-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148487-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148487-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148487-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148488-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148488-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148488-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148488-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148489-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148489-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148489-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82148489-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8214848a-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8214848a-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8214848a-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8214848a-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-8214848b-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82158659-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82158659-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82158659-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82158659-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82168258-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82168258-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82178158-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82178158-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82178158-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82178158-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82178159-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82178159-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82178159-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82178159-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82181a84-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82181a84-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82181a84-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82181a84-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82181e83-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82181e83-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82181e83-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82181e83-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183184-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183184-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183184-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183184-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183284-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183284-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183284-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183284-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183386-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183386-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183386-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183386-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183481-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183481-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183481-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82183481-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82184180-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-reqs-82184281-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00035504-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-001e170d-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00303031-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00313563-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00333233-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00365a17-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-003cc0cc-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-003e7b1a-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-0042-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00646630-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00820081-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00820081-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00820081-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00820081-3 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00822180-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00822280-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00822580-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00822680-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00822780-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00822880-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00822980-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00822a80-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00822b80-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00822c80-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823080-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823480-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823819-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-0082381d-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-0082381e-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823820-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823825-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823827-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-0082382b-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823833-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823836-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823837-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823838-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823839-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-0082383a-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-0082383e-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823840-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823841-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823846-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-0082384d-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-0082384e-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-0082384f-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823850-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00823903-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-009a81fa-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-00b5ae79-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-01820081-0 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-01820081-1 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-01820081-2 create mode 100644 trusty/keymint/fuzz/corpus/keymint-rsps-01820081-3 diff --git a/trusty/keymaster/fuzz/Android.bp b/trusty/keymaster/fuzz/Android.bp index 5f24bc62083e..b10f7270fd2b 100644 --- a/trusty/keymaster/fuzz/Android.bp +++ b/trusty/keymaster/fuzz/Android.bp @@ -26,7 +26,9 @@ cc_fuzz { "-DTRUSTY_APP_FILENAME=\"keymaster.syms.elf\"", ], fuzz_config: { - cc: ["trong@google.com"], + cc: ["trong@google.com", "drysdale@google.com"], + componentid: 1084733, + hotlists: ["4271696"], }, // The initial corpus for this fuzzer was derived by dumping messages from diff --git a/trusty/keymint/fuzz/Android.bp b/trusty/keymint/fuzz/Android.bp new file mode 100644 index 000000000000..de73db720192 --- /dev/null +++ b/trusty/keymint/fuzz/Android.bp @@ -0,0 +1,37 @@ +// 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. + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_fuzz { + name: "trusty_keymint_fuzzer", + defaults: ["trusty_fuzzer_defaults"], + srcs: [":trusty_tipc_fuzzer"], + cflags: [ + "-DTRUSTY_APP_PORT=\"com.android.trusty.keymint\"", + "-DTRUSTY_APP_UUID=\"5f902ace-5e5c-4cd8-ae54-87b88c22ddaf\"", + "-DTRUSTY_APP_FILENAME=\"keymint_app.syms.elf\"", + ], + fuzz_config: { + cc: ["drysdale@google.com"], + componentid: 1084733, + hotlists: ["4271696"], + }, + + // The initial corpus for this fuzzer was derived by dumping messages from + // the HAL service while running the VTS tests for KeyMint. + corpus: ["corpus/*"], +} diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-821180-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-821180-0 new file mode 100644 index 000000000000..18fce253f004 --- /dev/null +++ b/trusty/keymint/fuzz/corpus/keymint-reqs-821180-0 @@ -0,0 +1 @@ +�� \ No newline at end of file diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82128140-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82128140-0 new file mode 100644 index 000000000000..906f64003e64 --- /dev/null +++ b/trusty/keymint/fuzz/corpus/keymint-reqs-82128140-0 @@ -0,0 +1 @@ +��@ \ No newline at end of file diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82128143-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82128143-0 new file mode 100644 index 000000000000..d629eaaee925 --- /dev/null +++ b/trusty/keymint/fuzz/corpus/keymint-reqs-82128143-0 @@ -0,0 +1 @@ +��Cfoo \ No newline at end of file diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82128158-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82128158-0 new file mode 100644 index 000000000000..3aa32ab1b0e2 --- /dev/null +++ b/trusty/keymint/fuzz/corpus/keymint-reqs-82128158-0 @@ -0,0 +1 @@ +��X@T�d�����%r����1:���z���7�X��$����v`�4����rc���J!Rq��3?ZD \ No newline at end of file diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82128158-1 b/trusty/keymint/fuzz/corpus/keymint-reqs-82128158-1 new file mode 100644 index 000000000000..1937534e124b --- /dev/null +++ b/trusty/keymint/fuzz/corpus/keymint-reqs-82128158-1 @@ -0,0 +1,2 @@ +��X@�v�E)Y�0j�Iê„»: �3=E9yO;QOA%pVxQ)JJIshG*rM&6R% literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82138285-3 b/trusty/keymint/fuzz/corpus/keymint-reqs-82138285-3 new file mode 100644 index 0000000000000000000000000000000000000000..1e2767336b38b950c0b61faa7465a84dd5aa5974 GIT binary patch literal 48 xcmZn?Zfb3k5@29pVg^%OEKO1h3=E9yO;QOA%pVxQ)JJIshG*rM4T%5% literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82138286-3 b/trusty/keymint/fuzz/corpus/keymint-reqs-82138286-3 new file mode 100644 index 0000000000000000000000000000000000000000..aef020a70abdb8cdddff75bac5ec4f47f196ac80 GIT binary patch literal 55 zcmZn?Zfa|i5@29pVg^%O3{6rB3=E9yO;QOA%pZU}AoWq2f#F&CCHWf?5J{#606sYk AKmY&$ literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82138287-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82138287-0 new file mode 100644 index 0000000000000000000000000000000000000000..1036580a4bb77d61fcf9b643f0e3a63dab9012f0 GIT binary patch literal 68 zcmZn?Zfb9m5@29pVr-H!U|?XDixO#lD@ literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82138287-3 b/trusty/keymint/fuzz/corpus/keymint-reqs-82138287-3 new file mode 100644 index 0000000000000000000000000000000000000000..32224ee1b0e7b4eaf0ab0d69dcde07f191410dd5 GIT binary patch literal 67 zcmZn?Zfb9mGGJg}mSkjTk`iEGV3KHPl2Tw`U}OSQtSn$@4zP3q1LOCvO;QOAOnaq) MDmqkT&a*ZE0G7@TEC2ui literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82138288-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82138288-0 new file mode 100644 index 0000000000000000000000000000000000000000..0d3285a5be0a5b8971998bb87391821aece0b08d GIT binary patch literal 1481 zcmV;)1vdJE6M~3>8V~>g0t12?5C8xQ0fHJJ00033f*K$I009Gn8gKvs_w|B0Z~y%| zLtSp`{w0EK~q0f~Yd5C8xI0fHJJ00038 zf*LRY00S8a0D>A&0077u00962f*KG20=@u(8ZZC?!5RPpBH)4=FaQF=8UOBr@}~5C`!M!lP-8p)xX`DU|AIsYm15N$DC{ zQ&0f_000310000000000007W~L!ki!pjiaJLjw$Qo{h&FMP1OtDhCBr$N0+xLj5Am znX|`w#OjPFj?$T@+kJpLd+Bv5BDCrV#S>;{VnVKz{;p3F|5Q0Ndg3oEm_DC#vPJCQ zI+@E>zkwSb^}07c7)&e$kV#fyv@1TKylGc=U=J>QaNaXru=w4-f7bhM_XD^bZXM!{ zO`~m&CGl=*%op6Ml3K|ivoo@Eb$yK%&@NA`1s!W#vcL1_U9_h1msvgh9Ip+$bF#j( z04=DW$>$mR{|bgAs;H%5A+A7xpuJP9o_;9;ryC_R6u-u+VlU2JHW9fU!7jV{R9vc~ ziJIsR(a9`Hk&j+&Ds}E6?toN=H!6^@MRL{bWRvpnC_t=dlY_l$Oud`PU1S9_Wy9*`YoF_KQUx^_$F;#R&%2D~IP6pUCZIQ1uiNA76%?4Vp6c9ky)D zKQFWVX;Rg(yq)S7qK@Kn3Zsd(5QlKQIxF;a0fSKU0|qexbHa}Ec$nty%>j1hyTJ|^ zKgS>>tYX29#wSk3!icojKxNM@(l>O<9QXyLhXhE-GpKjN0gYd?@zSR?@I;>c;H%Ge zqSWXm9RHaG^8e@gvKvDLE1gkn5Yb3KJ)!T<48cppW#F~?=B{b`n0(&um;RPIny75U zf%p1_W2kt~hQNlbhTT+wxeUIhpQ*b+Tu?A2Tr@}R3npzP{sTe&N;}=s`uhA1tS=K7 z1xtxBxvVwMq5_#?AA=iyW>KqGY@U&`G?$jcn`Pa6<8Li&CAoh6C6_|}xHw{{hl#Y@ z>w2g6=!@nOY(~+LT4eFCC>{?#kDu?McA^zuBzOIXi%TuE)%=1;=-u}rAr8ca*~#p& zz&=nsAXmiLppWcd&Z>=BEP|41^J%4M4?isOo`T5+oM@Bs4;Xj9##$4fx(17J41G5U zhrZa0NTq1*JQ4N);dG9TCkX7^JiN)CEZF7eO;WF<)a^p5;@AodyQ~1uI}2Bd=V$gq zmkx`cBK;EYIiX?HL;{WwClgtfa1bLJEZfTxse)x!-ri9!0`ZtR;kE#wX7pFwNx;3q zK0>%>pNLmA!{ZJmHK0=BJ_gb@f5^DEb?cFHumc}sS?~c*$en=@1q$xO1#7v0fLI|g jA2A&;8wLYa1Op5dL2hJnZ)s#8OJ#X;bZ>HHAWLO=KRK+Y literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82138288-1 b/trusty/keymint/fuzz/corpus/keymint-reqs-82138288-1 new file mode 100644 index 0000000000000000000000000000000000000000..73a0a5b9d4cdf7b8d3f7f8e6de752567729c1f05 GIT binary patch literal 75 zcmZn?Zt7@~5@29pVr-H!U|?XDU3 M$@w77j6WC~0O(*4V*mgE literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82138289-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82138289-0 new file mode 100644 index 0000000000000000000000000000000000000000..668b59cae74e2c31be8ae8703fd28418d47e1cc1 GIT binary patch literal 80 zcmZn?Zt853GGJg}mS|{_5@29pl2B-pQea?UWPnhNU|9}{1TdEcD$52GE?{8%{)Q&wLS7v)|( zS>dNa03!p?Y#@e#3(d|88JQPEH2qMn`yn$`we4}iwy<5xn&-DJx?bOuvQPGSSedPN z)vAEq)rC_7)_O)X&23sXPL@>62D++W?eopJuP zvz+TE<)2+qa>1!fq5p*ZrYVz>s?K-$%m0yWFk)TGTt8dk(u?GE7u>c!KJe+)7lGg_ qGH2`>8X^=80Uwo9~*oQnAKY}bRe%?-Sp z0~i^Ajs{{FxX|ppkdb*o#Ki2Ti}qo1E#}G6eh2?fQI>nN=*R8-O1ceK3l2cxv(x_YWZi8(+{TwyzMPeN_krKX zlP5eD3f~gU@7b<>b<^wgnqM)`UPi=<&#HJ@r?>JSzeZc;trwHdsP4=1`10qVy24h6 z42Sw~hbqRM|Ehmwt?c{Q&=8?$Aa5vZAkD@c%EHVe;+U6Gl%JWR;GJ4oT#{du3Ss~N DhoPAt literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82138289-3 b/trusty/keymint/fuzz/corpus/keymint-reqs-82138289-3 new file mode 100644 index 0000000000000000000000000000000000000000..0a51e0153451fad6ce6c6e653a194548a360de8b GIT binary patch literal 1494 zcmZvVc{G#@7>B=a#tb3Gk~EWyEtGvL5*Z4)m5Qe6C?U&a%@WBrpPLEIV3H*@V@74k zk!6xCdzMmDb8KB(Q3zqkl7_i*&pr2_`=0Zj-*et`-scC&K#33<1pqJ*LhAtle3u9S zp&bFB0}X({<_!w~Anc!jL+Bs?Tv>w50tM@4*6wb>5c)CzpWl4g3?2pm#>2Ua{qm%E z0)hYmw@489pZm8*`2Q?62+t)5HCV&NgXxrZ z%+ZVQTlNVfoZ4642;tV1-)2{|N48Gg(V%j(^9Q2i4&D3~wojQoCGtwf%iA4SlD<)L zN?PD#Y7{xDtCeNJ2q`~0Gh&wg=3D~_vuCO1fQ9@YT8LEpb8hVY7P)mqeE4Naov5H; z!;7V>Lk+RLzXDd^Rl5TeMky!q{HbcZfU8|Q2a9MIIhxxmoZLbR{ude{K3mBafyVeAv393Z}kKL3?j>P4@JX=hU(S+q=)C^@C z+Mc@WzPo55RjtsZQ@iHmQk0i?e^TN@rzIX z75!SPQTakFY6ttZscdxJPn@P#dJ8?96C;RB3Z7PvI5$xy=A53v>HXO!mcC~)_1Z_K z1+bhN#!_NoDb7@t&byM>GLM@zGSw2V8#}0O_ez6?v+y@eh)0~u`fjLbde!vUAe~p2 zYI}6($m4WYww0JK<#eUL+J@}gPo9utbbR-6 zT#}VmbWM1${l3AnLZx4qrEUeEc&4YU?%~u<7IidOG%v9dMGmSn+y5gJjCWjwBlW?M zX6j-@*7)pO@cP%dYoYxQPy3-h*jXNC&T+(>99lg;JzpCy zA^ysW8lKJE$S}KK;MYQ0S-a&?5Wz`kOejtmaw1iW*FRwt)>^qZ>Z!RH*?t$>>#w!} zx7s*hL+XVqyi$!ll9nlqIp%fN4p-Iib#k(UHoJ!p z*-Z|uC@D#_-ul=%Q`TtVXpY6V_UER|xV|f*5VRoL)kWfCA4yBC1v=D;eBg6;K~g@v zq3wbUqXwCLO+5O52)VvL+3vB=thv-O@Hv!9Q5TsRG_UKVYxRGfIC19LqwepxqS1a) z@!Dd5b4U!IIN`l)ohgybP+pgwGiADU+rX$Obs56FAe0JPYv7G^A>@f49zLxL<7JtC zt^}A~Kk$S0jW3%la8=%n+j!%aF$p!}+%uyVNUlk2N7ak4>9mkixS|JP9z50Ykc2{r s&bA_atK;I%E9oifE9ha6aAzU7xU5ycmEb_)6|95jjgZj5V9($1Hx(|fuK)l5 literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-8213828a-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-8213828a-0 new file mode 100644 index 0000000000000000000000000000000000000000..be73ca346d0fac1d255b352cdd5bcfcd86dcbaca GIT binary patch literal 466 zcmZn?Zt7~15@29pVg^%Oj7?Gs3=E9yO;-8;|5`hz<>!N0R?bO@MNL-q|NjU&^O!P% z#Qq3Gs2V66DjLYMF^94+^GLWRD00Ze_AW?*<$eo6j@L}PO#qe>G)Yhx2*Cw7OxbPF&r?E~sIU|>2Z#lWQW0L(lj z#lS4)1ZJL-Vl>%!7R)>kW=1G*RlapoRlb?taD;1v*_SYODf`FY*6g@>YK3+C9oH(6 zZ2^o7K)(Vp3|we-UdYJ2AY!7#!B(eE4WBO8R}XJb?=$&w>?QNmdwZpJafaI7H@>_x zWdW;4Ubpwl7e}sTdI&r`wf@}O`5HRs`q&wRFTc9_R>ZI6mzB=me!jgkOQY{P^I5rz zc{N6<6zaR$dCC3wu_s=0*P)(;*FRjT6?cp+)7`q};HvnkMl&_uWQI)gy|Hh7g2Hh@ Z25W^H`Xqb5G6$Y$oXdo`M4FSY}rCtC4 literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-8213828a-1 b/trusty/keymint/fuzz/corpus/keymint-reqs-8213828a-1 new file mode 100644 index 0000000000000000000000000000000000000000..625ce230e9d968c93dbb1a2b9a35d6395a66e216 GIT binary patch literal 1504 zcmXwz3p~>c6vzJ?%MxSF#9uP56cwAMJe$|bBacEJk;j_XFd-VPyUpv89+WZ~GKE4> zE$Ncvb-QHp$SW*_ix849SGxCnKIilMp5Hm=a}Eo|N@ju5000%)6mbX(!~g&U`b##< zPyn*D$kL~-uNj#6QmLDyZ|372#sa+nXqCdoFimb*mhrO`nFTgwZo~Z?^7dCdw%O+UJ*Zn7DXu$yt9SdLx7DRH}e1B z$C}-Rh~&D8R@Ir#EN=gI#)rRy z3L!p(WkV4D5LHrKQhUZmCv-3L)(!S09@saFAamOTe~5PkkFK|=IIwA{h5UO6odn(5 zhwVZB1NGMn2({X5P&A9~MA1;w3Tk-TK|gP))Gu_nGK(xEl`~FRf3c6qZb)qMkWk;wpKr~x+|PC|jA=9T8wLgGPFt)D=3cx< zj$!mr>&uYNN0f__XG)J7zbV!BP_!;=Qch@VCGWExpvh@ydY!XFa7++6Tq$KIi^j_6 zX@4F5r3 z^iCDTF9}Y>-3%ee$RBhLcFmOtxU)wybnxX+wFA#pB9H6kAJ4#4@0lHV+ZQILv1Jh6xJuGabvnXMIGf+vww!} zWQ5&X%j~ztRWnwg^=tc`HcO`Gdtkwb-bO*dix~cd{qA&ed>i zo*oEYBBf@K^P{pd996?_AOjfj7lvJ<4ye47Wg zw@}HQO1^#XE_aDhJ*Qhr2uUW<+l7ITiUl)%s>F7qxF4;N!as0~`;2P%wjgV~)rk(z z<^_#bzRhGiI{kF;z9VV?+i*6y*txpMTxh$8mOX;1vB>t^W3PZPfKOza)TFA9NfANS z`ENX!>}-F(iePsZo!Qk=!Be%)`LJ)1V-r-Qr*B%N(|0Y(-zZnsEe+ZqqPEh?G=iA^9a%pZWm)t@w(Z!le!-Qy9XPet0T?kp3+Y|~# ztlJ?;I2|&%luK9$$2}ysIdYzJ{yOjTywCUZywCG~KP(h0kp;>C02IOku>c^l0}il2 zdjMzz0SK^h!vFvT`cH_kz#ss!xWLk+L1w>{xUN>S^0RX;+ ze^B})&y041xv+p(CJU1ApXFzx`2Wjf0BH3_2Nr<71_7wbz$Vs$fQX#wCcXzD__F3r zY}rIt%u8z$A0?6H2d>2UpDFK@s=c(OKd*=%N(-ly2;SSm?IFO1Z)5)*ezaLGL?p*e zw5rZ@dP&S5o0vH90f{O)`nKWK;~}v8s%}cI=fMoqNf%BXSLzxI$GQZkC8t z{np0B5m7@G=3v!33)n3EFQEqyvqtKwsc~%;4c5cyTPP4ygNj2)V;Y4A@jdzF-9xVV z=p|j@D(2o5$v2cFppQ1-hyNq46NTaM5gGvoS`{V_u=(1E*9{r4(ZL^}LZBC6$qZ|Fkbe)M8>d(Mu+87M@9oV3 zLah!P6unD#rf8~Z``1^r(=S;n^$H!Y%^(X&<&2ZoQ}&@*_3@3Kk{Y|0rP-S8?Qg78 zw;hLQgevXnypM45OVo?eerS*G7`W%~=&+!^Vz4w*wr+TMtiVei%h_l5K;`1G)(?Mb z%(E(Su`l{v1xM!5em58x?oLYH;n`A7rYCXqiS(ZG)mz=K6EcF6vZm#tk@>FY*3FZe zhX#$kZC=Gteod=F|DrkGj(ryUbW5J)KDI|;WUHCaASg(47PB&#ef|MCf;o&@UxIWz zqC`oZEMEa{`8{YSBRGBSPOmkt zny~_X%XZZCE@zVaP{1xygBy}^;KaNaJ&63wG!voFn=iEEc<3%=6ogcCQE4@JCi0G+ z`Tkcojuv>uUDz`DtTZy*@$6Jt-U?E6?m#h6Ek5ijzQD=mo#+avb2A*7qhEk7l9DsX z`QdjnoK!>7k!531d6L~DcjA4tqzY*rmc$xT({w7HbI51arg*iEmyBaqpE#k3i7!kC z-OCx}kqoPmPIsr{2U;)Z7$Z`sw5Z9kX<6lt#vLlSA&IF8J3$J~yQyDCj7siM^6q(m zwNspWX0o}2kYEzAO?cr^v0&OqmDpw!v)mFU{0+yr&!~oP^|!`bIkcZ?n%8XM+l;rN z(@q8KJ)#D%4QCRIU8;-Bg|_OntRYm5Mb;U0dj*66eC&=%O|r&_G!ayt`_6;O&Gh!F z2zKA4Gdr7~@l>s|Kki-N*!UM6);F!v?YR-|Ym_7Bo&xO+R9k6b8o^d0vxz-Birbh& vNhR`SIWh(+WekR^GFAzvh*c01aTXPklr;%FA58T-kFh4xLPDv*!N0R?bO@MNL-q|NjU&^O!P# z#Qq3Gs2V66DjLYMF^94+^GLWRD00Ze_AW?*<$eo6j@L<0aHg(YG6Nf2O0!y9le$RM0Xmh0tBJEK^t2f z)r!E;OTzGxBFkOZO!Q304dTa86zma#@-qOfB*3eNf@DyJ)ioPC^y7>%1*tg`w{zRQ zLk$$k;3<2G%T&TyNUYb77fhXrT|p*dwQ|1qKLnd4^B*Ikdk6cegu6YkIjFhoO1tE5 zxs44Kg~d5i8*kpamDX8_)q70(1Q5Mh6Z(;XI_4lo6iTjV0}!PKx;Y!I%E)_kq41Iz z^sC#8h0`@OHu-8b?7W`(_p38PiLT$xyo{4tO>!a-a+NBhqXtJGsuFR0dGbtEw37ii z@!W;8db83zPByYS@eWoHYr%H)*gqLj40oW+HGhsD>oIf5DRWB1%M8v~Xzi^dl4D&s z~oGpfxos3c-M z2Ia86l)9`pTW_(s7$H{ZJVzc%X=5Z@V{7nS|7-~nrN9>#DULzeq+{l`jLd05vG>=@ zW#nWJnWz5#HXlAlgelKD!R%&BzzNSq?d_CJ<50O;E@aq%>rMT*4zjpd3ZSjq5O9@1 zJ89yLc=oDIp>^$i{A510!$+R8%0F@x7fm~9Beb?#>NQPjW(8cV)keKP_f}ir%yHq$ z%7j6x!KGmFs;44J!w+3Lny#$nLo?FFD!vli@eC(5I28{7n+oj@MDFD>F7#t(RHZSE z5~7e5-DIm?yGn(XAX5=qjelZdM=1+yW{u1^+5sNS8!vQTQ!i#_sd9g$@eRKj<9xk3 z{WNik^)qkjy&Zu~pmY#ZUCie4jyjH)BRAtkjM2!Rk5#D%WQ!x z2hX|(YZBc{1oZNVQk~;n>fOgeBs2MvUnk=o1o$L}&z*D~Ia5ZB%$;!mG_u|4geNi4 zN%sgd?nPoP$Q${SRcEs_g zY;mI|)eU5N(gH;~J0I~Ff(%})uUwXf(Gq8r-gb&{rOt<<@)4w$ zh0~W(6@8Is-5^@#Yh3DOH2fTXUvcNW=snudbp9g`a|L58n>*E{!uio$*S^dr2g&Xf z87-?!ZnY>CBz8GxH`yegpm;4{EN^hHOHFBI9|)$eTps8>4KE9(TT2&fUH1>o#^eb| z1Y~;ZKLI?Cuk5@Smla-Fo}1U6M6=F>wy;5>>GW{iPQssSw&q%rK;9PBIjD#D-u literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-8213828b-2 b/trusty/keymint/fuzz/corpus/keymint-reqs-8213828b-2 new file mode 100644 index 0000000000000000000000000000000000000000..1c07c9ff7ca6f04a885d79775acb31d561c18207 GIT binary patch literal 130 zcmZn?Zt8B55@29pVr-H!U|?XD$bpQYW literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-8213828b-3 b/trusty/keymint/fuzz/corpus/keymint-reqs-8213828b-3 new file mode 100644 index 0000000000000000000000000000000000000000..03094b324e8b75b4ec3ca9ab6be37551145d7408 GIT binary patch literal 1553 zcma)+c{J1u6vuxvCQAq}!q{enkY$i{G&wV3bP_SeWK?6wlEx@XFEaD971cvyuV)K| zv6N#cOQR+{<0)fH%97NH8ChcRJe~LcdVjoo&OP^Y?mg#zzxSUD?gf)TxGVrbAs`$D z03yob00?&lfLCw;0&MpX000pKZ9=v-(6|dBAvhZwckFDrf$l z2xUDrQ3w-tl&Yx6DVT_q0y!+q?@AcrqTh7{C4d}A4W#-b%s}{gKxAQCX1nlJ0AS|Y zpBh6-j2PlBZxD!MfRMz09sN}QPh&sTx2;24w^yM6XgeH$YEJB62OJRDhuy(H;E+Sr zy*t>qgPsWeaH)?k5^nEtnNBLeoR8Rxi`N!SO!0MptDXL-YU6pXD+Jg+dOQCKZVWCT zB9cdhH8`hpDZ1OcXf&K>dXvCE#;c;?B@w|uVe@>W8s z@%7h{@i>R9TDV|rULm}$q%2cK@x8Tx;T66)n^)^)%2T*c;@T>GF*J9;)%d7y z2&b*{`ts3TwygO_I#$(eFLm9GOhW2O#Xy`K_Uk&!w4<1(-7!5wT&h6f6bR%wKhB|R zyoJLEN`?NGG>)t5Xj1TfcE71j2wrg5D@!ID)~|olODp= zC42m>6^4YwyzpIpM_Ddu(bARGKB%hJ%vi~*c2O(;d=qN?R%=+PU6QyF@OasLmX+oY(pE|5 zhppwUtTgx2QaO&Vaw;Y%RR3xMXKs^?cViGOY;vAsEHduhxZ{bW>xs3^OOUvvjA8}B z=u>o2Kb4xIYBxkttmJ&(>+dX?9~;DTnlucl+O`?p$xP~# z7NjEhQK`mrO!P=G-rInUbxgCY%>objp#y4OkjbkJo8g`S^vAtI3wTJd(6r|OazgYo zMTWLpF>x4QiZAuMygR0`NMAvmUGo476VRvjJPj%#jH|hP>ZA!|O~IsrZ;67#SUjgMxiJ3x_OA6e2*MkTj@yB-vcXbU(IoObf*rDje3Y4+O05XZnEzx;;TjI>&*nZ-ai zKEe1>pR!Vxj9E@ztB(k`LO+P4KcXBOIhxDAFppf#aP!xpFs8riY4(*BETZePmarQA zZb{hY!^bg$>d`7oG1qO}pzwFXw+lxt6_!@3Tat{P}*ilPVu zD!1vhOY#bJYJuH_n0uK)l5 literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-8213828c-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-8213828c-0 new file mode 100644 index 0000000000000000000000000000000000000000..3fda800bf66ae5e8c917e276e48919b98a679c1d GIT binary patch literal 137 zcmZn?Zt7{05@29pVr-H!U|?XDjD*-O`i^Ht*w2*C%t!=)lIwFLOdEYcIJ#drAC?@TLG3B7c=2e_hA(!s~I1z@aae zUJayvC2@|5y5}L>rQ9i)uA}q0$oHnBS}jV8jJaj2Zvon}4r^G29LSeW9gl34b_G9yV*nAzt%Z3ct`0zJSG1QN+ zWCFtPqe_ZPYERhdhwXx<-{4&2gMG6IGOzvgcd3q$(Y01pXAUj7P;dvKA8$~5zdbl` z;Pv$aLai$HS$Wa&@Dl69s+>SneK&d#Yy+ zx3>MIInR26i>n-T7ao{L2VG-ecsnS0hM!Bhncl?lM_YE4uiWT;c_|}2DQiYP7MbsU za?LWSd1Tnk-|hvQ@>^OJ`d6*V4s1o-(@lBSdpKT&F|7v!hCyMPtAvg5=VxumF^nN< zZ3)u(fO0|RMClQ;SEah%O16cKD)Fr?O0deg2&o3mq#fM z!tCg)mE@~0!$g+tGdD6XOw-N%hWeRDX*2Ef8(@ZL!yFXyXu6U)6pN!*FA3dst zNhnMQJD*udadVj%n&J5+J)(f899~C#_g)O5vfm84#E_gf776@1eM&W z?BDnHa+f64XS%tBaLN4qR?+DP#lo2YHDbFd`+G~2=yx3BE~6U0IoK9&?yHyuiitIILStF<#t1KT4M@57&eBzdQO|s_L79yxN_mvNm zpY88g74E!EXLdDL@YQUy-|b%D+65OG8d+57_g#w)G|iFsOo8@?sxP-NO<^lB*~Gr> z#qG?Iq!NX)99d)4G6ut41*?ox!YWFLxr&QP%bACs3a190!q}2&5s}nz@(=h2spzWJt?cDl?K@q?#q7!C0nTTQ@E;sBtqGOPVoaj1YfI8Ci0Xt;Lcp zB9W9anlvf9C@nWzVrpzP-AqweI=4^vJ?A~|?>ryg=lS%23g9^qjRXKF1Vm#20EUtV zK(r$Obf5tUu%f8}00jE;z(6zufPDT066oKTO-O!p`YI7f-p80A;q><PZm&CjgsYF_I~eZgj6=?<$hj_|slz z)xz4SFNTk2+^g>A=Omv^--39H(Hjgu&_nhaa)baYwk!MJ^u?2kAh0X$aITK}j8JiD zWMYt)%G~o@VyQRP^FBi9c9DQ@ljtwJ@9+w%H z2d>r!94`oPNMO#eO~tnZ)v#h@e9UC^Fyct|j>h4P7gv}26rhf`?NECG^0BdUE8YQm z>4;oo59{e2YrfMNOAz z5)k8|Zx+9tf(D9C`79oBr_MB+McHr4+2_W|^q-t6emy2tnf6TY>5?&N@}1YW=dB?z zhc?*TPDr?Eu>hw2{YNJ|l#@l=l}jPX;jraIlu~*|7`y`RnWW2+Z}%$~|J5PwcLyU& zuGg0XaBg_W!Eb{|P{*K*k}*R%X!q57b45#*tT@*=lSwG2;V9Ka;zHHboPSF>t2bzB z!a+Gbha8A)OEcr+h3j`Sqw@DL%+0Se0-OL7eEERHA^+k{3Xd!?Q0+ox*F&|ud=Ob$ ztif3pxuGswL^EysC*f;bhY`wKIJiID7K_-;jvAk}O!BJZ$F@AJbRiF*Wpi?e5QX`V9li!XepZiErw4}bEMGl1&KQ2Dbb9>o&vbfpwXq{ZoYx&@?yNX3^+p>9V-H=9aOnzPvYOVfW zik)Q0m$g?_P%^6WjzggL-?<-|@@VveFizczACY)@o^}_RvPr8$6r-1Jk0_Nw7H}+~ zT>%n}HrMs@-w+X9i3P#yZNsN< zBL?zEx}+N9aNGxiN`Z%S;Z%alCvI!ll9q}0`wYIt=}5_t=oJ}2I*rxrnF?7hzTXRO z`QE?(t&&A->8Y{?p^Dg}j7Z?ScByaGib>+BIS5_Zk4S7^2C)n-ux9|d`qt#7ir|wR zT7mnW)3dQHf~-ntH1jBt3+U)etD0g&G4R~;Xdlbe#wfz$T2s&GNf)E~*Rop5T+`@d zm)$2HCMZ}{N81V6O>f+694kG`%NZ{JRJ*>KF7YxhYJ*D$BW`(|Z&2Z?(-%X92)R;^ zD&@HD4^R6JZ=mbfuJclSQghBGrF!Uo^E>;EYYYl+e)b$O?D+yVT{ql*#?#Pb!1zM+ z`MFHp2W}6IPIMPohz?DcH{`LCpFu>$z1m!w&rEi+??tNdHaFr%<$02-*{P5|4gSdd aG5oH*v9V+&>}H%IR{m!x%l;~5HT=J_53#QR literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-8213828d-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-8213828d-0 new file mode 100644 index 0000000000000000000000000000000000000000..16388b32fc718fb5a958242e3ed8801f7b3cb71c GIT binary patch literal 140 zcmZn?Zt8845@29pVr-H!U|?XDvdaJe*V;8B zH76$@%(ik)%g=9;Dqvvz{*wQELdPEJ0U zZRMPn4`kK<|0C!mAOI5jBM>2BAZ93HAjHNT%EHXUot#=!qEK9#l%-(QB$dFx{DA>X UeUxTkcvgN%{)PnDdi}2r0H1*=J^%m! literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-8213828d-3 b/trusty/keymint/fuzz/corpus/keymint-reqs-8213828d-3 new file mode 100644 index 0000000000000000000000000000000000000000..b0bdc3ec865417bc73e254bbf54a7c6b5612c3eb GIT binary patch literal 139 zcmZn?Zt8845@29pVr-H!U|?XDM+fd~l$F+&jpAvWev7G@sq lM+fd~l$F+&jpAvWev7G@sq lM+fd~l$F+&jpAvWev7G@sq l^x#BM_lzAa5vZAkD@c%EBxx;+U6Gl%JWR;GJ4o zT#{du3SxjvV>tB{r2emUL`Fc6ze}idh^=L^L6U*Fnu}|gr?V@J=ji7WFa81nr4!ioT}#Q@8arXYh-4TW^SS8>*yEi=I9&}8sr*eYm{VWVVJDu z6a+ND*4)(6+}Hr*T&BH1*E4pg$g;c!TW=MSYLIMbYaq=cmYkofm!6-Wo|CGV2ywJt zdT|;PqmqFfcFEjgCKle4UE2(mSQI2nH+?KD-_yDD{%84lDa%ehYFui2@Z#0kvLf{l QPiXxD22}wA^P8^?0Q9PJr2qf` literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-8213828f-1 b/trusty/keymint/fuzz/corpus/keymint-reqs-8213828f-1 new file mode 100644 index 0000000000000000000000000000000000000000..dd1d192d0cdada61efabb631fae3ece625fb4faf GIT binary patch literal 370 zcmZn?Zt8E6GGJg}mSkjTk`iEGU}6SST#QXp3JeU4Okj$Ytx2kYf${s-CaDAl=8w`q zWww%6Y=Am|+z$**R`vh?2s$!0S>^x#BM_lzAa5vZAkD@c%EBxx;+U6Gl%JWR;GJ4o zT#{du3SxjvV>tB{r2emUL`Fc6ze}idh^=L^L6U*Fnu}|gr?V@J=ji7WFa8nW|C@PVxi{i@8arXYh-4TW)9>y`h~hVI){V?xdz!9C7D?mCaXCG z0S&MxXI+x!6EI%)0*{Mg3OKlHcygFM}r2gRv PtzW>PDqvuK^R)p0p|Nuy literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-8213828f-2 b/trusty/keymint/fuzz/corpus/keymint-reqs-8213828f-2 new file mode 100644 index 0000000000000000000000000000000000000000..c82d9a1868f943443a5831ed2676ed22a787dc33 GIT binary patch literal 286 zcmZn?Zt8E6GGJg}mSkjTk`iEGU}6SST#QXp3JeU4Okj$Ytx2kYf${s-CaDAl=8w`q zWww%6Y=Am|+z$**R`vh?2s$!0S>^x#BM_lzAa5vZAkD@c%EBxx;+U6Gl%JWR;GJ4o zT#{du3SxjvV>tB{r2emUsI$Lch^t>nypyM&i))Z=a*|m}qAAE|roBL$7&}yCb*#Zk zts+tlk_~MQq*=t0^K4%}|L&L9%qy r$HMYGolEb3mY^x#BM_lzAa5vZAkD@c%EBxx;+U6Gl%JWR;GJ4o zT#{du3SxjvV>tB{r2en9zhgi^yq}}5tF4(unu%E&$WW%eKsy*aRAj5RffZRrq#7g} z+8Ri+h$ZLe>ZRxBr{|>VB|?nWOD|4iVpKAa!!DUy%*4WbvTK{65{rUl>86i`<$F4p l-v2B=FJ;-OM~zEu4_>@FTUMn0;R&r@Ko1o#Fu(cQ007dPTc!X2 literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82138290-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82138290-0 new file mode 100644 index 0000000000000000000000000000000000000000..8865ca7a539fd259a49a29fa2ebdddd67b2c0402 GIT binary patch literal 131 zcmZn?Zko^}Rlvab{cDqy00RRPW0RBt0|T=p2Sbxo00YAbDF#LcpqK&!kcLnY9vc&w s#|q)GLV3&(K^6$b3ZdA*)M=oS1P100KvRI!M`;FzXXTgVZ%8x%0O;x%D*ylh literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82138290-1 b/trusty/keymint/fuzz/corpus/keymint-reqs-82138290-1 new file mode 100644 index 0000000000000000000000000000000000000000..36369f7339669d07e7c3762a17b42c758a64aec1 GIT binary patch literal 131 zcmZn?Zko^}rNF>&nh`=VK`3Sj#R8#NArxDaQ~?9y_peP-0t^gHKn(^A49t=o3{6r2 v3=Aiv7#JBKhA;v}fJQPxcx(_OS%GFHFfe}r$^og5(hLmG$}h>^kZ1q^OuHNl literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82138292-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82138292-0 new file mode 100644 index 0000000000000000000000000000000000000000..ffcffbf44af4e2a6c621068245663e3ce1b527d2 GIT binary patch literal 145 zcmZn?Zkp62Rlvab{cDqy00RRPW0RBt0|T=p2Sbxo00YAbDF#LcpqK&!10xfJVg^&J zKzX1bD@2YJBF74qV}Z!ALMS#c#RgHy22sKWluKY>{s1%uNPU!MV0c!3N&bdJ0|4b= B81w)D literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82148485-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82148485-0 new file mode 100644 index 0000000000000000000000000000000000000000..3741bdf895454e03ccf281b16fec1f478b696f3c GIT binary patch literal 83 zcmZn?X=!be5@29pVg^%O3{6rB3=E8HO;QOA%pZU}AoWq2f#F&CCHWf?%n=G1{0Cys i>a!UBRsXO)^S;{GN834_&15f4wy5)I>HV+k)Bpg4of`%K literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82148485-1 b/trusty/keymint/fuzz/corpus/keymint-reqs-82148485-1 new file mode 100644 index 0000000000000000000000000000000000000000..74f74cd3c180e5fb3cc066a7a03981fbbc7de614 GIT binary patch literal 59 zcmZn?X=!beDqvvz{o|RvczahaK op^(9UAoi?2i{W4O59>4Ut9^a6ozvM&_R?gFI-i!_|GG{M0EL1c1ONa4 literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82148486-2 b/trusty/keymint/fuzz/corpus/keymint-reqs-82148486-2 new file mode 100644 index 0000000000000000000000000000000000000000..939c47765398ff1faf83d2b096d52dbf0eecf462 GIT binary patch literal 106 zcmZn?X=!Vc5@29pVg^%OEKO1h3=E7+5DF-mz`*>00Ze_AW?*<$eo6j@1Y?AOfgTeh zg8?fWvvz78ixP`M2LFNBv-&KCf7L&%&%Cep_0e`tXEWJLlP&6eT6+KMIyC?Qo|RvczahaG zVPK%g#K>U4%Eqjnn#ZEVqL9IVAoi?2i{W4O59>4Ut9^a6ozvM&_R?gFI-i!_|GG{M E0KIx2`2YX_ literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82148487-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82148487-0 new file mode 100644 index 0000000000000000000000000000000000000000..4d4ed453b18264b9c4bd54de91e2da116c1b547f GIT binary patch literal 79 zcmZn?X=!hgDqvvz{Gn~9N;MWMJx?`(Ciq{Dtq zgH^NrF8`k*_mth~U%DZNX-0foW yv%cF?dw15Rts1+JuaXY@=(l?}_l0wcdydHDZD43VZ(Md!{)(sPgH00F{~7>40!ZQj literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82148488-2 b/trusty/keymint/fuzz/corpus/keymint-reqs-82148488-2 new file mode 100644 index 0000000000000000000000000000000000000000..e00aa32cc412b138c42e635566b3499e40fb29b5 GIT binary patch literal 107 zcmZn?Y3XQ^5@29pl2B-pQea?UWNeZ$U|`^oNC0zLpu%iG;Q|K6?_a@`K9EXaVA?AU yRNtW@v+F!_ghKk?!#a8IkGx2Jy#4>l>4y^6yIniq<=Xp{>#FUMmlMCRHvj;cdnBd+ literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82148488-3 b/trusty/keymint/fuzz/corpus/keymint-reqs-82148488-3 new file mode 100644 index 0000000000000000000000000000000000000000..1c414e4ef4fae48506954e9c55055e14e8b4918e GIT binary patch literal 706 zcmV;z0zLhL6oiO^8gKvs_w|ArAOHXX0)iSK00034f*KG200IGm8Xy1w1q6Z`AOHXc z1A-c000Zy&LNQUp zUoe6KTLJ+90)c@5#tBpj1bv1yfh}4gfp+9vLDmX&u{i3OZvLj6RuITo}d%sW9tmh;GkiPM33qOB6-DJ)> zwUI3L<1aa@7=u`^%*}v-0zm-ew4U`3c3nFp-QXI|s_`)L$7XP;8ey&ouSt7Kg1&9; zkImKN_qrVW9}JRfi1>_>zpE2}x*~-ldxOJ5|9n*fK>*#WwS$~Ye{1v97&0;N1+yBZ zivQiE$DT~iA%APhFx%y0)PQhoB1O>b=Y#Zt!N*#16xt6nAW2h=# zM-Qltzk)p70zeykS45iA4HXz9nqOACm?=$5YQZo3hLi-CrKN*leh^EO53?Tbnrv&>2zXP9%D@}QqvKemjB)#cd=!!(lCfNDfDK>z>% literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82148489-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82148489-0 new file mode 100644 index 0000000000000000000000000000000000000000..6ce48a5bb6f965fb3b8b54b427286cb2d51bc751 GIT binary patch literal 715 zcmV;+0yO=C6oiR_8V~>g0s(>=FaQ7p83X`=8c+ZL$OD2JAOHXX0)iSK00034f*K$I z00jVo8Xy1w1_6Q^U;qQ~0D>A|00Z$G008E9(jV9u0a*fhFoFVg0s#Op4F(A+hDe6@ z4FLfG1pows0$(tK0$TzB00M!50LBSa2?TwHG=VKzA%S+}TtU_fb+I`C@-!lB|L1m6 z99nm|k#7!s29vzb2C{I9P?fsc32Sw^_B?1Eh009Dl zfE(cOO`NVb7-=5^Q#de=kycApiJ$vWgwjS1W-ujw1+&hp0+%iNyw=WNZsJ&;ws{fl z53CmCIz&s1h8|Q(1(P;ca`?LTvMO?=HV x%%IR;hHY3i6uomK)$=w*=g0s(>=FaQ7p83+J^8c+ZL$Ql3v00Dv;AOHXX0)iSK00034 zf*K$I00jVo8Xy1w1_6Q^U;qQ~0D>A|00Z$G008E9(jV9u0a*fhFoFVg0s#Op4F(A+ zhDe6@4FLfG1pows0$(tK0$TzB00M!50LBSa2?TwHG=VKzA%S+}TtU_fb+I`C@-!lB z|L1m699nm|k#7!s29vzb2C{I9P?fsc32Sw^_B?1Eh z009DlfE(cOO`NVb7-=5^Q#de=kycApiJ$vWgwjS1W-ujw1+&hp0+%iNyw=WNZsJ&; zws{fl53CmCIz&s1h8|Q(1(P;ca`?LTvM zO?=HV%%IR;hHY3i6uomK)$=w*=C07??jWfT@qt z3=Gf8FUjAKV2tQ8Xl!RyRF6oiU`8Xy1w1_6Q^Z~y`K^@18;00Zyg z0s(>=FaQ7p83+J^8c+ZL$Ql3v00Dv;AOHXX0)iSK00034f*K$I00jU6Sp>l_f&{$+ z0RS)!1_>&LNQUrr!ay9qXGc{0)hbn0KU95D^}D)u_>RLYH(KQ3WjKbqlLr!w^W(bI1zd}S0v6w@ zR{&=YY*8lgmM_b2|1ggw1d(LS_iV!2W~benfu|J0fSqX=VKdU5gjSA;D{uSr8JpV_ zI6mSeKz|tnSn(05NmVMkXA~lR8`t)-4baPo`9^zjlR5J{|24CR3qN8YPC|yTl#ZiF zwIozaUzj-Zp5{ZadG7e96S5%JfN3Pn_bE_t#R3BX009Dm0RU<9ck^E_SWfVDH9XB6 zsh2q0J-mE>^Iwx@&KGU{8xvZw05CL4zhA!39Y$IG?;H=rFoR3szBv(<6L-5kRyr=J z%8yFf#EOjO{ZVRjTxKSQ$F#G+ntOv(6FzT~_mI_|uDLFR$)q!r0?gu%-vrFc`hDZ` zs3+9+_tTDOuxbF(fu$)$V#A(@^P^jKd9)GHx3wE}r$|H++-|nZ=dk$WM?Wr*5(%~25cxI)+W`WBfdJ?{378>CLF!MElkvBH zE}7=fFki1Vf;izO5>M*#>z5?5>U((R10zF%8i3_p9fxmhJ=zM_w0PW50OM*F+O%K!brN>T*Bx z{(qxr!7&?3P6YyifdJA#{J{0saa`UZ%Pq)mp+*xfqp)vb|0?xM^MrHtovqB{D_=~* zEzr7eP?JZrwXwB~Ir&~kn9RFF=sf`$to1VUS;}-gg&Cg$hG7mM376L~DHj)-$+mS^ zcQO*}mL7}FdOXMpyi|s%Zc7eo^OV_625Jcax3><0q))Q|Q^5j(fdH))+8n)VNh@ZB z8>qt;(~7qM;?LdLCZ<>bH50{4sue3R0v%?3AP0|74~o<0^ORk5sFCd&DC*Gu>g}8;KM&vN2){TaPZr}+=AP6S#}z-G!x-`r zgPdeN&x=jgeB!JzE|nLJU6n5evA=hpNfwezaP@+sKM^oa0;T6xTH-1-=TGd&w*ARJ zlA)t_1LV&RV|Y8zF1Hq^?7RA4YY?|h0aukG=kJ8sAH^amAqd$5!2*GRd2i!_U!BZ_ z-y+q9kOp0oiHgl-z=yu5+B##uMM<}n;>`{_;EdkApU)Q{+0DfV4RrJk?T!%w#UWCo z8)0SmI%guT&&)NXlhV9DIl6v=thPY2D_nLB;I{)`3ye4QK7 literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-8214848a-2 b/trusty/keymint/fuzz/corpus/keymint-reqs-8214848a-2 new file mode 100644 index 0000000000000000000000000000000000000000..8b735f45802478f15e44451d1fcd8f35217e1212 GIT binary patch literal 726 zcmV;{0xA816oiU`8gKvs_w|Ar5C8xI0fHJZ0009S1OS2>PyhhP8UO(R0fHJJ00033 zf*K$I009Gn8Xy1w1q6Z`AOHXc1A-c000Zy&LNQUpUoe6KTLJ+90)c@5#tBpj1bv1yfh}4gfp+9vLDmX& zu{i3OZvLj6RuITo} zd%sW9tmh;GkiPM33qOB6-DJ)>wUI3L<1aa@7=u`^%*}v-0zm-ew4U`3c3nFp-QXI| zs_`)L$7XP;8ey&ouSt7Kg1&9;kImKN_qrVW9}JRfi1>_>zpE2}x*~-ldxOJ5|9n*f zK>*#WwS$~Ye{1v97&0;N1+yBZivQiE$DT~iA%APhFx%y0)PQhoB z1O>b=Y#Zt!N*#16xt6nAW2h=#M-Qltzk)p70zeykS45iA4HXz9nqOACm?=$5YQZo3 zhLi-CrKN*leh^EO53?Tbnrv&>2zXP9%D@}QqvKemjB)#cd= I!!(lCfKqHV{{R30 literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-8214848a-3 b/trusty/keymint/fuzz/corpus/keymint-reqs-8214848a-3 new file mode 100644 index 0000000000000000000000000000000000000000..33148a1a6c62acecfa0b631d2ab7a47c80b345e5 GIT binary patch literal 1311 zcmV+)1>pLE6oiU`8V~>g0s(>=FaQ7p83+J^8c+ZL$Ql3v00Dv;AOHXX0D>AI00032 zf*K$I00jhs8Xy1w1_FW_AOHXX1%eu200Zyo`f&{(- z0RS)!1_>&LNQUrs4#*Aqyhl|0)hbn0ItJllO2fw&Q`Dne|>P_{AE8s zG|`m7{?z~&`$OB4dj{rns5db^REj5H5`&<~tTd<`SMF)e%5k{|l&6Gy>UKyUAHk7y=C%(*LaeYL`VTQ6Mf31AB-YW2?)#2_Tb9pC31Dvfkl z@r5Hyunqyzg7FWJ#&R7h?LSB}%%Z)IrYIrZRRRM6009Dm0RTf3N46yy2oWnD=Wm(w zaT-##V+mjcY%S*v;fUBX__(M{|W640eibeKt{<5F6NKG7- z=F(T2pen8k0FVqmzex@~EZ6Rh4j{!g*LomyLhFhW!z1R3r=EZJ|z75;I zB-{hC(#uReR1dJPQs6YA&}NviDCO}1s*wY)X}{{jLqJVJ;f_$)3}iEt5=$1VFCXgD;pv7CJ}re>owU+!6x$ zp!vNBFn|Zk9!`H)Fq3Ad-X-_L$+&=LdRJXe5~T43qjpC_XTV+yy!^9v%u1%jxgJ~aN6oL@VaRl4W8 zr?yRUsv0xX;Wws=7vHx(8P0U00^N)uQs?fdVD<-nP$*TP5_fmp|0LL zwz%ws9m!rlSC>)Zzu)3|=XjVum6KK>2O}tZ3jfTXa&Sb{j5j|UtKJ7B`WK}AO`wo0 Ve4Cr{d!`%atpeZO+K*0XB7i;MQRe^v literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-8214848b-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-8214848b-0 new file mode 100644 index 0000000000000000000000000000000000000000..a43a7fcb7c065ab7909521b7b2359bb65145c7f1 GIT binary patch literal 1317 zcmV+=1={+86oiX{8gKvs_w|Ar5C8xI0fHJZ0009S2mpc_PyhhP8UO(R0fHJJ00033 zf*K$I009Gn8Xy1w0SAH_AOHXb1cDkM000I9f*N1|1MmQX8ejke@f!dD=6BK`*cbs> z1i>(Z1iblzPvOmR@6hWDW95Z za8~FFiGDGJcBP?!Ddsya*Eyyak<&T#jmKlz(Mb{V?d&)`?h*Den?z9#dOppYdAW0f z7n2NI3*B@0A~(tQ6}(~FUxTMFpnh!kz~yGY{J@Rr`?)?rxe0~ooN_hGt!-eR*s1) zZ~OBZo7)sPKH?-me;ET<@e!#>RVun?6e4{a*Y>gv(94MVMtgCSIrBUJHM55cKVl$G zLWZ!Ej-yDmBveaZm^kvD=0mV~?)aw@vLM%hX(Y|}DNu050s{d60Rn;n0BQ4g^ItDm zPVjX#Jk1=bmpI!!ynKK2Uz29e7j69;6I!tVFf>ZPU%t;BMp^yu91p}WgG=GQIT4i; zce_1SIxeZok4o9Zij3y{QEGEsW+sNmw6nmPdxKOHK5vuvkky{9xh{msq%)HO%;JyV z1kB3%edF_}C)D=$(~fAc>}t0LWLxlbq~r+=2KyEIjmbA2EbmjuwJc%b`RR7Qq736dzIQq}~zfRUkO&>dQ^Qeoy zQ9oB@wa|1ndZ+hU#~TSIN>G|PwMjPmn5?4dwAvpBSV53faP5si2D-KAj9+;RunJn zg?Vim7xC!Fbn!yAeLZe_errR6=}ongkcr!~M%BHmK+G+c?gR-(UKdlSj0*v9*jj`Cdnu%)3MAJpmc4^)mBW%5*%18J_}%VGbY(m)9{V z7Z;kzwslx{G7{{T9*fR;Jje;WREDW;OAc!Dl-W)OY6$?hw+@1&PqP41!2*GS0Ie0; z9KC8uD`tfosKXZ1injpb&)wN3rdR+q6U9ra6)P|T9cFzX2aiw>iqq%wlwEYFk?k5N z>d^k`?2Hts=rqqpp*<6L$(Pe7hTCN|pG{t} z)io6MdrYptNXV;%ngZjOVUIF#H3ETvAELpfGZ=uWEss7Z9AR+?zc?gM7UNRpp41n| z6+fQC81fN=oMb)Ei%r&i;;b<)l^2a&l`jUdzjvQW7LrSF^@5^55im{yrRP>!;wm-g zPwdFH{mDO)p`&*Le zZ{vbroy>*bBGrbF23?bhip^!fhrX!VI%B^@Nw<~a%?>-@jNZMU&le!s&BX@|bo34F zju8UIAyT6oVP*I_XCki8%r&Hw*JDOxxQL*QKCm?LE~1P6<3{2I(=>vAcZ(M7K!+>R bpUXB=Yi^VOuxEH_Yf7Dgy9$&e<~`+rd`woB literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82158659-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82158659-0 new file mode 100644 index 0000000000000000000000000000000000000000..66898a78bd65c9d1d9b8bdffc8bc9b44a11c8654 GIT binary patch literal 1837 zcmaJ>c{JOJ8vP|=-vuRNS9IDcs->~MDsAc1*4MFCpJh<3t(MwJ)Ka98s7weI`bZB$e6v8S zT*9cP$1#&^@|l|3Q46H1r5`yj82IZ}D}C|OPO{JvOkzi(@vo&#f7T~ql_Fu?b2nbD z%<@Du-0(ngAp8M%F`X@^w$&+oi>-Q<+u{n@o6NFhX1PV64HIL$$~t63|8Rv4=9fn_ zdN&A6ahI{1-lGjC0Aki;t}&8y~5o8Nn>b_Xx@I-oB0J|L4gau&MMJ(m(UDy zh_+Su!o6JF&f?zBr0@CcvZQNgw4AE2o&Fl6J=x9cX@WB|-axl5U79y3{ohBfR9}fr`E9nm7I_X6%_{N1Rx57VUnJ!!Hm2*Baz2|3siYOO>h=|@JjWqx0O*As$B%;|0J!~R1bzzx zz)Fn2Q(zhl;E=p}B8Olg9m@L?Iea4R6~G}dXFTm46FtiPgdUvfI?Ari)YppBlMKyO zch`4qwFUuy-|}CKpiD_1j(i75d*ibGbc4yBSA3|MUXb3^33@|R%TQP} zWnwDy0^}Y#K|k;javGVvAk8cW%IDZQOhs@sLdYnNh|jPNtXD@cG=g zUVP!TC>S%Bc+Hd*>bvD`+6m8M8Xc8Z$AUNZ?aaBL8lN-Fber?Ksu?ryo%aZ`zlE~Q zO}C;w_shGqLn1Tzl3uT+s^@6@ayoAKE&sZQ`)CU$ds&^JL#R-$%Yql-vEM&z`!=-7 zLh#0;+F{cdohQ8sya|y4*hb=BPpL2y+gj~)_X^c|r_?ev@w_jFa*=qHRfCy#!UwyP z1ibs#gruTA!UNmf>K`@NBuM2N+w459u!O0_Avh~c0%=Yihnz994De?Wo&xr2p=Gh6 z5*(!h|73pnzz`LFg_KgT*7wR^4cjn62=nK-Dwo+xt*6hpOCqZdt!v8~OwD3u z5POxlhj|@R_U2ZKX4q!o%TC3)bQ4mzd<7qUOw>nG>8v6|PAF*c#Zp`XRjh@LMowq0 z;rJ6)MXD5Jl+FZ2insKQuL|*wT>J9|$|BitK&P#5@E;HVr7p5FJ+@YoslJE*&~oN5 zz@Qm>p5WsQedXuL7X$tpq}qz07^yOJ_R?mNHmZ|0wAL~^o_xO#7_G^|Kvj$>JA@Ip zTJ9gEExPmjmzQC1UOpH3V0y9ioPY+Qh;@ivm8$D?g;fRwpOF~!PAN-|O1f1*jwT6r z^rfD%E9p_z=&y3@bUTMBV<>&kz~N&}C%Zj%FK%?@9KvYEvIkH}{_uN_v>mO|J4RK5)Ll32gY93|q!5XHb)g7X7{uife>G5CRexga<1tm|#N3P{e>BRi!9pB5f5yuYy8YV3D%Y5~YRE z+fqczDoc;R3KBp8iH5d-E)Z&H!DU(An|bs8yz}RrGxyBgJNL&SpN@9`qtIk990CGR zG6-at?O7-nKE}uP@1#@z1tIe0l%b)9inVx=LG*OX`2`1We)HEus1LDoQ=6%o!;%MO5aCq5t2`_*)_?2)AG8^r%>29 zrS5`;$hXA(v<{kKh z$Us~S8B8Hd!-1nEWNBFd0D*tge;og@n911l*owlM|la0 z@ocxWgc?4DuULV=KezlB%vd8j$XDP1Z7bbmB~qz4{O+wDUWr2cbwlUMuQcJht2)&) z%n|kYpg+SC-ojc~H$~>=(lcKMFLCE$^^vdwj}dYko<`D1tQq*67ghNUG6Xy`W~v-( zfL^9X$<(%6{{=2E$b;Z|*0ki{6 zv|6WmQSw6h(lXflSpGih!fhYAI&(AiO{s^jTE&I8FYJ7Crpg5P zGY<-Mf+7!3;ciuQf|O)t_qMcc8(Jm(E&?FINg!&G$$SE4#!V zIPT+VuRUs~I{JV6RhhKz9CNb#CcSeS70FkZz1HT!?@n<_|EoU9{F2Z&m$hUFwi!Q; zIN@Q_XhHTV6EnDO%Jb{S@5ag1#*Ur_Y^`=uTV;d6i_Kk`1?Km6)aGN%tTVbAnQmuK z)F!Ib(|wE_S})T_Gwq*5-BQQCx9NKlen@Mu?cEOis!=~0zzR)Zb4l4o7R|pj7QZ;Z z`_vgxg<(eWeD?2l^Pi9cQr-Sf+eS~c@^Rz{cM?0qJK*rF)xT8$|(D5GB$ zn`o5P-@c?sBM{i3;u}@ENE||iP>CPDC=<7tj}%ixAFfT-jrVOD5>9inHt&C;3Ne>6 zxTL_F5!`6sZ6}YY)uz!e`CrUFO%$b#%YB5M@5M~_<4)x2L#qQw=a-dvq8JETX}v`@!fig5LY ztFEn9fV%qJ8fRjDrLopcb(ZvqZmLP-3=eiOlWxRd+9aP6i*5X#OUkoVoW8`&xN=_H38sHFkLvgWT}ZNOj-y-W>4O!{G{jG)Eq|%Wa8OS$v&QwSfJxRX-8@qe0oC zp;+l+P^$^5B9ydr=(01Se#eK5%v;M)EhAJSD&%_}7 zyv@Q$9^xIVUJWHM8`R+p%n9T5h(s~{%)m7L01cBqI~m;XZ@g0F>T=YG#mgozeMVb} zcUl;&6*d8 znD&m$XyZD>pUtt>miL{`w^|YXok8y2?_MlLv1W z^5PxnJ@nq^*sQ`k)M2kBVpy**9O3Lvs{drIXVw(~KUaic8cH}!st_Im@3CU8S1vFeVt=M&XC``Ojhi{FNZ%1XpR-%0jJy$%YC5Tl&Yd}lhwF7q<^ub0!mbA&6 zR<7j=T`4`_w`R_4U@y~V{T@lt^4?D^Mc=h(*>PwOwW95hO7{PQ{J))xR7N8I2E2qn AvH$=8 literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82158659-2 b/trusty/keymint/fuzz/corpus/keymint-reqs-82158659-2 new file mode 100644 index 0000000000000000000000000000000000000000..8b2a6ddfd8f3a2ae4505508b8c2c999915ee782c GIT binary patch literal 1837 zcmY+Ec{JOJ7RP_TNF<20wWXFsliEkBrL+WXwTc#Pb?DfhS`tgePVK>1{S!4MFDQb3?| zgfNt9rf|We?xt7cgX1DQBYsa?_+N4>D^B|r-}XAw9;a@o_6yBTTV~cndr4fRRhqhm z(Or}}cq3li+HV?yPtc{7W}`(h1Pq;su~dg|@BAiZTE-xJXyiQ7q=#Q!72vheeJ7Ri z(2-jDVR~`{unT4nm3Szam{7y78Lgk5X4wugG`B5-*XN~A#Kgp1QBEllQr=1VdUcpcY00$y(IZ!w%RutZm$i(9flZWlVjSAWx-h6Mls+qfUfLwubppfY>Ms zNTr~JfWsja6dC|P;6L(Tf*lbIdL-Ns3JMPZT#|^xkU0RfqYmSTK_LLrc+`S4qX3B9 z#6Kwr8wGHQT|BbADDZ4e&ynprvR3G<;~_Vn^&=Gw4LqwMYPmby?^Q(pv@I4OJsi@@ z)4`dTgTOz#{IB|>FXe$;xz^Ce$8DDF_6-;p$};KmW!?c+SpMk6jxP&|rpyQvuVZ)o zP09tBE~_IHqVX#2NeE00SQs3(!}raB;&xOPA}Z8%Iq|o?W*+T7_=JZCnI$Yva`jv3 zAN-u~t{}1=EZEUYftw@d5jiNacIvNvah`W8rpJ{S2z%GdKHXijm0_0*!xj^hH}p4w89^SO)>b!aSfEQT_Mi^?UmfOjLB*CeiLVg zNPA{0SSL-IvxSRsfL$~QRWD3ys-hKkh4BpZ zB-Jp3E1*AH_B)!mS=y_;-&l9CQCm4YZ+9#&(%uOI)Lj{rqmff+x+Ya6*C?f-jgk` z>+RN?`bp$m1UDl^q-16DGwM0{W&Z|YiuS3_G6P?M4U`q|fO{F6Iv_Jwc$tA^Yb`#D zhWG2E3}5eEtMBbW+yH#Mowl7!rv%)0HCt9L53+AHQ;m?<1U!Y@%XG}_GEbcCkM2V7 zRNP&EBtVj|o2tI#{>7KGNiUk%VJ*egF00bp=B&QzcZz)tlYfzcT~T@hs%gBl8`Gukjs9Y!PnVxB`cs;^S7_ zMWW}oE9RYN4Bfeuii1X%8rI6!lE!1CctY)cD?_6^-S_uW9$2`}_N=7Uq7$xfiAkF6 z3dg#mIF)NEvVqF*l5DdF2+P5wY*ibQc|&?ur=+sCX8N3h)(cG3D_-bFo|Z*XrNaCt zm8d?&05d9>KOFE%h0gwQ4jv(~f2+B9vyEYVsXLJum+Cy7_tqor(M|Hw`sRb-GLg~5 zVIM36x8u^J+I~BWAY&2wJ~Jk`_4=^pN zTkaWpN;A_&gqJwes}g_+xQ@2%jn2$#s?y_{$MwC(F%qZ#G#B+Yv51(d5ZxJ5jMx8p zuA(d~Jf84Dt7ESoC1Lfxk94D*lqJ}BnL=18qA1V!zPud1zk(VR-rAV~fCyDS%tBl&XOy1&&>@;?cQ#3h}#r?EV{FJU+C+)j4 z&2(D2D#)b(-{Q@AXwcSn({cW}M!CXM4R8S;5?+~5WTrUhs&6m(X2wC1Wu|;#MR4sN z#p89+{0$CLx`BRgbC#+r@ zaZ-zXx_V+Ob*lmpO5xW$@p=@Q86W5TZO3tZ_c%5Kr6)q+nzkJWADEe+w7iO_N zu_I=M?V^7T(K0&!H*InN$4U*_B-%$C^NhK^qcv1TTA_#2s#VSj$`*8k*wq{DT?=z@ Y-*8w*XPBUNmc`!Hu)it)|8oK0->9xUYXATM literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82158659-3 b/trusty/keymint/fuzz/corpus/keymint-reqs-82158659-3 new file mode 100644 index 0000000000000000000000000000000000000000..60bb11331d1a0ebbc69f43a7f9abbd128f8d0d78 GIT binary patch literal 1837 zcmaJ>c{tRI8vgxe#vDr=k0J({vBgPQvV>!4vM<>pGE+EY->&^+YidH8K|^DZeH&$$ z5JRIZmxeIOUS!FHh_N1B$Gy*UpZm{!|9Ri{`QGRGzUTYn#R)!e0%MeLU=#!dU^oz{ z7}I4wwvy8}e_R4tp8k$UlUHAdjp*kv!+34bzb z5TE3TXm|`OQn~;Ep-S=voXYT{|3E;n5DEd2MKH*bE9Ou>GGOU3>9^mDfN%gXWT{wy zbgWGM!a`OVvF7*lW^`T&3N>H4EKsdy_Mgp-1Q@@JOE<_><=LV1ohS2!KxvQ@M<@=! z-^GCh9D*M>T7p9$0RRO4P5*Hm$BqMbOmGMep#%U>5zeEKH30M=j^al_egHx{9zk9s z0EpzLzf%x80)Pskk0k>Es@A?cmIKGq5vlEAWt@ag>F{ZE;xig)RCa#TxLcoe728J{ za$CsicxMd)f8X+74Bop^07CPfU^EF~xa}o>=dq=yS5o;08fhZbseCGmlv}a)%*5Vu=RZMaIz%MpF%pITn?0IT?w9Kiu zGo77_!%jC-*(YN|JxN01c=E=#N?fHBL$PXdO*0sS>3uIj4%NLL)EP`nYc6Xg742{A zS%W(lR&1TU+0hd9{MlUoyv#0m|8?44>*rn3aAL(G<6EbipBGj%56M@avHab`XqFEx zcgX#UYWT|a$83PgSA!4fQY81l>|b@LfV?z%t}WvhS@BbO{g57C=-NCS;+d`Ce3tQoN)Xkw zO8FyaHM)!caEKX~>frvmQf(y5)|0%@;I$WVXKhp<_g<1p5t&Zhv*6q})(>K4>deEY zg~k&xSIf?sAN+_v=gC)AzzSY!Qw@;oY28lDl@}D` zEC~nU`4JnQFKac6t5RsWv6Pmm|GzPYvQI zHG||sbi_$#Oda-7{Xm3kuJx0;Q~M|eaz+Xtr@$w=6G9{CRrRMW=J;$6cY6mweBEO9 zrW}{KWy=z+v`%Hx(lln4MpLjbnAQI2VeYy|sQm*zk#21jZ)QF@iDjf7jTNy;er2-7 zm#(P5HIplQ=#37L(E#N3D4GT1(Dk!<9HFwKtD_}Q*|R#PVu<@=20H$~2>-Mk0rnUr z^OapJJjZrHNMsd0G>_HVKrBi@GnZr>5-e0A;HohpIq)9?*83 zzwN||pPa{E@{?^_#zptDWNteMpvNg@aO<|FgmA^okq50sVel!#Up3<=IYT~0W`J(R z8aFcJEMr_L?!EH+;aw!t6pkyZLziE+vl-2PTH9tcnF!l2C6;WA;6Jp55(jTax-Bu~ zc~dF1qp_5F*2?y@R;Wejf|+>suv@V)ahX*;rJBO%Rxj>xh|68_;50*SS=wJRH26%K zo5o>G!(wqEXZ}k506e-;Va?U%nIyW)3AO)tgGWcNyo#<~M?$EQ`dG{Y@deZg*BWKP z>G8h#x+M{HwtI5K6L3A4Sr?V2=nzeKL5klmzpxNHY4WiX^tfY^HQZi;cUtO?`#JsP y8Z)7>h86XG&~8OI&dP{f)Y_IN9H)Itc7V&vx`0v{jcxc}{30QeU<6ho^3 literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82168258-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82168258-0 new file mode 100644 index 000000000000..e68e2816a816 --- /dev/null +++ b/trusty/keymint/fuzz/corpus/keymint-reqs-82168258-0 @@ -0,0 +1 @@ +��X4just some garbage data which is not a valid key blob��:o���Hclientid�:o��CGappdata \ No newline at end of file diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82168258-1 b/trusty/keymint/fuzz/corpus/keymint-reqs-82168258-1 new file mode 100644 index 0000000000000000000000000000000000000000..6b94220472acaef197546084c0578e5d1fed24eb GIT binary patch literal 206 zcmZn?Yl=A0#L(K<#Ms>=CBVSIB%#nGrNF?z$N-@j!4w;iGGJg}mS|{_Dqvvz{uQK_ zX&+FH0Rz)PDF!B`2VmwQDF$XSCouDz6r;(;vtZ_VFf&4-zxENYWcmdwKgRcYUVk^H zyh$z-`8SJmp31+DAFOYLI06_MKo%pwg=Xi4jLZunRC!lh7b|qR$sby7`mnY7OwY_4 aTUxi-nw+z%UHGEzc+oK)&q>#W8X5o%JwP=8 literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82178158-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82178158-0 new file mode 100644 index 0000000000000000000000000000000000000000..8c41bfd6d142a8284c2df4d1f1ab351c3324a50e GIT binary patch literal 206 zcmZn?Z;UwE#L(K<#Ms>=CBVSIB%#nGrNF?z$N-@j!4wMXtMDvn0X$|j8Kq%kU|+y$*0o!!0id@6b^mKv=CBVSIB%#nGrNF?z$N-@j!4wNKm|_F+3>X-gB^p3#nf3wI z7%(s$lwx2~dH`k~l44*Ma{@EZNimviJPT%?2QwoSK3A6<==4%B?tV5!*_Z#r&VP&K ztj@)pw*K5SHG01LLGb`a29U)FaG}|GAtUpG2vzm(c5BpqGy3^XZFW#rd!$`11DD`m3++TLS>WJ3jdU literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82178158-2 b/trusty/keymint/fuzz/corpus/keymint-reqs-82178158-2 new file mode 100644 index 0000000000000000000000000000000000000000..c09cc84efbd7ce9d78c2b12a2e25d7a9abbe76da GIT binary patch literal 205 zcmZn?Z;Uw6#L(K<#Ms>=CBVSIB%#nGrNF?z$N-@j!4wMX-gB^p3#nf3wI z7%(s$lwx2~dH`k~l44*Ma{@EZNimviJPT%?2QwoSI7L~%h1LE$y0CqDk`#yivV;$f z;faUVW-kvmUUBVG!t($|29U)FaG}|GAtUpG2vyazkE+R+dk#F=pS@rD;X_t~0-mfr W+gPiM5%S_K?4A*?LDvn literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82178158-3 b/trusty/keymint/fuzz/corpus/keymint-reqs-82178158-3 new file mode 100644 index 0000000000000000000000000000000000000000..63d07cb9f808fbe9fb226410611fe4510484cf46 GIT binary patch literal 201 zcmZn?Z;Uw7#L(K<#Msd!CBVSI#0;jmSem317#JAYK|H2?3{6r73`_^57?_kEfSHG+ z7?{PJz|3<}j3yh;f|=*R%m@Xw@^dSz_8;utoBVd_8~;>}oOb=~hgzeSoxA0(`+m_2 ztpG*_pxHnS0~eZ|7cw$0h_KK|{a8K4x5bY|YC-f@9|3 literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82178159-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82178159-0 new file mode 100644 index 0000000000000000000000000000000000000000..5d7d27a2387a333250d2bf471287a269a89f9373 GIT binary patch literal 314 zcmZn?Z;WI#X<}$?Y+~$gk`iEGU}6SST#QXp3JeU4Okj$Ytx3v&fq_|)k)cVdfPwM* zSCAs6eL$W81Jgk%1}3EkVCEqy24*oQF!P)gqshjzVCH!+GeRL*^JDw>y4yVA}^P9eS7tGLz~{p zwCCIXkJVXJ{M+-&N%6!z!42VptN+?)B+GA{`MuZg+_%-Y<}V02$>))Je#LZgmg)`G za_P4JKE4#+nXqBUNm1n*MbYmpx#M004#Yc2xiX literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82178159-1 b/trusty/keymint/fuzz/corpus/keymint-reqs-82178159-1 new file mode 100644 index 0000000000000000000000000000000000000000..79515cc5f6d8bc19aa1f0f7de3e6758eb5c5438c GIT binary patch literal 314 zcmZn?Z;WI#X<}$?Y+~$gk`iEGU}6SST#QXp3JeU4Okj$Ytx3v&fq_|)k)cVdfPwM* zSCAs6eL$W81Jgk%1}3EkVCEqy24*oQF!P)gqshjzVCH!+GeUtUBq`$KB6p``uXXp{ zZuB_Gw8(1PEveV16ga|i;(m8M3}9pcS_#B3aG}|GAtUpGh>0^zX0_($@yg2y-g|IY zlx5**twZ*WA9>$v1xG_8lr=9rSezuS*(uQL|g zWNe?#T>N&S;8ekNl|}K7+&-AEnfc$iEiHa=$$D>!H1ui!0Oj6vod5s; literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82178159-2 b/trusty/keymint/fuzz/corpus/keymint-reqs-82178159-2 new file mode 100644 index 0000000000000000000000000000000000000000..c5f577c4f91c6a4559ce63d767679e5933170b6e GIT binary patch literal 314 zcmZn?Z;WI#X<}$?Y+~$gk`iEGU}6SST#QXp3JeU4Okj$Ytx3v&fq_|)k)cVdfPwM* zSCAs6eL$W81Jgk%1}3EkVCEqy24*oQF!P)gqshjzVCH!+GeTkSp$!ja*qF9gE?Lvj zGOdAC;={g$X2+(i_?VQmBTg{YQTH(vqGjZ(jRra%AVJRdWoZOjKGlxAm5>=q`&}5#KF)r!_|| zeeJP|)0cW9iZ|SrR;`~JCG<35+U|F?e2+gx<*~X-H2%rFXdF8Az-->Y%g*U1-f0D2 ooT^r{eA`v?=|aYOI`{dOaPNJ%RNaclA;)6Nr;ln!{Doy20HPOkasU7T literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82178159-3 b/trusty/keymint/fuzz/corpus/keymint-reqs-82178159-3 new file mode 100644 index 0000000000000000000000000000000000000000..c93b24c7570384d0639e16a2e8116106a87221ae GIT binary patch literal 314 zcmZn?Z;WI#X<}$?Y+~$gk`iEGU}6SST#QXp3JeU4Okj$Ytx3v&fq_|)k)cVdfPwM* zSCAs6eL$W81Jgk%1}3EkVCEqy24*oQF!P)gqshjzVCH!+GeV&wJZ8n0Esdw7n;+Vg zlx6?ye|7uY_s8w)pL9HVFm2KV_5el(pp`%j0~eZ|7cw$0h?r>pby7;2fpXHEB^rDO za{lnLA1=^-b4C5L*C%J6g4oK@ o{OWH%!rXQAf8jGTD+OlJNxT68pA0=*6y~|@UcLNR-JA~%0P*y9@Bjb+ literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82181a84-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82181a84-0 new file mode 100644 index 0000000000000000000000000000000000000000..cf90447051c5c6ce847cd289ec412aa1c01602b9 GIT binary patch literal 326 zcmZpYkZNI!_|e4B+StU{*JKs{{~xDx+Ku*`(NbTPnxq667?>m!Ks4hI#wIBR1_nk3 z2nFG>Kqxi|hbAcl1_owHkhB2<<4ud#yIV-j{G=V*X@I_;rgcjWU42+FH*LtZ$C=|ZtydM>GZ~l#wpAO~mOq-<8 Tb*Zo+VNSvi4HFh-4Pz|;0;OxC literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82181a84-1 b/trusty/keymint/fuzz/corpus/keymint-reqs-82181a84-1 new file mode 100644 index 0000000000000000000000000000000000000000..02233d7b04c84c91e3e54baa7a0100b69f5a5574 GIT binary patch literal 272 zcmZpYkZNIw_|e4B+StU{*JKs{{~xDx+Ku*`(NbTPnxq667?>m!Ks4hI#wIBR1_nk3 z2nFG>Kqxi|hbAcl1_owHkhB2<<4ud#yIV-j{G=V*X@I?avkqA}- literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82181a84-2 b/trusty/keymint/fuzz/corpus/keymint-reqs-82181a84-2 new file mode 100644 index 0000000000000000000000000000000000000000..f39c95304ad948fb66086276e7a59c86d9a02ded GIT binary patch literal 326 zcmZpYkZNIw_|e4B+StU{*JKs{{~xDx+Ku*`(NbTPnxq667?>m!Ks4hI#wIBR1_nk3 z2nFG>Kqxi|hbAcl1_owHkhB2<<4ud#yIV-j{G=V*X@I_;rgcjWU42+FH*LtZ$C=|ZtydM>GZ~l#wpAO~mOq-<8 Tb*Zo+VNSvi4HFh-4Pz|;0b^^T literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82181a84-3 b/trusty/keymint/fuzz/corpus/keymint-reqs-82181a84-3 new file mode 100644 index 0000000000000000000000000000000000000000..438b2be0857ad3320d027959e3fddcfe939b4674 GIT binary patch literal 326 zcmZpYkZNIw_|e4B+StU{*JKs{{~xDx+Ku*`(NbTPnxq667?>m!Ks4hI#wIBR1_nk3 z2nFG>Kqxi|hbAcl1_owHkhB2<<4ud#yIV-j{G=V*X@I_;rgcjWU42+FH*LtZ$C=|TrydM>GZ~l#wpAO~mOq-<8 Tb*Zo+VNSvi4HFh-4Pz|;0Yht{ literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82181e83-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82181e83-0 new file mode 100644 index 0000000000000000000000000000000000000000..3f8123775e89b45f1d0c72d60dd424e4efaba6e8 GIT binary patch literal 208 zcmZpYkZX=O(ZtZ&*u>b~BqhMWz$Bs2B&EQ>z{mih7{L?^6PRKH@(dUlm?auOYMJ%{ z)fg}^9h72VQhESp9+F~U7IOkK&q*EtW-%u)^PCi;$;Pu_=6NtPLLt-h+^Nknx1DdybYpb->l?4x@oeF@ zMR%X>U9`7G{@*T^07eF&O+X9-7n+?HGBPiSn0PVnW!IghY@dXVFT38dm%)AC8oi(u z_N7EtW-%u)^PCi;$;Pu_=6NtPLc!vb+v3HH#!Q;8Q#&_Z%BqSKx;k~1 zBg~V57^pg0c^6mhkEPQ-^rS4?RMNHS{^wxPWho%>e5ruF8&<#zm_RYd>A8T hd*%O~T^oW+uM{M`56$2YKhn3rFtM;(Rkp#w0RRL8bEyCT literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82181e83-3 b/trusty/keymint/fuzz/corpus/keymint-reqs-82181e83-3 new file mode 100644 index 0000000000000000000000000000000000000000..705537b14a79bf52b97c1185d05e9442bbe57e84 GIT binary patch literal 308 zcmZpYkZX=))NW#EZERxfYLXIQU|?bfQ(TNqQVI+Vj7$&;C|JP2`28zLj%go5lav7i z(?KZ)CZz{p<{>EtW-%u)^PCi;$;Pu_=6NtPLP3>vr=#81s_zreI&=Phu>Oo-y<7hb zOP8!W>@W6fU(37}z{mi!35a3fLbLNiM&<<(6We!AwYnu^Sdo24q@dflNqcY;12JS8sA`WFdh-frc0=8)n#t*;^X*A^-t_ s8UO=IBv>GE>j~dlQr@4~$@0Q(43?50iqdg_V4Pt1C^Q5EC^IU6fGYPOa{vGU literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82183386-1 b/trusty/keymint/fuzz/corpus/keymint-reqs-82183386-1 new file mode 100644 index 000000000000..e07515ea2bda --- /dev/null +++ b/trusty/keymint/fuzz/corpus/keymint-reqs-82183386-1 @@ -0,0 +1 @@ +�3��6�.[��LHello World!�@��� \ No newline at end of file diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82183386-2 b/trusty/keymint/fuzz/corpus/keymint-reqs-82183386-2 new file mode 100644 index 0000000000000000000000000000000000000000..fb70126f45351f7a3cb5755ea9de296595d191ce GIT binary patch literal 86 zcmV-c0IC0i7&C?&N8i#Kgs_G7flNqcY;12JS8sA`WFdh-frc0=J4Ak~_aq3MkN^RJ s8UO=YU|1mBmf8Ro!r)i10f#aX(y4*I4#md4Q26Q}2XSIf76fYECtBme*a literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82183386-3 b/trusty/keymint/fuzz/corpus/keymint-reqs-82183386-3 new file mode 100644 index 0000000000000000000000000000000000000000..2ec87008894ec8dd8008f2fbca30189c51a63dd2 GIT binary patch literal 90 zcmV-g0Hyze7&C@D0F0x#&cw)ifl#G}sSc?#a$GE#1x*NkKc0a=frc0=8)n#t*;^X* wA^-t_8UO=IBv>GE>j~dlQr@4~$@0Q(43?50iqdg_V4Pt1C^Q5EC^IU6fTHdt0{{R3 literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82183481-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82183481-0 new file mode 100644 index 000000000000..7f4913fce35a --- /dev/null +++ b/trusty/keymint/fuzz/corpus/keymint-reqs-82183481-0 @@ -0,0 +1 @@ +�4�;z��ʖ�� \ No newline at end of file diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82183481-1 b/trusty/keymint/fuzz/corpus/keymint-reqs-82183481-1 new file mode 100644 index 000000000000..9a89501f0f46 --- /dev/null +++ b/trusty/keymint/fuzz/corpus/keymint-reqs-82183481-1 @@ -0,0 +1 @@ +�4�߆���6 \ No newline at end of file diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82183481-2 b/trusty/keymint/fuzz/corpus/keymint-reqs-82183481-2 new file mode 100644 index 000000000000..219dbb27b925 --- /dev/null +++ b/trusty/keymint/fuzz/corpus/keymint-reqs-82183481-2 @@ -0,0 +1 @@ +�4�2��� K�� \ No newline at end of file diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82183481-3 b/trusty/keymint/fuzz/corpus/keymint-reqs-82183481-3 new file mode 100644 index 000000000000..f3875ac841ef --- /dev/null +++ b/trusty/keymint/fuzz/corpus/keymint-reqs-82183481-3 @@ -0,0 +1 @@ +�4� 訢%�� \ No newline at end of file diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82184180-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82184180-0 new file mode 100644 index 000000000000..a0a6c554c311 --- /dev/null +++ b/trusty/keymint/fuzz/corpus/keymint-reqs-82184180-0 @@ -0,0 +1 @@ +�A� \ No newline at end of file diff --git a/trusty/keymint/fuzz/corpus/keymint-reqs-82184281-0 b/trusty/keymint/fuzz/corpus/keymint-reqs-82184281-0 new file mode 100644 index 000000000000..775bb4b5ab5e --- /dev/null +++ b/trusty/keymint/fuzz/corpus/keymint-reqs-82184281-0 @@ -0,0 +1 @@ +�B�� \ No newline at end of file diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00035504-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00035504-0 new file mode 100644 index 0000000000000000000000000000000000000000..8900169ffcdf6c6a7db0cb59d998877e890bd240 GIT binary patch literal 1975 zcmai!c{J3G8pmfdO!j@x7RmaXF*EkvghAF!#AIJC(L%yx84Mz1lAR>s^=8R(361TB zM3y3Xk&?Y6jCHuW=l*feJ)L|1dd~OzJkNih^8rCG!r0iL4mce09B>wXl9+fUy}SXm zmk*$(hEj7!Au*mB7$0@Cr#Ao~F<5ssED9h)qycs~LV;pN*cs zULU7b9tCSSXCtE7wH4Uk7Z^H{)X{opSjS!GW;s1F9h9wM`V3!b-CRaI%pF5T5@HHIUlh1tpg(s+ebep$dnZ15y8QIOXLh%u`Z%o zd0KvCq2-uWWu|9>Z#rt-OxVOwXmZR>a{7x_U&Q^+9)S)CTgMF)FBT%THX~Z$3?4 zgx^5uCBa!~_!=8|{3b^=?ZuCRZ}5oH(yP#n^csHZ(WCvuw6<}X4P-Kbx&j{Py7DxO zH}7MR*JUC+Z__b|mvLt%H$*KL^wHw>D{?q3;H!6-6mxz57ab)YI6W#`>rZwC*{aa4 z9R_~XXM4MGs5X>1!|oygpDHg*cz7E7jlzTWN^7S`6EDRB;%0F1A(Iy^v~*N)=vD$7_F&Y=iMK2ioGeywF-LV!RFAJ%;iL`q^p*ru2S znjVW-_ODp;0Gz)Lc){Rf7!v?J834zxg7a4agF+y%|HP2>Ul@Wx30w6oJu>wPoqXPB zXYJ_0@0LfXzTp1wPocL+_K&y>Vq)FS|26fHU?N+=mFi`%?omF*V|uXj8J5u(Df+HL zolsKW@@A)Lj>r|xQ>^uW>fnzotqjY`wc21dnBwwidHLT3z;tn8Qc8{BqX zbz`JS@vxYurgbsuCI(vK%{0Qnj3B(A-(F$)%iF*GSiRS_#?x?Hxd+UB`1*03B8V?w zfTZS3u8J33LfFuRsb{>**<{?ZQfwb+392~v3!_Y=WN()HD< z5P4uwebx}OH)STz`l&LJ95ot51Qt$_@wXy2`7g@zezWm?DD~y-o{h_%wOm}iw%Iw| zP`%L#mLs#fUIU}wMQ3)3|B@7`?j>7=e=smhgn?9x07$XDWRBp)XvTx|nvI*N3t;(+ z(%-$aXi}Q1TDx&E=?E^tI?vn7CZEyoi$N7CsmA@3ZY#^KM4@34y00KncpP1w-t7L9z=&+~e|!Ih&oOcTP^NL+mAj-!Z+b=IX8S_(y!2}yR;+)#%Cg~^ z2?vqBr`i4f*)|HATx;pWGL(r6at1o5TK3D z8&7jrw#EO87eEv#3<#beb)r2kA59bhXnJd4)I6{r02%|F7Gy`E05ueV)Bx1c8qR|3 z=#z-V{5$^d=l|!(nxdefg6%y+>qqGy)ibV25VI^KTZNH#tFpozglz5Q6hva$fDY+6=~ z0&f{+zZM&ex~2Mj8)@5g^!%8i7(9P;`Bi&Sx5W{QOyM7gt7(lD-xRe53y4}_8FP(% zM&U@OgdFZ?Mb9e(+9%3L)JieK!@;xT(c|>%f3U{dxj)meE)6%KoQF-It!C7))Vy8#Sj;^8&8XaGZ442qlDzN|Rs?O~3gGXikK1EcNBhWG?GbFcT z`DI75o_6P+&W#RpH;Z;vUfhC`ewy6W8ob}sXR}jYrqJ4$Xa56_M&hS{wQb)^+PfI% z*rSyfdwFqvvw8|Bg+pJ(4aqtTe~O>fPz{hD^gV1ZNv&4sV+jXN0$v*Oo;h~YiRGM6 zYgh`E<$+wz;sw^hGah%rU2mXYC0O+?<2&bPi)xDLPcq9%d~r$g3E;~{N(+%O&8hij zbJ}hZjksQ!<5ZK~pJRS4bUSt=ACXo>QJ4^?m(oUY2&ZxT5ccd6Rcs3Hy3hOJGJKG# zYhLiWi65%XH{Mj1B7x8yUf48nt$1j>&S~Y}WCXHhv;gM5de|(cn6bgFgW;5a#K&dH Pfjocb$logPcaHog&+uDU literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-001e170d-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-001e170d-0 new file mode 100644 index 0000000000000000000000000000000000000000..1d6adc0819ff47d74e9b28632bf2ec74ca94090c GIT binary patch literal 1975 zcmai!c{tST0>@`FO!j@x7RmaX6+`w3gRBuT*_TVSkT6*Wg9wrABnijKlI0Mx-jK*r zBnK(kOTt)(JMMG-xX*p=bI)Jz^ZCB-``_pJfKCgtqtE~f1pqh{4vBLVWJfa)srDBF z8b~(a6dZa9#>NJ~Ky6YVorzyn=ZpJnpqehTooLW1XR+6C~^@6O}|p>sf=Oz*s= zgtq&A^9+$}1Qey@LG9p2A=Fd89V z?^vuko_!_E0{nU7^slLv#^kv~} zs(|EUWkBNOS_UQr2t@JWT<1XK1SW)4lA*uRv4~m!iUkkAdGdf43_gZ20Z_&PaGVUB zCj$%$fx!M#L)L$52nNM%)iw9X)Wvo3d7hoMrUkxV9?9?q_lJHCzD>4y%%vL@?Q-GI zsYmvPvgKUK9=hvpWn(->2RmP2X?@|M@5|Nfi|d--?ljJkxB}Y}$n=NGk#Xs6g!aA0 zZRR}vlGL;Q5z&(^hHj@YX@g{QnW>EZc=M&Ul!x$+ntjS|Wz7 z*Uwh1r7VqEPvn{4*?{>8a#;lTQ^5-Ijn&E^d0NZDJfFbOEC}q zsB0V#1F04QkRlt&Y{5&B^oOa{8@Esw!Sa`+e|ToLOKGg)cVnVb5nO_`?st|AzhFKT zfyz~q4f?6w=4M^-Lc?TCUw*(2alWxC%X()fY+=S1m>V|IAQ>fx;d`Az%mu0ov%i`7CE;Tl~L#0Ys6)fFMIDM)tV8G#IVa z@Knd5-EeLI1`C`N6a}DB08$-L!>BU~ieVrU`xpNI&wtm*>c(D*Vr?0CO|f1j>8-7R zd*ynzDyla!7zt&|vNjdHx`a6BRj43H1ZlP92J&Kqh^3?uTI26n><_^%l6$7$bbk7R z8qsFpNH#U~ppnj#ap#GGSw%iU*{HM#1>VxjdLuR%aa;ApHqxr`=*2NzF>wCq%Imhm zZqp+cnS$RAS5q3wzboPg^GW!Sw7CX8{ZOPsTsHUf!WR{OZ4;&Bj0!Qm!@;xTk>j)* zzp+MJyFOR9C)IfW4{O=2!C7)(Vy8z+kFH^K8|+?=3>RBp z&bRsItj6s2lSgI!0aa9#!{00_Jt(JR`Bg`gwr1y^*3AwR7t=OXUc!QsPKw;r8ob}g zYqL{croh60Xa6IQdi-aXP&JSj z@FQd|0bL{XshEQx0WS&qz#P5lz;e#3B_t_><)K{m;zicMGj8|5U2mb^Bv`et5Ig5* z3#*H0Pt(iDd@%{~ao{WZN(PaG;4MwAE~{NsxTo= zD`_7kARNYRg4nZ)RdGqY>s}v*ONjxh&bfi>hCZlP?^q*Qss!Tv@WQ69bNM5Kbxw2N lMtzVKy%{j^*2ZNrMU4$^9SkS^Gd3nu4&?s78p%lDzW}5>S5E){ literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00303031-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00303031-0 new file mode 100644 index 0000000000000000000000000000000000000000..05965d99040acafd230e7291a483404eb79b493b GIT binary patch literal 1975 zcmbu9c{J3G8pmfdO!j@x7ERXQ3^Ug3G6q>AVzMunXdz)@3L1ix?nRK%_s z%P|=>x7p|lns*G2OFI`yi`S`$fi;}571Qq83hwU<4j)PGXuUnG=c#w2f)Sko%F!}^ zim$SDPwo{$Gi`k*?OmGVP3^}BzUzUq&2?U#62 zhY@rHn!~oHJ7w{rvQ_udjF>eyB=;bh(V7$D>Nu!%yGL6`p*$(~J@%eWaI{hT=!ZnP z(!zWKIJ9qxoJlV^i>OhVMvg4B9J8y=^h^j$$E@Q-O^rk*$K1r&D^jm%Mg`j(bl1gf zpx&CGL+ZBzBqamp(~)9=h9WPVU6qHga*)SwaMjSCe=qzBk18v>0?o{*6{H?L+)qkx z8<*Qar8rYpzyn>EpJemre+copM1bdSI)(5vZ_ng~spo+{Sl)U`j-&^D@r{sSrS*T- zQ|5y+VsdnT=Twxh4)5Aw;z#|qw;PA*!U;2+ZbI;>ilW2^C$V2Cd>TIK?G%}UWrNmi zDgTk6MFiZ$)hy-i3e@N2(00H~Q6$^NLz|r3yS>3FG@T&l!8n9ugKMeokngI?Om~yg zko=tDDkjqz0tJJ>W!``%API+FkmQ01!2}v>B7-#f?J0ro^2}w?T#AtNLlr>k*IEuH z0tk@=u%2@uVloTDF4Z*H{8-GYf5nCm;Qn>M4+bB@SODnH0dV~)xPKKeCthTkMQJmfJX#d)0jW9oskseC0*nvdbS zSH&2g`N7U7SY}_e_}fZN=TchB>z$@K0#9grGLd;-B{nh3%Z$F)w9Q&zT$XVD_03$syuP14m8tOfN?A zzJ^;WJz(C$SC8tIKmtJnM0Hnkb%OX3!j>*dJ>_G;A>U@5ZHpMX+Av$QmcBG*KT%+z z!vV}s5G!JM9}8CzudP;xA%Q{7StHEe6b{M$u_}oiGa5nw7EX}yH={NMFCh89+WJ3` z`TS8EsCTXiLg z3==i_3X`|OjQ0HlGqYyQke-Xju{9aZo_J=Gr@lB&8FvzC6KS`6YrM;$Zs5#&U^QxU2yQDC!Q83ZW>hF|a8<^+ut)=B z772h1g*}8qzz_%mw9$F}N#4q~d?W=`R_riJs8W`ZD zFee%fsG|Xt7NDu2;GhVG3G zM?pDq>@CGFFCh+k6|2mo!t~nnL-{db_;Nx7qv>}H=9_RA!8==cx-e@&6Ynr^B%hIS z(8T1U-g=~HRaI!FVqRW?25%YVypkA1BIyx8)I=T+wfb ztLcrEUzKzQ3kf z0`bYnMDQhJ<%MWcb6NpzPS+!<(X3bQIL&nT$5=oM!=4i*K%f^>6elDZW%N-qgv+=? z7-vqY8a9=G-S6FSIX*=iI-Z^Zh>0^WW!uKuEN=Hrh{1)7uvSkZ6pj1_lL? zAhG}_9HB(Ul6N@4U@!{^N`i2Me)cCIBnTKp5t=7hZUoF?rME7xDSu)D^?L%3G^@rh z-x#I8oW^`zS`tnwugwoy2I(3vqR#Yv1nG(N(BS&VP@& zXB!-C+&=mtNv^!OkN^(tUm|67l$}M?s!l78EVLZ6tIhOI2u#PUV@1u3MJC7G#Mmim z*R-O7Z4Y|tV>Xa)O;I5YTLF@i0rMG(VuD5@FYvA^!&f;-<2Sf!JDz_p{tAz(sJH^n z%B&O2IeNICoY6Kew}DK>=d6GSyDvY<6qz5N4U&(x$ zJ{j#~nWAOG)?6w7k)TBc+|<=P_3jGP=jG6Lz)VRb+r>lMy!^X;!KqZ;AUr)DA=&6! zt~cbn>N3;Qq&y@)r?iUB!b6~75V*n{@B}2`&)#tu``9i{F79=q}G(7R@IM zNk3Etq<*dCU?PA}oB+mi4n$00LD;961zQ}8Sr4q(@&Vkx4*0>~V;Bnn{W$=xUj_HC z0tSUZVE>LG`#&)RgOawWExmHoq%Hy9)3XkY(6`GYIsV{*$dBPSiH;9>jN;-w&iyg< z0B!Um-Ot9!5))x@Pb?bZw9JfjC7V0&2Q$L(;sHmc z<a_I>qk+ZtcvE!AEy@8PRQ4ay*aph2RBE2$ga9m@AmMIC zZ3{t*>Ho=Dz+o+9iPF`Z{jmMWq(ME)%KBWBHtTf zlVKqBQUFrsD4j2SA(nYRvu@)C>O5HSg6ucn+zuI?Ro&f$xJ(3(aD(@)WwTG3@5(?` zYU!o}^WB2MmEHKQoM3;QN%5Oa3%UYv5)%) z&9C8ANhdeIer8QHe*V~ly0)M5;y88OS)@&*-RiB$E{BF8p7+3d)bxSQaeD?DAC zy`Y7296XZG%sgmf^5xumq-0%PY_4iiS%v~{8Rxx{pvT-)f3}UZZ#sH*%v27YKf3g? zy|l;bh)u5Kx5L#8TGdx&U3xJ=HzI3}CSVeYbV-Wgw;#|SjaoJ%7oy#ven+^23_VllJT6$QutMi*Ls2FA_Os&BO zEc`aR6y-{6P5JiU^Jyo43|iavzo@s1c8xz;dA?Ve&_8RSgi<>6SKg3rKntb?$PCp1 zMIqlJ_EI$JMLv{snM=Vd!rrmQZ@RFZ@oSAp%VE2(kiU4Ioqo#e4!HX@^ota`!6jVR z{A_7m8RKy_g(#4aqL>7}WTLVV9oL**gq_p#h@zSI$sMPg?fw`GXkj>TA_WK?rDUZE zNk&D-s5!!A+%b$ZuUs9I#=q|OZnzQ`qV8T8x^5PLYV%LDkS9wa&JHhZ8o5_JFkR=i p32ZU}*)v-JOMe4QE=$}Ped}O2?H`E=xe6ffzjEYXD)9eu) zNMtFJ7b)3G!dS<=bNHn{E2e5u~;+uPc3G0JZx9 zk2ESKF5ej?9#}p_+B9Q1ro!j98l6B3_5m>|=fdh^b;=`Q4QH%HwY#?i2Koa+MiV<* zZ;$A?>D?%&N2GzWwM?H9E3I7;`-IR8Yp*F=$L3g^jd`?n9M#o%)ZNS>1n>F%7&=YW zNfqm>`t+zvO*iE5Pw;V5wr)IgSTh8WQZa%mG{x~$aQB0?jb6@H9OGBen{(fueOeS zSwhZx>^-Z12&49~5Am`k1$ks}Q2#PDy`%UnqFQA}VRW&D$*wxvJ1H;|xj_)Y86l^} zokiKpldoxp2Us2U)JATi-kP8T>$ZI*BzzZA6+{IMkuOM2$|F}fs1rB1sym*4FZc=% zFD<PuZ5a@Y{4A0wg2;^tnp3Mzb&jo!j zzx9$D*5UufD^!}be&Dm7G9R2CnXU6Xr=na{NcS#-IOe^x(>PokLZ0Px7J^Tg7sfw0 ziTz6B)9_4fr%C6p7_??d`i%N7A>bxX_@uk5P|ugcJHE4pVQd$Vtg>_N_5~!>>-dv~ zVh|DyP9?g-UTcoCJxxl(a`TF7m~;{Z3I>5oJpeaA0uH?(!37h72{cxR`D^mq()?WH z7%L(7ciGA_WBDQYpWYQ+a||2p6YgPAZE0Qz$P zT)ztLUj+;bfx!M9L-v1S2nNM(*SGY_*2i}Vc%7cJr3bxT8O`(o4}^UTxk<5m$YU5C z<9hCo=?5g7Tm?^xr{RWs`8c2H;qE6`dVhr2+X_umNqx)f-KKdmPf&Xzg>hdcDn7#< z-?87c!T80t_i+*BS7p;ji)RAcJARW#M z!wUxN6jwgK`P=ukyKU=y4YyQ!!MsPW9@Qy<1pEgn>Q2%4q#!DQXa|sSh$jMZLKO;0T|MpGs5go6BO7#Rwhs*#{$W~ z;t4A8X84xi1qJ@E);3*Uc#lKffW&)fF=llHZYx1z z?o{s3%au2|Dqm3YZuz4p8yeoQd2j2udD`W=J$CfrT- z$P%6@$XL`Q+6^AdrKKG1#D^kpsy*95*)$zLV=|P2 z7LG5yY%l6DKW39H{OxEhwXx!>lFm>8Stm4ozEQw94CNS~!~3-8S*3sbWEmy1Qrzfh z==4O?1pV4?>@l`(PqnN{!*H~7u$lVzz57xn`9coeo5YC`J%@ETTP{reQay`v@+p4c+aPm@X>#L$LFH%9>yu=c=h>yUTpuIz9L%j$VX{YstzNV z>?=K71LOyO3*AptuSI?+;lfM8OM~CB#%wvVo$+oBP0nPyFQ2n?o_*+)`yFuiYv>nA zcKu7lu7$axnqvCnjB<)VY@$Lu_>!^mVnlRvNrIAIsenO&lWP3GV5em7D^3{-Q;3);Z>qT77pOyy{jh_fS$TZS$b u4@@?=E&ZB|K{kvQz|2P;QButFKAVMbDNfKUfmMn*m^@K#0 zB6*RLy(ElvIGpQzIM+Gv^`1}9_4_@~^Xhd zWvUxLCzM;cB=iWN7*<{rHja%kM%HFzt5}Mw^RTG2~(-Eu6boV&lROFh8u#vvd#Hh0fYiZIAweSGT z{jTcBb>w?PRA9}fueiAHT#CF1zn;)52PdVW>ui*?9Kx4$`M@$W>wZr_Vy&jX!$34byw0geYtU=O zak{HPaZq+vVFjD!0D*!*;9?KJ4G=#@N}K~G0OPB#4D(mxwW0dC$TF6Mv#0`+kCg$5 zleG*?2oNCi;oN3Hqy#2}b&^ql@sWsm-?AkSzyhvcz^o~EUh;}^nIC{Ls4zh+wF!~B3Dpr0*UcZIVvvQ9pARwu*IBfP@H-; zAToNQ*~tAACT)OZVY{eX=epx^o-9p@g^`~b*O1kW^fbjA+Z^_%1>t#pwhBvM-~H|9 z%KesAp1M2A-C*v6H&1F5L45xGB(xKyB35(}Vbvx~JL74}Cfj0>VTBmHUN=*@nzA@* zGoEXz$p*}glS(7Gp9+?fZmd)U%L4;yGy2%wNfUY2&*kxy$dN!IFn@|dxE;R1e@UMA zyOqx)sju&Lt(zJir^Bg@wl^O^ab;w5LBj;Y}iNb zvM}$A7aAgAdh-%CgZ1}({L<2=@$zm9M^Tljjc&gj7!fUg?;gDLJ|gZN$kea7a2FNm zOf5^?YMpPKlYZmPit~$AS<*iF)a?a{sj<`tb;rvzaUGpZt zos(BPwIae{?#Q)vb&vMyC~?eQs70vN?7hJb8(P zc4U$SC`@7i1qyo%g@7Rt1ZchE=CkbOE%E>21rS9F1A@m$9cz!vTLT3E8eZyHv^&ln zz+i#Xg6t?1fJOmGbwCZHer!<8aYSPO9sm0I|2eX%p@*VaQwm;HtW!yPYbW4Qv6iKZ z>WKEV*YYZ$$H`e$u3*>37;)~d>jpI6dNk(*qF_ZfR{bjZu( zTN?80edJM(|LniI<#SnU2kR7lxcqWAC#H8sM**d9;G?)MS%c+I@|7B_0&)X?gzhGw ztA#!lao{E3#lat#qcA3<(R&NZ3Uat*J?_sAS28}0lW^=+ctup{}1Z3R??adCQa+Xx=v zIA$Bno>`=dOX6Mg{xDQR2vl{+30gDqMYZ_E8p~285a);HH}qV}9vQB2TKF{>fUFr! ffT@oTE`y0YIo*7EAyK22emnVt^pc0!Rc=P$^>I zARSz!7>YEdNLlL884zhAJ+y({eVDUnpZ4jV`#bmEb05C*fwZbyI#s7DuAaOJ9EU?~ z<&*ABK+-c)bZmbTGt2TX#{@DPUX446selNX= zhY@a)BkzLjM@!~ljC)E6F-UVOL(Xf|&xEl0&<4Dg|R3(S>w}QtOpntQ|;4%;@Ar z-pofFHLChE=}CQ2z<{Icl+(Ab!J31!Q!;MJQC zUeq4ZbMG~Pc`S@ui0cbDBi?+-uZ_XCT@G*+rV1f=vVWo=rX~^0zBDaE%IE-lc`j@( z8MNGeeja_qKeW1~M{sdQa1%SXgH*!u-{yG6F{X^dB=QFk5k2vKV~!b>&LzU5%b8s! z3yho(wdXSeSbTZ_3wk;g3IRhPqW0ZUFUFH;)I`hAC67QI;s1pVAd8j;B=^aJ z@gYUsG%x_5L089PT?wuL4i6lY6vAKu%zjG15YPmQq!4z$MXUX%1vJnIK;U2*fq;^X zjL@fnQ~y3CPoo1knj3({Vz5*U8h=e4@1};kMh5^ionr2%$Mm0)ccC6_ASM1Be z46V&VtnRa196DT0>;jBvKX##mEX^3%#+>o=8tG%~z4m0F*y4?}#;JE}^>(Fy4hL9&&OXlQAkX z;<{2F$&|BSeG#l4KjA!X`Hz%&_}z?*-=T4_`Qq%|R9<9EWslMlI-1P>4*pW>{5Apk zV!)er)d~J$+0Gleb8q;$KlV9j!0b)~E0F8?C;hgsVE@~be-|l%ItF4y@$p+fH1smwleygd-BRrT5^4BK@rO@J#o;w5`l*pC zYd+mG9c*`SbKq#eErw01sBTE8%cVaC6Um0kS)z|J8SQ;=+TmKr&& z_(RM3`!Od`pQ%YnsQ}a^472bO<@tqy zrLc1D%YNgx;!3km&`c1@mF5Xn{B6D^BYAT%-@2~!CYxv?fXQA4hk4|UWH#f*Y>vMQ z(5g0~hu<6|stAr|N3xim-cG=j0L%2&-DPoG7392?d!oWb`=*t{rsc`7;)}%7+5x|G zW*y!oKA?T+T#y}JfBlENOkN|)Jg`rf7zqPicm+US+sG$L+6M1Djm=;3!&rb-Y!w&i z30wt@S!1|9lO~I{(O^Iik+|a&4s4R|c*rC2GZAkLP|pE`HcZ zg*v?#oEKY0{Yl;ls=VI*q}*-KiMOp(y6AW$?bR-_3j;I-Hkv+Q9Z{{~MhB!iEIN8qNjJ06~T?|>u5;9X7oTj2iw#uHY zM;vR7C88)xk1W^ja1`NK%6_@`{?WaEocq`3dB4Bk=kt92cs(!350P>lmlNXe321Ha zE%){{H9OUsH#1>hrzR%Ewfk@hoLx%w?hOm)SSn%~U?Ii<7OedV90rBK4nsO>-G$zs zZ)09fNcAnZD)$7$1cXn=y1gaUeqJy%-?qMF&{W?C%eSA|Y@V^bTadPk^zYv5+!}lm{Rgs&g9$zRtWdW*Kz=>f^z`fxzBkRA^|GSK{e%Is$Z#>W zjUMJV?6HUQ9%=Agih7iQ*ae)dPv`DsBNlbsKBxATrQCLD&Ma1+^&R)N6WpjNHB&_C zWh`YFEaQ919*$+JS1-f}C)&+`Db%Hs?Lk4b?TZ2lM*-3+Zcr=6o3By%c%f2vuKMt{ z>JjJG{3`LTI4MlmW9On1x7yQ$%ZjE6?MRQO`Mn+dhEJG8>s`&M6((ywkZeA6pH1_p zIW2#lU}+h1l5&3nrBiJqf^xWd!Td|41kSrN_I1q~>r~uEQ`k%A)hzPQ&abFEXdt_K zy3(e9HsG_Sv5b*;FU4Q_8GJmDv1ektBW4z(D#Xwt4`hiizHNbB-m(M~;LiVuDA&Gp zNjowo5>-`twxV|GZOBD3B|?hikgpoMg&v3w75bRC2m6(G%uVwtnkXysC`*NdYzlhj zpEn>Gb!L_!c&*>Ds!GFsbtT>W7 zUYYciS`zz!^d*s!R(l1|>)2Xe;c#Ql<}wQ z2zpcAWTA=IJ*-eyYIP-#z;lyJS@|}zuv_%HP32@BJDR7KzGNaXl~>mzbM4yI)7#-C zGnNYc7G|f#`@!I)3QD`S$b6>l*;Xs3A%24+xlvWgIN4UeWO`9K$sQC7*>F=!G_8NkYP=B2y4w67VJdGP}Hev+TF2h3ykAY?Wd% z$P>xC;O$m7AJLhGQ zjh+3Xi*uqI;QS6+1r)wo;CuJlj44~HYzP(CpAMWb?EQ$ zlLH>(bj*4yt^VjXzdq*NioX7D!3@=Y&%$r#zh&DuQE%Ly9WcK~?BjY}$!VDt89NnA zMVbOEq!GY^YyR7F64Vczw8?Zjjc5I)@)tG8B7FrfO3JSQZXUtr2)qVbN zlRH591|}Q-wBJ3U$71tBiHvOx5j7Ywu~Ov(nWp%~{&GJ2Ia{wF8d0ffBd6QE>etck z7uv&VtdHu}r|Ab5tViB~q>#)?EDCL0Ij^N~J2s3#J8BL4oUP?`n;Wc)E5%fwbb&48pOoEm6BNjBso;~NHv zrxPuwZ5DllZdWS?dYe0S9BV5lNK$~BkkyeUWeZv5!uz=O=y?|n@h;YSeG1cw(nX4T zrK_i&ckAH*@t(C`q|uAsp_?jM8EJ0Nfc8IFclnPEgiEzYGuF?L%+&0Hr_G$6ZCDfd;SA-+7OfO>?V-5;=n}jM2)6~ zfT@rn%dj?9IN$eo##JT3=N(h}T1N!dqf_*X#ZIafg*JcPvFP<$TdR6k9_ltK<{~99 wT#$K_r$AhYJA$WkU&JY;&l%P~IPTr!J1Z<;;$#|s`xBhr_HNB*G&5Z2pA-2+=>Px# literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-0042-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-0042-0 new file mode 100644 index 0000000000000000000000000000000000000000..57302ad8e75a8c2898102bc1d11dcf4e59249fa0 GIT binary patch literal 2 JcmZQ@0ssI+07C!( literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00646630-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00646630-0 new file mode 100644 index 0000000000000000000000000000000000000000..4ecce85e86ad0359d442be5e2439e79615a5ab7c GIT binary patch literal 1975 zcmb7^c{J3G8pmfdO!j@x7RmaXVaA$W#vp4%O!nmxEhJ2q!5~5=*-6sydb2dfC1kxJ zjVwj-A|-oC80+xXJ@=1$?s?C>=l=Da@ArA0|32pf^7RKaG*B8|C?wiP8||;9>Ej0g zNHoSv1A_vH5Lti|j!+_DNjsciFqj1dB|^ACKl>99A_NSg2+iXyHv(s|(p#6;ls_?n z`aOY1npNYM?~LH~ZJvtQH)A*^qvtkhZlHOmkc5nLQPf0TN-V7LjGdTH_g2V2e@Mhg zYG>>1VSO+C8x%%N7AQ~K;wi4$&Lg!?2*tGXn{;q(PBgQ(inmK5db*EzTRKOW`+h%y zP7!r8#rtYLJ?auYNj`p41W?aE7S*{37lm9AvhSHYc;aY73V}Y>|jZ2o5ZN6 zTg}_82VcMYcj>DEShoR*m-T2tC!jfeYr0DoCn{TgAH|4Wb64c16B(^}p>9re?c2RN zx(byk`R_6JY(rv<+eben%as=w;=y74OT_Gsva^U<)oI0%g_dJ>wVB=tf$7+Ftf-l> z$mE#27&|5XnpSj(?Lkj{><03!DJryKD^OB0a6VH}OwdT=g^QcY@Kp}t_zkYwj_2Qt zzrv#{Dy~4Yv+4xNM-TT?GTX-GHjrs9_vI(K{DmJveJ|nRg`3Wy{LI@k1>qV6 zpbu8JUJ|1^g1`7h%CJ%gKI^OS!5Oi6y1#QO$=5`5?=W$r{@dHMq525?45zyge2P+% z{NN_SgKNH)5a>kav>y3X`8DG$ldDXpTjT_8{}2wdRn(a+iSL=~)Lx*xTh1asYTB>SM%Bg5yIT zqxb~RbAL=da50mw;>qweTKA@m@mU<~e1c{7$B4hJ(sC)Mw!GeHn#1#iwWku8_f_MP zbG*$v_L{a?i%crAPKU%MOtzYNpU}*v6Koup3>!UnJ{=CJzIrDsvh>t*$9KtDz+o+9pAyxZ{jmMWq(ME z)%Fo>qTU-}Q(z$VQUFrsD4j2SA&z-Jt8U{4>O5HSg6ucH+zuI?Ro&gh_$&mEaD&gS zWwTG3@5(?`Y8j>jq#hgV?i7(>f@Xhl>Q=b%en3!m&WyRD*Wz(pZC10_4;N-kThN<( z&;5__`-gJ0br0V1QiJIgsT=JJ&GWLa{Mj)e@c}#c|rWvq+mryVYBhT@DRH7v2NwQQJds zTe%4OPW3i}qO!qNmEg)E4G>u*03sCj5DEc9APCS#*Yzg_E8CL)!3!Xc6a|ETA_ZgN z=keD;0f3I5Hd@0Q;|*w{fs?|VC={T90+8B(mZr9wFsJ6vh(!M@{`cqq<;c3GKB961 z1-z!*sFwcPNyw*WJzpKw7Z-tqa^yK!iC6)C+`?T~~b#VJcC4pQm zVSGqGJsvmCxb_=+f`ivnZQF_{GtxQOH1&P&o^*MUkaPD2ZhTnZc@5510FyX5Qh9Vm z(}?E$d}O%X;bO7l7Y{8~@9%tS>-R|F;#?ut@j2lIoy#ven+^23_VllJT6$WwtMi*L zs2FA{Os&BOEc`dS6y-{6P5JiU^J%Ai3|`v~xTv>_c1t)~dA?Ve*gtEagi<;TP~MPk zKntb^$_&*3MWNp!_fj?LMLv{snM=Vd!r!qbY`U_Y@o$YxC$rsG$X`6qPCw;+2i*M{ z`bCP};1aHDezvr(jPW>!LJ&wyRZIq7GErHGiEqv*!p`Y=M$^pu4Uc7KcowlEwx zkplRRQj*eyB%`8Z)EwbD?ikLQSFVmp=U?}KH(ZGeRre?iTQ>_twFM+u$djZHXNMOy xjXbIzn67i%1T~p}?3pcqWq<)DmnD9TzI8C1{*R=@Tm_KNUpewG75M)+@=sAyUabHC literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00820081-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00820081-0 new file mode 100644 index 0000000000000000000000000000000000000000..3d4a9d30461b4fa79e0cd5c7dd86e122041bb9a8 GIT binary patch literal 361 zcmZQ*VrXmb|BqhMWz$Bs2B&EQ>z{mih7{L?^RFn6y1IAB_J3L5{LwW02WXLH$Re4QsfiMM~IEYifu(mUeL-%!4Fog*VBR~LXd9+b0nRFhYPh zBmhJ}m%}|Q0HkNE!)+5lY2zt}+wO2D2=&A6l-c$tRSxZTdN*+Ax(`ZSdk(JFMCLrS zS~AvL^D7+-0p1e#=k42)xLQcoOjwyXh1auwN$-u@4W;3mjMsK+j(w;odeVF&*8g~? zTf^IKTOLP+==~b2Y#*hz^=`RPU6XcVKmy&qaTTAM*YLV;w(7~99{!%m4PTw`2%PWl zVHxOzIDYsBw#0v))`&F`C$*L7j&j{6^)N4_7E)s%6242>N}r1^zg3m-UQok zQMyZEP08C@v@LNR4||H4|36{OV1tPfOa{b$Z=9CJLw%^5i%jXH5HaKs#1MyTNCFZB zgvf>MJiIiaO+}FeQi}RxOzNoq{mC@7S~Ls=+Y!rMD4{czBAG(0kfJO-ZBQbGOrh7y zjagD7Es+=v$d}KNBP7C~qfO*2|H@)P+WZ~J1TJ1-{BP>?^>AWWv`7S7BspzRJy zNA7GV$4LnI>_{YZB4Yt%x^Stysd%>eorAyX_@SciT4Z!>R421A0g)i$=jAQ%Q zE}?8l!ESaIF-m6)0>Q>F2@=0ip)vR(R*nRw2&FXB5MtYG7c~hSH z{M_*D{QT@3Iy|#4pW)esMgj&P-@hKrEhH$;i6y&40hG{d){Z+f<}_RCFW>W9YgqsF z6;r+H(CM>le0U3gIzIdnK&IMSmdO4@KF2?@j>5?R^^OR8Gmb!O$sB?OtmZc`z-H7K zltc-iEALenLf`@kN*Gvpv{lTF_19^2k&_#P^L*>8+ipi%IaS-W1vO&JOshGDMUc2G zSk1B6!9~GpPGu96y(U=AnrGgNFPBUJNKN>Iis0O`iwkNpc6-0k{c{S#88OPz$;;x* z)Y2ubzP}U}5W=u8+KZ;0SoCA6XRc;b2#+^SbFl|(2-*iGUXk-x-itS-!(RLd?&3bT zPa|C3?3U20Ulx^=vPaaOtGo4YC1aqG)L=vsiCB^;7RmGqnNcp)(^w?3h)hX@*e)5d z1c}86MTq4{f+ZutP$Yi_|BD)5Ehf(Vntj{L&tLZ5@A1BV+*C#ENN%Z}=-ZGcE=J4)EBNuQ-o;fPX>1n?|@mQ6ivrdmPk&j(S11L|5_h{p+ zgf740Kz@(%%B&+EYd7a5^hbX7;XrCI@+{{0FReUuBxFYP)=944ymqed|7c;Q+wW)hH|^b27@%}ooD_b2S!Cp8@!kPD9;7@z zl^-o0J^Ze%cWdrtIWOC;B*#7rt_g-ntak%gqPm-vm4%3kEx4*!PVe|$Q#5%S$mt9X!u@+wlu$+Q7wet$zS4t6h@- literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00820081-2 b/trusty/keymint/fuzz/corpus/keymint-rsps-00820081-2 new file mode 100644 index 0000000000000000000000000000000000000000..3375a2ed2b51f2287f3f6ed4c541e0ae421f079d GIT binary patch literal 35 qcmZQ*VrXoVaBOU4PIJ%CPtQqZXv_<7bye_At@O>zD^Un>6afIqCkr9~ literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00820081-3 b/trusty/keymint/fuzz/corpus/keymint-rsps-00820081-3 new file mode 100644 index 0000000000000000000000000000000000000000..41359daa920c61f783ed04039e818eecc6e548a4 GIT binary patch literal 381 zcmZQ*VrXm5*o-New^*u>b|BqhMWz$Bs2B&EQ>z{m)uSfE@sAlHC_fmxD~0nFf# zNNAEOU|`h$3Z}jTDFFtieM}%prh`%pOiB;H%tKNP%wkSp<~b=wlZ|J=%=2Jogu?6v z6Z$*~UwfUFPkHxj&pW3V8tL)fXQclK-&nO|bMn<00gMblmjE#gTxfP)$jH1P!fg8c zEyl@4xkv6DGkayUn%ybSvFUruUxulnOA|uMm;Jic>J h%+E)StW5*p&nAhK#wMu*2By8zK;Lwz$m}}b007IPaHs$P literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00822180-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00822180-0 new file mode 100644 index 0000000000000000000000000000000000000000..0ebe5ae8dace6d7a4554f84f78ace3f4ec798d67 GIT binary patch literal 4 LcmZQ*QfvSK0!#rU literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00822280-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00822280-0 new file mode 100644 index 0000000000000000000000000000000000000000..a797c202958f3db872e8ea9e04579a43c55efdb4 GIT binary patch literal 4 LcmZQ*QfdGI0!{%X literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00822580-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00822580-0 new file mode 100644 index 0000000000000000000000000000000000000000..3691795bd35941db25e2d1c37b50193e41ca3aaa GIT binary patch literal 4 LcmZQ*Qf&YL0#pGg literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00822680-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00822680-0 new file mode 100644 index 0000000000000000000000000000000000000000..dd5cbf34592140814e1f4f3f39aca7888ab24acc GIT binary patch literal 4 LcmZQ*QfmMJ0#*Sj literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00822780-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00822780-0 new file mode 100644 index 0000000000000000000000000000000000000000..4b7906058171da80e2c2e73e64e06a09fe150b82 GIT binary patch literal 4 LcmZQ*Qf~kN0$2em literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00822880-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00822880-0 new file mode 100644 index 0000000000000000000000000000000000000000..e7eab4c84210ae0367faa5956bde1cf08808d9bd GIT binary patch literal 4 LcmZQ*(r5qx0$Kqp literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00822980-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00822980-0 new file mode 100644 index 0000000000000000000000000000000000000000..0072b55be09fe7863335185b2eae54149968a89a GIT binary patch literal 4 LcmZQ*(rf?#0$c$s literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00822a80-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00822a80-0 new file mode 100644 index 0000000000000000000000000000000000000000..9a60d671b997bec53d36b2c9ebb600d55b64ec60 GIT binary patch literal 4 LcmZQ*(rN$z0$u?v literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00822b80-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00822b80-0 new file mode 100644 index 0000000000000000000000000000000000000000..88cba547f3954291e78cd5f51f9fd738b52c7d02 GIT binary patch literal 4 LcmZQ*(ry3%0$>3y literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00822c80-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00822c80-0 new file mode 100644 index 0000000000000000000000000000000000000000..deeb51ffc5f3727ee5b2259d05fdd948d2133ea0 GIT binary patch literal 4 LcmZQ*(rEwy0%8F# literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00823080-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00823080-0 new file mode 100644 index 0000000000000000000000000000000000000000..15f1535a0dc9c4bf8b2ad383de2467e062b5d955 GIT binary patch literal 4 LcmZQ*GH3t*0%`#> literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00823480-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00823480-0 new file mode 100644 index 0000000000000000000000000000000000000000..291df50d62f5b8bb5f364fb948e166c67037e43c GIT binary patch literal 4 LcmZQ*GHCz+0&)R2 literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00823819-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00823819-0 new file mode 100644 index 0000000000000000000000000000000000000000..75cefc85325794579a78a04167f4fefa3fbfa88f GIT binary patch literal 5 McmZQ*vXE>500Un+a literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00823840-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00823840-0 new file mode 100644 index 0000000000000000000000000000000000000000..4f73211b9d03c345426520a8161ad488197ad770 GIT binary patch literal 5 McmZQ*vT$es00XrFdjJ3c literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00823841-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00823841-0 new file mode 100644 index 0000000000000000000000000000000000000000..eb9bc2a47baedc75c15ca608d1bd733ac8645337 GIT binary patch literal 5 McmZQ*vT$qw00XxHd;kCd literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00823846-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00823846-0 new file mode 100644 index 0000000000000000000000000000000000000000..8f404308315c25d03981ee4ee657c2ec20385606 GIT binary patch literal 5 McmZQ*vT$nv00Y4RfdBvi literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-0082384d-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-0082384d-0 new file mode 100644 index 0000000000000000000000000000000000000000..242516ed5d32d4e91e665832c5773af82c1a3455 GIT binary patch literal 5 McmZQ*vhZyH00YkfhyVZp literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-0082384e-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-0082384e-0 new file mode 100644 index 0000000000000000000000000000000000000000..72f293019478922a0721ac077e52d033a3f47cf4 GIT binary patch literal 5 McmZQ*vhZsF00Yqhi2wiq literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-0082384f-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-0082384f-0 new file mode 100644 index 0000000000000000000000000000000000000000..7cb67c34ba15b518004641b03651ebf23508f164 GIT binary patch literal 5 McmZQ*vhZ&J00YwjiU0rr literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00823850-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00823850-0 new file mode 100644 index 0000000000000000000000000000000000000000..25251ccbe66c0319b503dd89b0e6d361a27ab3f6 GIT binary patch literal 5 McmZQ*vIuAZ00Y$livR!s literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00823903-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00823903-0 new file mode 100644 index 0000000000000000000000000000000000000000..42e4206fc368ea46822bf0a312571d5dd3ccde0b GIT binary patch literal 6 NcmZQ*vSfbV000Hc0ww?e literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-009a81fa-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-009a81fa-0 new file mode 100644 index 0000000000000000000000000000000000000000..b5ffa781a03325ab3c429608ffe2e28f731c5c38 GIT binary patch literal 1975 zcmai!XH=7E8irFrAQVk#Do7U?&@cIt5D*pt5dtG^0!*j|63_ucw@@V+F@i<~4boHy zMWl)_R1HPi2ukrFWf24hhM^CL(g$|;hr2&!e?8~E-}gM{`Ei{Kk`}j7Q|`c->Kkee zK3XzH(iW2&U$dW0sN?Gyv_I!=@SUFBdg7K@CG0{{?uaVGP?l>)lHD0*Z21M>l(sl3 zViI5>#sC(q{Rtcfg~1L&I%+%*ygA#-yqu8gS7uY@4TuYgXvbT|e-Vd5#gGs{ABzG+ zh2V||6beo;H^*uL$M+Kwtwd)4c)AY&f;fedNtT?zAv3mcBf3q57(Dbnc5{`riyu2B7eSkzDd3)>mc;S5*Am~E}SkUZm z4}~Hja2E6qWUo(vv7m8~QmK@BPIu>)C9?`{_vXX-dKmDvgzdKN2 zEyw)i^gsNrTQ(VFMU(pp17y+RB5EuBivO_JF3xwP-g_zfQ37HIaIrm^vzv`r)bp54 z?JG^W?bei8q%rL`=IbE5UR`3Lgfhrj$}n2S_mn;y&DN-zj}=LDm;zI%OT}A*!f5-K z`BKh8q}SY#7L2bzv*Pi5h5k&{!7a5zt}S_$l3npKn6AgJg~xBSr-_snP7>OYUQhFS zI|TKAU=nS2v?f-Vthpev<-~n9Er8~-Jo|~IW6DX&`2mzowT}qlb8|xl7fA`6x2GIy zn>5#`xb?;>uUuEN$UnNirt+Xc?5fEMyZ-6GSuImJ6Ukmmfb28)SP)~^%zj(kB3A7H zLx((&CAs*f85X>04Jg80{~1xHd-0-fWNaj=vgCAm&BU9q^JGed49O`^Ep8J%5EFjj zL*g#%Iq#^4)>AZ5Ui49xDhJsZ@+=^CKsx%=G($M5-wXzaLZEzafCeb+(V`%MkU?M+ zOS8Ubx8X;G*9;pvd$p(QTs1;~WBbpl2suFJ8m6-3s-GU(A^xJf`u2?c!+05`C%S;- z{s%M^x{E*p@Vx;@>=%;z1p*F(A-=_6k5@Pg28BGDt1!##MD+Iw|8%_Yw4lg4ui{uX|Xrw#4RAE`jH9IA!JQ)cj6iTdS&e zE<1*&p1x!zHIZA}BNr8Q`Q+Bs;wfuIK{K<{>fK=IQaPnvS9C7Z{&b6t%aEYnncSeJ zY?^FuSUkC?lH>@Ahpl_4Cz^T`xPwgPYY)fBUHRfxz%I`z_L{Y`&pY1K%s3%oLy0Mj zFAiL|8O$zg-zfcMVt(tm8(X!A4Dv*C&v`nRe|F6=Hi&dia($^*?L_5rA|6OBWV=<` zukL_O5aUDU8mBg9Ug2q+hF>Z7TFS$RWR0Dr%N6ioQi1K27E9<2)1#%)c^T-=5azIj zh2Sj4F}ZG|<=pToqfryz4`zr93*$D@rlOvxoSM=mF5&I>;a(Cnan#0<-!L#Ma(v7{ zmf;zfv7zLZIreTkWaa&ddF;WkxQ5PtvBep&b#QJQtqO`<&iA_;HD%70DIG$^_a}vZ za_853R!EGkSur&HC6uAo?_Kcq?AL6^ zM(WSErw1(W5&O74m-x-oqN69`s7P~wg){+JaIJrPPKx@TlQy1Cr}1omt+)m0x&A-c z07tO$fb1Swdt#IF(ce>+K7&L6y@*}_p738HBVvi)ifljrjmZA5BUvz&Z%_G`$Y7Ft zB7=#-_EFB4ne-qpUl_GiTJ@a!ZhRXkTgPPMpZ0qu^jK}2E0(jbCZYx-KCM)`Kqe{v zaktK1eZe-!k3m#u*&WtzTJ`T}_Yd#kG}J|R8`2Cz^VcHpKvGB+#a0D&?wmFm+_oKK z(1BXbK4Wiv&F*K`dAA-fvQxM@eQ5_i%rf8}X)7GhZj@I{-hG!2ys*iU*Z)yS9u^>D z-~4Gak7h*D5lIcQq9hv&kT>fGi6;}SC+!yfLT*af+3Minc0 zm4f@YwU{|KP023ST3rg$h0;Zeeywkyk$dCe0P&u!f27IF-l6NNSs7^_(7^WJS$74G zjYLXxM>Kn;YIem=e0==@GZM3CDSyU9Zm`eouvmU#uwI0}?PhaX%rf@98IJjU^@4)J zg-NdFVd>Lyubf?Ux`R-x{!ob$LG4n;yif$69{|65r&Kz5=gGzmZhgP%GWMo(@*mJQ zO`drV&}lVgEc~Kl!cgas&{|B2L6Nw& wdSQ6emu;(FpUmD6X8>mD5Y3p`*)mjD0& literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-00b5ae79-0 b/trusty/keymint/fuzz/corpus/keymint-rsps-00b5ae79-0 new file mode 100644 index 0000000000000000000000000000000000000000..c5f085ba23e77b85214287991aebdfe13862b209 GIT binary patch literal 1975 zcmbW1cQo7!7RRTN45N=8iJFLn{H7}5=?tPpnMbr?kUSnqkOUKD^oSA@B}x)RJEE6W zGfEOAL5NkK?h&2nqb>V(&)KtQ|JuLqx!-&4J@=2#`GBg5ecj}FZinBql{#7wObO=` zeJcxaFheawc);Kj7!v?JEdcvjz;PD9pb!WQU}J{MgcHJd*}z~{CJ>Yg0fSyI#kQ{D z1|2-JH~Y+N>U0$#B2D@)Q9nO}=4sCOKCcW9!g+)X|HONLtI5iQe5<11M1|F8^VHf$ zfKtc7#%5$}_6QU5zNpw`q{i9<=AEYU@%dwE^X4rnSF%F-PunpbhKS}$bJDlbi*?0D zk8*HHc0$RUdvhztg>9cDWO70RlBCksH92Q;>Usqzl*cy?eT(J{F49{)zUuc3d##t7 zx686DXPByeGO`|_HxTujB*ipnrpiULYvKtO7&h;HJE>?5y8>H`hgeX`q+VAZn?7)o zWEmJ_Ky>Lznp>F0J!6P^oWmA*u0}lwDQ#zzRL`s&Ua<+0c&~>^V#zVICzfyDd8ex6 zPfWPeC|P4^6&vZ7$hn$jQ)Rk!jIji%a%*3{$yoS+B}F!Mn!or|?lZ!#O5`mU!D12$ zjGufWfFm?6lswH%=lS~3V^mj{u7k9o)iXXBj^0$6PH%FWGAs97{Y%dA^LjZ0YjO}TGo>zw9Vy^lQhs~zuXFn%R9K~>j3N80_#3z`G`jX z1Am<77EhVe4&f^qL4*$^cum=6H`rIQPj2RX*Q+C1h^y?5{1!DmhHk*U*ZWKxoGXXSHHZ`glf0|=u80sd36U`#xmE{bRXP;^$nVI1*}02T*a*NdoC>)-I!J`2xMEpNr0soU=4$x`N0y#rDk8jpaZ{zL+L3GQ0`P%dmP`Z!I z!sZXyKkL%D>t0qEcm6IA?_SrGC&pK0sVK`u!};X3@)eSLG9DxE2+VHkfS+F;gX z&Fx{#-$d`b60AEed@jZDngcc7TVu`Q`hwyGFVQ;z%Qn&+UDTcWWDjfeE`_Hb6_qaM zM5GMiUl_alt2g$Igh^zkr`mx%+ka5w>2Flv#j<14y>qoEta9TY2a#g|YXm_pb%EjU zHbSg<(GTSP+>H-fO9M7g{hDZxvaP!!B6nwFrGbWL(vIIUB4Qf`BsNe{MA{hL3qPFC#4J zB7P;D8%vID3>QmVP_0kAc9bOq+XDg_0Yw zD;O?PX`Okq+j+@qytVpTx73u(5-y$yfr3HcY$t#Oh@5$k9mWSk{!dR{IvY#C1OUDu zB%U+{qC_&mO{2Bkbx(wDbu1cl|6d{v+p4JjC{YpCjC8&-aeK$Jf1#J=3hwZo^m#-v zd&{X76zrh$$7m8!ODdo9IazJZG4DIK?!oRfEWX`exIbT>m|0Q#b+>xTj?=R-l5+G? zHZUx~QJcPBy?riCBRlSjdqD7Ty_O>jHol8uX!b+3(qYe5B}kkS3Jc2BEen#@Qd1JC zp%V|r`I*x@%w!g3dVX79ifLHpu6!c<5zKYinN@ZTgmn8t!B|rZLxq39P3VF&NwOY7 zs=+YP1m1nWa-w)S_Q&_zgK2t72w--Qk{7`Bj=zBNV5!hs8t9UrP{-|$5~Nut3nHii zeI9ne91B(dk>4h-g*4BKiEEPBOwYcF&A##Fkcyjxt13Rf^yQyFCOjj5>01>Z-+l9k zs8Dem)zEiHjSv9?-FOW^-k6D|@LL2Py^Jf_@Io7br7gr)ofGL|ic3m+Awh9)PX02d zCktBB*uTF4<;y+S>%X;G(9-bN~rzG5e3{;4$?;Id&-qBVN-aE5Pw{qJX;ar$~Yr%8RSleV)pY+*`hF1z#c@8)#a_w~CjO4+#G7|`c#FQ+v6^{9rv=Fwc2~I+@bVNVwMlu|59j ziV&cQudmY_LbE8krnZcX#qfN;Z?}u6$==e9fq^z3N24#REISFGUoLBRR^g#=RoO>ApWNqDKXu^;mJn{N5HJ6A~ax%6Itxq4wF%z` z3RCU9JvSG}5QK*{gl#A zx}`|WtqFsR-xXVZ3bwvzPO7XHyFcs@GVD~_N2MjL(WKJiolEySg)gizBW#8%f2<-5 zWnK2{4wi9&e_y~_yE3{H((6V0e^|U9n7g{BRj~I!RpTK22i2eR=Z~(9v19zTGkkvE z?zM}zlT!lXGKy3O3)0MkZgjY0kRIqVxg%2P8)_0&a1L1ZDW>`~mprZE@d-&y1=r%f>SAv|FKv|HZ*c zIEZqXw@q@)yeVV&a_*9&*Zj59M3iAu^U&yY*W%asdDRcm{?lbL6Dv*q*}Mij^)uM^ zk<+&;6GnnH$p;URmV>lX1#A%ORyLCTg7w+c56$k?<>6ELFy8MOra2SujsJn`cpZ@T z>eX;omTXRkvLo|Mxrw~RJ$CjTh~=U6*J@^MnY=|qrC8MU|MzUAl06a55CvfmQD99K za2N=K!6ZGPlP9>9Z&=;f%T`VlnN|54_;t)b<5(D(mSY3>+ z7KA4d1N9(XtS*6|6NJ|aB5G;|1wtq>J{<@`AD&})iSz3n0*%o;yjVS~o)?5dpN6E4 z(!qH}0%Br_S7T6@h$IvtBp@_0G%^^4hA5yM#P`2?Kn?&-0r`Q$cODo81c82>%~l^v zqDRivcR-|U3?$SnylSe8-g8Qq?N&M0pS|{hD{k@nFSfNL!`lM1mOmANQ&pBE}3m9kI$Kk-KjT;vZKyyEGgGYAQCDmp(}x% zeHnGCy#6&4n<>ePc-rVCXTy*@1{0;SVK?ti_{ul*ZhL-rN2_zD9|k|%u2tk6h`b4% bI_#u0KL{Qm5O5d_0r4Mcp(D)!!NLCk8ZcTG literal 0 HcmV?d00001 diff --git a/trusty/keymint/fuzz/corpus/keymint-rsps-01820081-1 b/trusty/keymint/fuzz/corpus/keymint-rsps-01820081-1 new file mode 100644 index 0000000000000000000000000000000000000000..37f4af5a520e1c33084fcada68fdb95d3397b40e GIT binary patch literal 1975 zcmc&#`8(8W8~=W17|U3)#w3lUl=V9cW^fELWlJ17h9cX9$v$>EF&b&4BB`Sjlar>B zJ-g79DBBou2u;yWmK=NKOy29g-ap~}JokNlKKJLop69xMdTx*bq%joI(mh3E7yvVk z0cJB$+W-ItGEis$0Ac?j_!fx*TZ9nyAOL`?iVJHO0O&#iARzQ20dQsM=WST4umJ(E zM<@WM`FcxoQ2<=oW=r;=Kzvp2mh9h>6tuG#t!7)Q%oB2Ehp(<$HR+cX=!zB5GHkUu zHPfxEvgjGyhP&`=EJ;jWWTx8 z$eAFWGZaxgzK(ZY;;tQm*HTcn5v!K%6||6LRPH;pE9suPnnut*lSr#;3T1KMp8p_z zMSpV3Gwts-JU~g`VC(HJ3>%II`-C~y2g5z=?GoSVs0l$-nB7BcuK!Sq+%!ZZBQo!NX^vH2UL zX`5Yv4?=J21~=Kv{wa2rUipYfZ#a4Q^x2#0l+8YALnj>vPo?8)*H1KV)0Wl+eq>TO zR0Q7LY%kkZ>wu)uLyN&4OU!N7oq{;}&Nq7|&5z&LSeznH%9Y%I2o%?1`PJ8Ta%L-i z^)8uYOjFBRj~<-%Ui+ZUGxkx<<@97>4I*nr=r?3{4okiz5R}ARLJng8Ud}xw$%=>= zO(1x$J;UtTRa$gM&T-L3nfWl}$PKpgY2?f3x34Z~S) zb`NXPiKEV|3&e(pc1H3F^49@lzCoW^Dhp#99)t+`2PLbY;EcQD@s#sm;8J}8DXVOF zHH~kTIKtU1{lwVrfB8O1)5iH;SHR$=gmu%~q@u&=bJ>FO{Q?ITFG6e0j@A{mq$`~` zq$AeZ?r3M*lB(}j33hTx`GRYg3&~8D|Af0euK!t*X{j>O;_=Wmu`aiD6Pa7Rs>mA+ z7h=QT#(Z%*)H$DHJ=_Jjzp6TVtF`twzfwcl(VGLy$L@q^+a1;)4h)x(cR`kDYEE)O zJ>)J~mo}WX(!Tj(|3dT3%-CrI>E4(mISIDHL=@foO)p{2(71P^qGFQ4jULQy9*{q8 z9;WH+75{nh^V-SE2+Baw>)KGo=i0N@E1V-)zr6n39$oykGo#p(p;ipCsSf#L@z@0K zrssP-r!4Kc`8dsSr_?nNkR4A&C!(j z13bkP^*7|FOs$}IuEE8!bl=^!MI)HX&(ev`)+d?aYwc3JRrZ?WIRkt?iJuu)dC@ZY zsu+5~j!X}IDj{y*UuI(SeW}hbaY{8=9sxT=0Xxj&w*4WEQMX}Vau6?L*33JG(CBj+Bz6?%?0&CRK44>b&fNK8Uf{>D8rwY+ zw{L%Z(a@mkQb2fCPkM*UA+nF!2&pXscjnm$zE@HK_o=PNI{Ya_z@8)DY!eCjM)e2{H#P3 z&^W3e5o1ii67Z0J05y;Z5sV1|0j4MX@h7M_+=)O4yY2j z%M+{RdfCf{qS{B+jpE(D!TG_;?Sdh00ZO3);@&;H9i3s~HgNmYM`V)!lgGNTT+#BY ztsL3>6|YybE)8;r79aio&2^J}?MhS%%htS+e{=tilf%g46>K_vB3Se;Ip8YHB8mHUKby0YHFT3I@QPFZ&x|o!kNhz@B3O*s+-d z%EAEf!^Q`61OsY39zLL>2b3buT5`Q5AJ*;h``at&&#T8-SxL9jq)>lhRVTwuM<||C zHXy)l%k}?aEY73|gcmv@I+PUFmLdF9J z7jwvnbC6jXM@z^V|KLs@cw(L z24a5d3Y$C)^WJZ}5_OZYIiGuWaZ7tSrv?DN>jbz)`jWMaNxop9J|D`%9@~2!_C6~Q zjXc|9)Tf`5jZ>b(G|pO3;iQ=>d~@Q!!v?=Ad45*$p=(sV?I-^7(6(sY&4uc>s7skA zo8PAY{_y*l1kC1%1zHoJxXqRucbNv2PKz}&5H#0?F}JwZ_^uwh&5@}4Q%9@QK6K!o z@!cT$EB`hfSjX;+-3aK^t*BJvP)0|F_#)sD8Ar5&f*T=$tlQ& zd>0mrKg=R4nQv5Ie*}`K}`(6Ip9I-ACsbVC5E^7R4XxX6m!>%R)beM&)V;8yM6E``H4z z`0@#kRc=9}OBaQsAvc81Y=9}cdZO+sMog|pP@3v9**<#Rf5(6A9?(L&FHfEcH-}I^ zQKRP8jTo-=tl0L~l{O~x#L24`_)NCi*v5Uei}m_R5UKulWw33=RHJMa0PcD z8~Gp}81_uEsQYMU7gZ&s*&Umk6M*Jd({!=mOnF6U%Jr4Z$gU*o1dTs^aUiSSZUZ9Zq_PLKr!gs}y z^orxJZnW0;8tr6`&H?_ zo~jdUmM`h)2ltrNs8dd-RAhoZ&t!TOw<_p~UZ2RF9zr&W;W~QzD*K%5@)zUnzjSnl zeN)tRUrlEj#@ygcvENewQQO%X^~I3y#V$EPvtvF&|#D`C;0mq{Ifk{Yj^ z9+rI*k$oHEX_VR=r88Kk=lqUQ5H-#p(OyPo2F*TjTpyI&g7 z5C#JQNC3%ql3~W!5duL0NE;^z@gw16grFeY-qaMQ3Mua^9tnAMFE?!*fruw+K<*x1 zp4t$RK=km?@^;to_EJ~(_Jri6gtQA8n;R#vb;Si+F58d)W4+}n=(F-34oXZO8ItSmj~#58FGQ~z zvfB!RbPRQicRp`b)lP+Aun22RxTc%d`kzgBrE`ITPK>WC@{#5{7o)bdYul+Wfsplj ziJf+}-m`lVV@#f`H}ck(l?IuK5{6TqYik|%T4Uf%@j$)6qHXy(o%ZvY_KbFV_;rT9nEgyf@e?y3Lz3uen8gpf4`fT~#+2!GrE*sfwEAUbZ z-U&Z44SK#!M&mZ$Yu8hpp2N(nU$&>E)G8tK+xwddP4nq-BOqebmdhCydEP5twv9CD z3EP=So|AQ*dEAKE(pJq3+j%_T@!4;6{7>k{C%w5EjFiVaj$vlNuTPu98fIBm6p_4T z_CVkZ4v0RIjYdxS~KxLYRQsuXZ%)g!3&O$x$o)D>v7ZdPxcwYNW1g&qOOFP~e-LcK+CH>)f$?2IJkwgq0O-z&yNQ7q0Rk7)jjX_)m!8bo?NPxRg^@VEf>4$#=Vz=@%|SbxO~yEyo!XFQOHWa!S~;abA6_g2IVEjBYVnMincn6MiD=uBNyb>8~%`it*hGIY!}X%~XZ^SX$R;subh!X;)%5 z!xhJv&WdA+>=NTZJj)Dsn%2daz3V0OWWn}VTA0j?_bv#~m`BvB4E9SSDukqAI+dkr zH(Iyt#0Jyz67Lmuoxk~LighE=xLa$#>ZFbLre>GxDY=v52PoZk@q8lP-+EASkrtN` z&#ccmp*GJxp{4;MQhn%(FSu$#X`%+AokGT#$u<+WZ=u*A4eg*55edwFrmkd%eqjh< zecaPeha^mVreR){O>Vw8dD-A)JHw}DAR>9pB}XbCL@#-?=U!<>g%I+V^&fq9S5=sM zF#?@qcld;rQc2jsgwwZ2Ud~I%nEhSWh6U1xR{SGRFH3C~NVnDG5|64|XO9ci+chgU z^!K#9Qt%fX!6hY1Ttm2hb$cSkN#JM81Y$`Ybv8len|98)&oKKtS$e?b7@Pk*ZDgOi<{9V7jhkA4t@-q@E#@z7pW$pr zDIcF*hDA`ClYDZ>r!VxWMV0EC96GNZU2)%TV2ULoB_T|{1v$yHBXTAb35 zIfxy5y5oz=U$T}E7MpN)2Cbf@f-B26nfB|Ee1)?eso_tP3jcj0q}7<~2+1J;@k zhk-B{A3w=F1`-w!)JiZ**b)UnVTgbhfrJF$4tydaaC=izv?iqfL-9+Zu)dxIv>qOV z*M+>ieSHWJUJvi>jq~%;_4CDI{d^#lv?vaO&^$YYtBg2-2Q&uDb3K9{!4*K=SWu?b!N1;s5s_G@w+FjTD{fSe{E8-vDPfPd#xZnTq&=v zaZ#++e1Vgyb88{VF;ZOs_w}N4T7B~6EMmY~`=ryHPc%PGMedE3*S9To=1XR0n2u;^ z?iqgFOYufa7$@xk0X=Sr{JCE0x}CxW2iqswWdys$;V+~TTf+1?)Cm8c?7~FRB%`9+ zq;Ps>gkt4n{7*O-so3~@air4xBe_seVYrLD8B;ghWT;kbc>fCc8n=dqOsJJaPyRfuLy%k4=u^l{{h)uVNn18 literal 0 HcmV?d00001 From 32dcac7851284cad16c0ce25e60cd1f5273dfc0e Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Wed, 15 Feb 2023 16:23:46 -0800 Subject: [PATCH 0052/1487] Support ZSTD in userspace COW Perf: Lz4: Update took 429 seconds merge time 35.4s cow size: 3.18GB ZSTD: Update took 676 seconds merge time 49.4s cow size: 2.62GB Gz: Update took 1057 seconds merge time: 50.0s cow size: 2.55GB In summary, ZSTD is a middle point between LZ4 and GZ. Speed: LZ4 > ZSTD > GZ Space: LZ4 > ZSTD > GZ Bug: 274129758 Change-Id: I203bf088b7c2a9ce429f75478799da0e7126febf --- fastboot/Android.bp | 1 + fs_mgr/libsnapshot/Android.bp | 1 + .../include/libsnapshot/cow_format.h | 3 +- .../libsnapshot_cow/cow_compress.cpp | 20 ++++++++ .../libsnapshot_cow/cow_decompress.cpp | 50 +++++++++++++++++++ .../libsnapshot_cow/cow_decompress.h | 1 + .../libsnapshot_cow/cow_reader.cpp | 6 +++ fs_mgr/libsnapshot/snapuserd/Android.bp | 1 + init/Android.bp | 2 + 9 files changed, 84 insertions(+), 1 deletion(-) diff --git a/fastboot/Android.bp b/fastboot/Android.bp index 7794c4b464fd..56cac88d3828 100644 --- a/fastboot/Android.bp +++ b/fastboot/Android.bp @@ -196,6 +196,7 @@ cc_binary { "libfastbootshim", "libsnapshot_cow", "liblz4", + "libzstd", "libsnapshot_nobinder", "update_metadata-protos", "liburing", diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index 3dd1f1ac4a3c..d3bd904dcb00 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -163,6 +163,7 @@ cc_defaults { "libbrotli", "libz", "liblz4", + "libzstd", ], export_include_dirs: ["include"], } diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h index 6baf4beae733..c3ca00ae034e 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h @@ -157,7 +157,8 @@ enum CowCompressionAlgorithm : uint8_t { kCowCompressNone = 0, kCowCompressGz = 1, kCowCompressBrotli = 2, - kCowCompressLz4 = 3 + kCowCompressLz4 = 3, + kCowCompressZstd = 4, }; static constexpr uint8_t kCowReadAheadNotStarted = 0; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp index d06c904ba884..a4a0ad661823 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp @@ -29,6 +29,7 @@ #include #include #include +#include namespace android { namespace snapshot { @@ -40,6 +41,8 @@ std::optional CompressionAlgorithmFromString(std::strin return {kCowCompressBrotli}; } else if (name == "lz4") { return {kCowCompressLz4}; + } else if (name == "zstd") { + return {kCowCompressZstd}; } else if (name == "none" || name.empty()) { return {kCowCompressNone}; } else { @@ -112,6 +115,23 @@ std::basic_string CompressWorker::Compress(CowCompressionAlgorithm comp } return buffer; } + case kCowCompressZstd: { + std::basic_string buffer(ZSTD_compressBound(length), '\0'); + const auto compressed_size = + ZSTD_compress(buffer.data(), buffer.size(), data, length, 0); + if (compressed_size <= 0) { + LOG(ERROR) << "ZSTD compression failed " << compressed_size; + return {}; + } + // Don't run compression if the compressed output is larger + if (compressed_size >= length) { + buffer.resize(length); + memcpy(buffer.data(), data, length); + } else { + buffer.resize(compressed_size); + } + return buffer; + } default: LOG(ERROR) << "unhandled compression type: " << compression; break; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp index 3d34413eaeae..da90cc048169 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp @@ -17,12 +17,15 @@ #include "cow_decompress.h" #include +#include #include +#include #include #include #include #include +#include namespace android { namespace snapshot { @@ -336,9 +339,56 @@ class Lz4Decompressor final : public IDecompressor { } }; +class ZstdDecompressor final : public IDecompressor { + public: + ssize_t Decompress(void* buffer, size_t buffer_size, size_t decompressed_size, + size_t ignore_bytes = 0) override { + if (buffer_size < decompressed_size - ignore_bytes) { + LOG(INFO) << "buffer size " << buffer_size + << " is not large enough to hold decompressed data. Decompressed size " + << decompressed_size << ", ignore_bytes " << ignore_bytes; + return -1; + } + if (ignore_bytes == 0) { + if (!Decompress(buffer, decompressed_size)) { + return -1; + } + return decompressed_size; + } + std::vector ignore_buf(decompressed_size); + if (!Decompress(buffer, decompressed_size)) { + return -1; + } + memcpy(buffer, ignore_buf.data() + ignore_bytes, buffer_size); + return decompressed_size; + } + bool Decompress(void* output_buffer, const size_t output_size) { + std::string input_buffer; + input_buffer.resize(stream_->Size()); + size_t bytes_read = stream_->Read(input_buffer.data(), input_buffer.size()); + if (bytes_read != input_buffer.size()) { + LOG(ERROR) << "Failed to read all input at once. Expected: " << input_buffer.size() + << " actual: " << bytes_read; + return false; + } + const auto bytes_decompressed = ZSTD_decompress(output_buffer, output_size, + input_buffer.data(), input_buffer.size()); + if (bytes_decompressed != output_size) { + LOG(ERROR) << "Failed to decompress ZSTD block, expected output size: " << output_size + << ", actual: " << bytes_decompressed; + return false; + } + return true; + } +}; + std::unique_ptr IDecompressor::Lz4() { return std::make_unique(); } +std::unique_ptr IDecompressor::Zstd() { + return std::make_unique(); +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.h b/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.h index 9e83f3c5cf68..52b3d7671261 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.h +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.h @@ -47,6 +47,7 @@ class IDecompressor { static std::unique_ptr Gz(); static std::unique_ptr Brotli(); static std::unique_ptr Lz4(); + static std::unique_ptr Zstd(); static std::unique_ptr FromString(std::string_view compressor); diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp index 4c5a8bf5ff5e..6749cf1b0363 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp @@ -30,6 +30,7 @@ #include #include "cow_decompress.h" +#include "libsnapshot/cow_format.h" namespace android { namespace snapshot { @@ -777,6 +778,11 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_ case kCowCompressBrotli: decompressor = IDecompressor::Brotli(); break; + case kCowCompressZstd: + if (header_.block_size != op->data_length) { + decompressor = IDecompressor::Zstd(); + } + break; case kCowCompressLz4: if (header_.block_size != op->data_length) { decompressor = IDecompressor::Lz4(); diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 1e03683e91ee..9fe567acbc7e 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -112,6 +112,7 @@ cc_defaults { "liblz4", "libext4_utils", "liburing", + "libzstd", ], header_libs: [ diff --git a/init/Android.bp b/init/Android.bp index 7b529033a968..41c7a953abc2 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -169,6 +169,7 @@ libinit_cc_defaults { "libfsverity_init", "liblmkd_utils", "liblz4", + "libzstd", "libmini_keyctl_static", "libmodprobe", "libprocinfo", @@ -370,6 +371,7 @@ cc_binary { "libprotobuf-cpp-lite", "libsnapshot_cow", "liblz4", + "libzstd", "libsnapshot_init", "update_metadata-protos", "libprocinfo", From e556021b5295f6a7b6041eee98990f6e4a92c84d Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Wed, 17 May 2023 17:37:38 +0100 Subject: [PATCH 0053/1487] Set IMEI in provisioning helper Borrow the code from AttestKeyTest.cpp (in KeyMint VTS) for determining the devices IMEI value(s), and use that as default value. Also update to use the newer provisioning message if the second IMEI is set. Test: provision a test device Change-Id: Ie8e183dc50ac9107c2c2c2966c591e8b6022fd20 --- .../set_attestation_ids.cpp | 146 ++++++++++++++---- 1 file changed, 118 insertions(+), 28 deletions(-) diff --git a/trusty/keymaster/set_attestation_ids/set_attestation_ids.cpp b/trusty/keymaster/set_attestation_ids/set_attestation_ids.cpp index e944167fad4c..6b8f90fa46b2 100644 --- a/trusty/keymaster/set_attestation_ids/set_attestation_ids.cpp +++ b/trusty/keymaster/set_attestation_ids/set_attestation_ids.cpp @@ -17,8 +17,10 @@ #include #include +#include #include +#include #include namespace { @@ -34,14 +36,66 @@ const struct option lopts[] = { {"model", required_argument, nullptr, 'm'}, {"imei", required_argument, nullptr, 'i'}, {"meid", required_argument, nullptr, 'c'}, + {"imei2", required_argument, nullptr, '2'}, {0, 0, 0, 0}, }; +std::string TELEPHONY_CMD_GET_IMEI = "cmd phone get-imei "; + +// Run a shell command and collect the output of it. If any error, set an empty string as the +// output. +std::string exec_command(const std::string& command) { + char buffer[128]; + std::string result = ""; + + FILE* pipe = popen(command.c_str(), "r"); + if (!pipe) { + fprintf(stderr, "popen('%s') failed\n", command.c_str()); + return result; + } + + while (!feof(pipe)) { + if (fgets(buffer, 128, pipe) != NULL) { + result += buffer; + } + } + + pclose(pipe); + return result; +} + +// Get IMEI using Telephony service shell command. If any error while executing the command +// then empty string will be returned as output. +std::string get_imei(int slot) { + std::string cmd = TELEPHONY_CMD_GET_IMEI + std::to_string(slot); + std::string output = exec_command(cmd); + + if (output.empty()) { + fprintf(stderr, "Retrieve IMEI command ('%s') failed\n", cmd.c_str()); + return ""; + } + + std::vector out = + ::android::base::Tokenize(::android::base::Trim(output), "Device IMEI:"); + + if (out.size() != 1) { + fprintf(stderr, "Error parsing command ('%s') output '%s'\n", cmd.c_str(), output.c_str()); + return ""; + } + + std::string imei = ::android::base::Trim(out[0]); + if (imei.compare("null") == 0) { + fprintf(stderr, "IMEI value from command ('%s') is null, skipping", cmd.c_str()); + return ""; + } + return imei; +} + std::string buf2string(const keymaster::Buffer& buf) { return std::string(reinterpret_cast(buf.peek_read()), buf.available_read()); } -void print_usage(const char* prog, const keymaster::SetAttestationIdsRequest& req) { +void print_usage(const char* prog, const keymaster::SetAttestationIdsKM3Request& req) { fprintf(stderr, "Usage: %s [options]\n" "\n" @@ -55,34 +109,53 @@ void print_usage(const char* prog, const keymaster::SetAttestationIdsRequest& re " -m, --model set model (default '%s')\n" " -i, --imei set IMEI (default '%s')\n" " -c, --meid set MEID (default '%s')\n" + " -2, --imei2 set second IMEI (default '%s')\n" "\n", - prog, buf2string(req.brand).c_str(), buf2string(req.device).c_str(), - buf2string(req.product).c_str(), buf2string(req.serial).c_str(), - buf2string(req.manufacturer).c_str(), buf2string(req.model).c_str(), - buf2string(req.imei).c_str(), buf2string(req.meid).c_str()); + prog, buf2string(req.base.brand).c_str(), buf2string(req.base.device).c_str(), + buf2string(req.base.product).c_str(), buf2string(req.base.serial).c_str(), + buf2string(req.base.manufacturer).c_str(), buf2string(req.base.model).c_str(), + buf2string(req.base.imei).c_str(), buf2string(req.base.meid).c_str(), + buf2string(req.second_imei).c_str()); +} + +void set_to(keymaster::Buffer* buf, const std::string& value) { + if (!value.empty()) { + buf->Reinitialize(value.data(), value.size()); + } } void set_from_prop(keymaster::Buffer* buf, const std::string& prop) { std::string prop_value = ::android::base::GetProperty(prop, /* default_value = */ ""); - if (!prop_value.empty()) { - buf->Reinitialize(prop_value.data(), prop_value.size()); - } + set_to(buf, prop_value); } -void populate_ids(keymaster::SetAttestationIdsRequest* req) { +void populate_base_ids(keymaster::SetAttestationIdsRequest* req) { set_from_prop(&req->brand, "ro.product.brand"); set_from_prop(&req->device, "ro.product.device"); set_from_prop(&req->product, "ro.product.name"); set_from_prop(&req->serial, "ro.serialno"); set_from_prop(&req->manufacturer, "ro.product.manufacturer"); set_from_prop(&req->model, "ro.product.model"); + std::string imei = get_imei(0); + set_to(&req->imei, imei); +} + +void populate_ids(keymaster::SetAttestationIdsKM3Request* req) { + populate_base_ids(&req->base); + + // - "What about IMEI?" + // - "You've already had it." + // - "We've had one, yes. What about second IMEI?" + // - "I don't think he knows about second IMEI, Pip." + std::string imei2 = get_imei(1); + set_to(&req->second_imei, imei2); } } // namespace int main(int argc, char** argv) { // By default, set attestation IDs to the values in userspace properties. - keymaster::SetAttestationIdsRequest req(/* ver = */ 4); + keymaster::SetAttestationIdsKM3Request req(/* ver = */ 4); populate_ids(&req); while (true) { @@ -94,28 +167,31 @@ int main(int argc, char** argv) { switch (c) { case 'b': - req.brand.Reinitialize(optarg, strlen(optarg)); + req.base.brand.Reinitialize(optarg, strlen(optarg)); break; case 'd': - req.device.Reinitialize(optarg, strlen(optarg)); + req.base.device.Reinitialize(optarg, strlen(optarg)); break; case 'p': - req.product.Reinitialize(optarg, strlen(optarg)); + req.base.product.Reinitialize(optarg, strlen(optarg)); break; case 's': - req.serial.Reinitialize(optarg, strlen(optarg)); + req.base.serial.Reinitialize(optarg, strlen(optarg)); break; case 'M': - req.manufacturer.Reinitialize(optarg, strlen(optarg)); + req.base.manufacturer.Reinitialize(optarg, strlen(optarg)); break; case 'm': - req.model.Reinitialize(optarg, strlen(optarg)); + req.base.model.Reinitialize(optarg, strlen(optarg)); break; case 'i': - req.imei.Reinitialize(optarg, strlen(optarg)); + req.base.imei.Reinitialize(optarg, strlen(optarg)); break; case 'c': - req.meid.Reinitialize(optarg, strlen(optarg)); + req.base.meid.Reinitialize(optarg, strlen(optarg)); + break; + case '2': + req.second_imei.Reinitialize(optarg, strlen(optarg)); break; case 'h': print_usage(argv[0], req); @@ -144,19 +220,33 @@ int main(int argc, char** argv) { " manufacturer: %s\n" " model: %s\n" " IMEI: %s\n" - " MEID: %s\n", - buf2string(req.brand).c_str(), buf2string(req.device).c_str(), - buf2string(req.product).c_str(), buf2string(req.serial).c_str(), - buf2string(req.manufacturer).c_str(), buf2string(req.model).c_str(), - buf2string(req.imei).c_str(), buf2string(req.meid).c_str()); + " MEID: %s\n" + " SECOND_IMEI: %s\n\n", + buf2string(req.base.brand).c_str(), buf2string(req.base.device).c_str(), + buf2string(req.base.product).c_str(), buf2string(req.base.serial).c_str(), + buf2string(req.base.manufacturer).c_str(), buf2string(req.base.model).c_str(), + buf2string(req.base.imei).c_str(), buf2string(req.base.meid).c_str(), + buf2string(req.second_imei).c_str()); + fflush(stdout); keymaster::EmptyKeymasterResponse rsp(/* ver = */ 4); - ret = trusty_keymaster_send(KM_SET_ATTESTATION_IDS, req, &rsp); + const char* msg; + if (req.second_imei.available_read() == 0) { + // No SECOND_IMEI set, use base command. + ret = trusty_keymaster_send(KM_SET_ATTESTATION_IDS, req.base, &rsp); + msg = "SET_ATTESTATION_IDS"; + } else { + // SECOND_IMEI is set, use updated command. + ret = trusty_keymaster_send(KM_SET_ATTESTATION_IDS_KM3, req, &rsp); + msg = "SET_ATTESTATION_IDS_KM3"; + } + trusty_keymaster_disconnect(); + if (ret) { - fprintf(stderr, "SET_ATTESTATION_IDS failed: %d\n", ret); - trusty_keymaster_disconnect(); + fprintf(stderr, "%s failed: %d\n", msg, ret); return EXIT_FAILURE; + } else { + printf("done\n"); + return EXIT_SUCCESS; } - - return EXIT_SUCCESS; } From 52205b820693b74fb2b33beef2f4cd4ba63cf738 Mon Sep 17 00:00:00 2001 From: Frederick Mayle Date: Thu, 15 Dec 2022 16:08:52 -0800 Subject: [PATCH 0054/1487] debuggerd_client_test: less racy test setup Make sure that all the threads have started up, otherwise the main part of the test might not be testing as stressful a situation as expected. Note that the "race" moniker is still valid because of the debuggerd timeout. The test is now faster (405ms) when run under good conditions. Test: atest 'debuggerd_test:debuggerd_client#race' Test: Ran debuggerd_client.race 1000 times on its own. Test: Ran the whole suite of debuggerd unit tests 1000 times. Change-Id: I487e7654a71df9f1799f09c6f385c929ddf2f234 --- debuggerd/client/debuggerd_client_test.cpp | 30 ++++++++++++++-------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/debuggerd/client/debuggerd_client_test.cpp b/debuggerd/client/debuggerd_client_test.cpp index ebb8d86e0bce..33ff05fd6ace 100644 --- a/debuggerd/client/debuggerd_client_test.cpp +++ b/debuggerd/client/debuggerd_client_test.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -51,23 +52,35 @@ static int getThreadCount() { TEST(debuggerd_client, race) { static int THREAD_COUNT = getThreadCount(); - pid_t forkpid = fork(); - ASSERT_NE(-1, forkpid); + // Semaphore incremented once per thread started. + unique_fd barrier(eventfd(0, EFD_SEMAPHORE)); + ASSERT_NE(-1, barrier.get()); + pid_t forkpid = fork(); + ASSERT_NE(-1, forkpid); if (forkpid == 0) { // Spawn a bunch of threads, to make crash_dump take longer. std::vector threads; + threads.reserve(THREAD_COUNT); for (int i = 0; i < THREAD_COUNT; ++i) { - threads.emplace_back([]() { - while (true) { - std::this_thread::sleep_for(60s); + threads.emplace_back([&barrier]() { + uint64_t count = 1; + ASSERT_NE(-1, write(barrier.get(), &count, sizeof(count))); + for (;;) { + pause(); } }); } + for (;;) { + pause(); + } + } - std::this_thread::sleep_for(60s); - exit(0); + // Wait for the child to spawn all of its threads. + for (int i = 0; i < THREAD_COUNT; ++i) { + uint64_t count; + ASSERT_NE(-1, read(barrier.get(), &count, sizeof(count))); } unique_fd pipe_read, pipe_write; @@ -77,9 +90,6 @@ TEST(debuggerd_client, race) { constexpr int PIPE_SIZE = 16 * 1024 * 1024; ASSERT_EQ(PIPE_SIZE, fcntl(pipe_read.get(), F_SETPIPE_SZ, PIPE_SIZE)); - // Wait for a bit to let the child spawn all of its threads. - std::this_thread::sleep_for(1s); - ASSERT_TRUE( debuggerd_trigger_dump(forkpid, kDebuggerdNativeBacktrace, 60000, std::move(pipe_write))); // Immediately kill the forked child, to make sure that the dump didn't return early. From 59abbfe64706a7ea0c4e932ae40bc8bde9746dce Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 16 May 2023 15:53:57 -0700 Subject: [PATCH 0055/1487] ueventd: Fix a race condition in handling device-mapper events. We've had flake in libdm_test for a long time, with no clear cause. Lately however it has become particularly reproducible when running the UeventAfterLoadTable test in isolation, and thus we've identified the root cause. uevents for device-mapper are fired when the sysfs node is added, but at that time, the "dm" subnode has not yet been added. The root node and dm node are added very close together, so usually it works, but sometimes ueventd is too fast. Instead of relying on sysfs, query the uuid/name node directly from device-mapper. Bug: 270183812 Test: libdm_test Change-Id: I258de5de05d813c3cb7f129e82e56dbfe8bf3117 --- fs_mgr/libdm/dm.cpp | 19 +++++++ fs_mgr/libdm/dm_test.cpp | 94 +++++++++++++++++++++++---------- fs_mgr/libdm/include/libdm/dm.h | 2 + init/devices.cpp | 18 +++---- 4 files changed, 94 insertions(+), 39 deletions(-) diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index deffae1ad6fe..1e8c14fe2c01 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -243,6 +243,25 @@ bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* pat return true; } +bool DeviceMapper::GetDeviceNameAndUuid(dev_t dev, std::string* name, std::string* uuid) { + struct dm_ioctl io; + InitIo(&io, {}); + io.dev = dev; + + if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) { + PLOG(ERROR) << "Failed to find device dev: " << major(dev) << ":" << minor(dev); + return false; + } + + if (name) { + *name = io.name; + } + if (uuid) { + *uuid = io.uuid; + } + return true; +} + std::optional DeviceMapper::GetDetailedInfo(const std::string& name) const { struct dm_ioctl io; InitIo(&io, name); diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp index 788cf5174853..c522eafae058 100644 --- a/fs_mgr/libdm/dm_test.cpp +++ b/fs_mgr/libdm/dm_test.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -42,16 +43,40 @@ using namespace std; using namespace std::chrono_literals; using namespace android::dm; -using unique_fd = android::base::unique_fd; +using android::base::make_scope_guard; +using android::base::unique_fd; + +class DmTest : public ::testing::Test { + protected: + void SetUp() override { + const testing::TestInfo* const test_info = + testing::UnitTest::GetInstance()->current_test_info(); + test_name_ = test_info->name(); + test_full_name_ = test_info->test_suite_name() + "/"s + test_name_; + + LOG(INFO) << "Starting test: " << test_full_name_; + } + void TearDown() override { + LOG(INFO) << "Tearing down test: " << test_full_name_; + + auto& dm = DeviceMapper::Instance(); + ASSERT_TRUE(dm.DeleteDeviceIfExists(test_name_)); + + LOG(INFO) << "Teardown complete for test: " << test_full_name_; + } + + std::string test_name_; + std::string test_full_name_; +}; -TEST(libdm, HasMinimumTargets) { +TEST_F(DmTest, HasMinimumTargets) { DmTargetTypeInfo info; DeviceMapper& dm = DeviceMapper::Instance(); ASSERT_TRUE(dm.GetTargetByName("linear", &info)); } -TEST(libdm, DmLinear) { +TEST_F(DmTest, DmLinear) { unique_fd tmp1(CreateTempFile("file_1", 4096)); ASSERT_GE(tmp1, 0); unique_fd tmp2(CreateTempFile("file_2", 4096)); @@ -127,7 +152,7 @@ TEST(libdm, DmLinear) { ASSERT_TRUE(dev.Destroy()); } -TEST(libdm, DmSuspendResume) { +TEST_F(DmTest, DmSuspendResume) { unique_fd tmp1(CreateTempFile("file_suspend_resume", 512)); ASSERT_GE(tmp1, 0); @@ -156,7 +181,7 @@ TEST(libdm, DmSuspendResume) { ASSERT_EQ(dm.GetState(dev.name()), DmDeviceState::ACTIVE); } -TEST(libdm, DmVerityArgsAvb2) { +TEST_F(DmTest, DmVerityArgsAvb2) { std::string device = "/dev/block/platform/soc/1da4000.ufshc/by-name/vendor_a"; std::string algorithm = "sha1"; std::string digest = "4be7e823b8c40f7bd5c8ccd5123f0722c5baca21"; @@ -178,7 +203,7 @@ TEST(libdm, DmVerityArgsAvb2) { EXPECT_EQ(target.GetParameterString(), expected); } -TEST(libdm, DmSnapshotArgs) { +TEST_F(DmTest, DmSnapshotArgs) { DmTargetSnapshot target1(0, 512, "base", "cow", SnapshotStorageMode::Persistent, 8); if (DmTargetSnapshot::ReportsOverflow("snapshot")) { EXPECT_EQ(target1.GetParameterString(), "base cow PO 8"); @@ -200,7 +225,7 @@ TEST(libdm, DmSnapshotArgs) { EXPECT_EQ(target3.name(), "snapshot-merge"); } -TEST(libdm, DmSnapshotOriginArgs) { +TEST_F(DmTest, DmSnapshotOriginArgs) { DmTargetSnapshotOrigin target(0, 512, "base"); EXPECT_EQ(target.GetParameterString(), "base"); EXPECT_EQ(target.name(), "snapshot-origin"); @@ -330,7 +355,7 @@ bool CheckSnapshotAvailability() { return true; } -TEST(libdm, DmSnapshot) { +TEST_F(DmTest, DmSnapshot) { if (!CheckSnapshotAvailability()) { return; } @@ -374,7 +399,7 @@ TEST(libdm, DmSnapshot) { ASSERT_EQ(read, data); } -TEST(libdm, DmSnapshotOverflow) { +TEST_F(DmTest, DmSnapshotOverflow) { if (!CheckSnapshotAvailability()) { return; } @@ -421,7 +446,7 @@ TEST(libdm, DmSnapshotOverflow) { } } -TEST(libdm, ParseStatusText) { +TEST_F(DmTest, ParseStatusText) { DmTargetSnapshot::Status status; // Bad inputs @@ -448,7 +473,7 @@ TEST(libdm, ParseStatusText) { EXPECT_TRUE(DmTargetSnapshot::ParseStatusText("Overflow", &status)); } -TEST(libdm, DmSnapshotMergePercent) { +TEST_F(DmTest, DmSnapshotMergePercent) { DmTargetSnapshot::Status status; // Correct input @@ -502,7 +527,7 @@ TEST(libdm, DmSnapshotMergePercent) { EXPECT_LE(DmTargetSnapshot::MergePercent(status, 0), 0.0); } -TEST(libdm, CryptArgs) { +TEST_F(DmTest, CryptArgs) { DmTargetCrypt target1(0, 512, "sha1", "abcdefgh", 50, "/dev/loop0", 100); ASSERT_EQ(target1.name(), "crypt"); ASSERT_TRUE(target1.Valid()); @@ -518,7 +543,7 @@ TEST(libdm, CryptArgs) { "iv_large_sectors sector_size:64"); } -TEST(libdm, DefaultKeyArgs) { +TEST_F(DmTest, DefaultKeyArgs) { DmTargetDefaultKey target(0, 4096, "aes-xts-plain64", "abcdef0123456789", "/dev/loop0", 0); target.SetSetDun(); ASSERT_EQ(target.name(), "default-key"); @@ -529,7 +554,7 @@ TEST(libdm, DefaultKeyArgs) { "iv_large_sectors"); } -TEST(libdm, DefaultKeyLegacyArgs) { +TEST_F(DmTest, DefaultKeyLegacyArgs) { DmTargetDefaultKey target(0, 4096, "AES-256-XTS", "abcdef0123456789", "/dev/loop0", 0); target.SetUseLegacyOptionsFormat(); ASSERT_EQ(target.name(), "default-key"); @@ -537,7 +562,7 @@ TEST(libdm, DefaultKeyLegacyArgs) { ASSERT_EQ(target.GetParameterString(), "AES-256-XTS abcdef0123456789 /dev/loop0 0"); } -TEST(libdm, DeleteDeviceWithTimeout) { +TEST_F(DmTest, DeleteDeviceWithTimeout) { unique_fd tmp(CreateTempFile("file_1", 4096)); ASSERT_GE(tmp, 0); LoopDevice loop(tmp, 10s); @@ -561,7 +586,7 @@ TEST(libdm, DeleteDeviceWithTimeout) { ASSERT_EQ(ENOENT, errno); } -TEST(libdm, IsDmBlockDevice) { +TEST_F(DmTest, IsDmBlockDevice) { unique_fd tmp(CreateTempFile("file_1", 4096)); ASSERT_GE(tmp, 0); LoopDevice loop(tmp, 10s); @@ -580,7 +605,7 @@ TEST(libdm, IsDmBlockDevice) { ASSERT_FALSE(dm.IsDmBlockDevice(loop.device())); } -TEST(libdm, GetDmDeviceNameByPath) { +TEST_F(DmTest, GetDmDeviceNameByPath) { unique_fd tmp(CreateTempFile("file_1", 4096)); ASSERT_GE(tmp, 0); LoopDevice loop(tmp, 10s); @@ -601,7 +626,7 @@ TEST(libdm, GetDmDeviceNameByPath) { ASSERT_EQ("libdm-test-dm-linear", *name); } -TEST(libdm, GetParentBlockDeviceByPath) { +TEST_F(DmTest, GetParentBlockDeviceByPath) { unique_fd tmp(CreateTempFile("file_1", 4096)); ASSERT_GE(tmp, 0); LoopDevice loop(tmp, 10s); @@ -621,7 +646,7 @@ TEST(libdm, GetParentBlockDeviceByPath) { ASSERT_EQ(loop.device(), *sub_block_device); } -TEST(libdm, DeleteDeviceDeferredNoReferences) { +TEST_F(DmTest, DeleteDeviceDeferredNoReferences) { unique_fd tmp(CreateTempFile("file_1", 4096)); ASSERT_GE(tmp, 0); LoopDevice loop(tmp, 10s); @@ -647,7 +672,7 @@ TEST(libdm, DeleteDeviceDeferredNoReferences) { ASSERT_EQ(ENOENT, errno); } -TEST(libdm, DeleteDeviceDeferredWaitsForLastReference) { +TEST_F(DmTest, DeleteDeviceDeferredWaitsForLastReference) { unique_fd tmp(CreateTempFile("file_1", 4096)); ASSERT_GE(tmp, 0); LoopDevice loop(tmp, 10s); @@ -682,7 +707,7 @@ TEST(libdm, DeleteDeviceDeferredWaitsForLastReference) { ASSERT_EQ(ENOENT, errno); } -TEST(libdm, CreateEmptyDevice) { +TEST_F(DmTest, CreateEmptyDevice) { DeviceMapper& dm = DeviceMapper::Instance(); ASSERT_TRUE(dm.CreateEmptyDevice("empty-device")); auto guard = @@ -692,9 +717,7 @@ TEST(libdm, CreateEmptyDevice) { ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device")); } -TEST(libdm, UeventAfterLoadTable) { - static const char* kDeviceName = "libdm-test-uevent-load-table"; - +TEST_F(DmTest, UeventAfterLoadTable) { struct utsname u; ASSERT_EQ(uname(&u), 0); @@ -706,18 +729,31 @@ TEST(libdm, UeventAfterLoadTable) { } DeviceMapper& dm = DeviceMapper::Instance(); - ASSERT_TRUE(dm.CreateEmptyDevice(kDeviceName)); + ASSERT_TRUE(dm.CreateEmptyDevice(test_name_)); DmTable table; table.Emplace(0, 1); - ASSERT_TRUE(dm.LoadTable(kDeviceName, table)); + ASSERT_TRUE(dm.LoadTable(test_name_, table)); std::string ignore_path; - ASSERT_TRUE(dm.WaitForDevice(kDeviceName, 5s, &ignore_path)); + ASSERT_TRUE(dm.WaitForDevice(test_name_, 5s, &ignore_path)); - auto info = dm.GetDetailedInfo(kDeviceName); + auto info = dm.GetDetailedInfo(test_name_); ASSERT_TRUE(info.has_value()); ASSERT_TRUE(info->IsSuspended()); - ASSERT_TRUE(dm.DeleteDevice(kDeviceName)); + ASSERT_TRUE(dm.DeleteDevice(test_name_)); +} + +TEST_F(DmTest, GetNameAndUuid) { + auto& dm = DeviceMapper::Instance(); + ASSERT_TRUE(dm.CreatePlaceholderDevice(test_name_)); + + dev_t dev; + ASSERT_TRUE(dm.GetDeviceNumber(test_name_, &dev)); + + std::string name, uuid; + ASSERT_TRUE(dm.GetDeviceNameAndUuid(dev, &name, &uuid)); + ASSERT_EQ(name, test_name_); + ASSERT_FALSE(uuid.empty()); } diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h index dbef8f902b29..3e7ecc645eec 100644 --- a/fs_mgr/libdm/include/libdm/dm.h +++ b/fs_mgr/libdm/include/libdm/dm.h @@ -298,6 +298,8 @@ class DeviceMapper final : public IDeviceMapper { // a placeholder table containing dm-error. bool CreatePlaceholderDevice(const std::string& name); + bool GetDeviceNameAndUuid(dev_t dev, std::string* name, std::string* uuid); + private: // Maximum possible device mapper targets registered in the kernel. // This is only used to read the list of targets from kernel so we allocate diff --git a/init/devices.cpp b/init/devices.cpp index 39442a0e8019..d29ffd604f4e 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -112,17 +113,14 @@ static bool FindVbdDevicePrefix(const std::string& path, std::string* result) { // the supplied buffer with the dm module's instantiated name. // If it doesn't start with a virtual block device, or there is some // error, return false. -static bool FindDmDevice(const std::string& path, std::string* name, std::string* uuid) { - if (!StartsWith(path, "/devices/virtual/block/dm-")) return false; +static bool FindDmDevice(const Uevent& uevent, std::string* name, std::string* uuid) { + if (!StartsWith(uevent.path, "/devices/virtual/block/dm-")) return false; + if (uevent.action == "remove") return false; // Avoid error spam from ioctl - if (!ReadFileToString("/sys" + path + "/dm/name", name)) { - return false; - } - ReadFileToString("/sys" + path + "/dm/uuid", uuid); + dev_t dev = makedev(uevent.major, uevent.minor); - *name = android::base::Trim(*name); - *uuid = android::base::Trim(*uuid); - return true; + auto& dm = android::dm::DeviceMapper::Instance(); + return dm.GetDeviceNameAndUuid(dev, name, uuid); } Permissions::Permissions(const std::string& name, mode_t perm, uid_t uid, gid_t gid, @@ -392,7 +390,7 @@ std::vector DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uev type = "pci"; } else if (FindVbdDevicePrefix(uevent.path, &device)) { type = "vbd"; - } else if (FindDmDevice(uevent.path, &partition, &uuid)) { + } else if (FindDmDevice(uevent, &partition, &uuid)) { std::vector symlinks = {"/dev/block/mapper/" + partition}; if (!uuid.empty()) { symlinks.emplace_back("/dev/block/mapper/by-uuid/" + uuid); From 0fa371076acfc89f6f5de999e92af4d0eccb790a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 15 May 2023 16:43:53 -0700 Subject: [PATCH 0056/1487] libfiemap: Handle EAGAIN in fallocate(). When we changed our ENOSPC tests, it exposed a path in F2FS were fallocate can return EAGAIN. This is expected if F2FS attempts GC to acquire more chunks, and it can leave the file in a partially allocated state. As a fix, keep attempting fallocate() as long as (1) it returns EAGAIN, and (2) the allocated size keeps growing. If (2) fails we return ENOSPC. Bug: N/A Test: treehugger Change-Id: I5f867b5a200b9260e486985f203f9872a949b3f9 --- fs_mgr/libfiemap/fiemap_writer.cpp | 31 +++++++++++++++++-- .../include/libfiemap/fiemap_status.h | 3 +- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/fs_mgr/libfiemap/fiemap_writer.cpp b/fs_mgr/libfiemap/fiemap_writer.cpp index 275388ed9e47..06e210eca836 100644 --- a/fs_mgr/libfiemap/fiemap_writer.cpp +++ b/fs_mgr/libfiemap/fiemap_writer.cpp @@ -458,9 +458,34 @@ static FiemapStatus AllocateFile(int file_fd, const std::string& file_path, uint return FiemapStatus::Error(); } - if (fallocate(file_fd, 0, 0, file_size)) { - PLOG(ERROR) << "Failed to allocate space for file: " << file_path << " size: " << file_size; - return FiemapStatus::FromErrno(errno); + // F2FS can return EAGAIN and partially fallocate. Keep trying to fallocate, + // and if we don't make forward progress, return ENOSPC. + std::optional prev_size; + while (true) { + if (fallocate(file_fd, 0, 0, file_size) == 0) { + break; + } + if (errno != EAGAIN) { + PLOG(ERROR) << "Failed to allocate space for file: " << file_path + << " size: " << file_size; + return FiemapStatus::FromErrno(errno); + } + + struct stat s; + if (fstat(file_fd, &s) < 0) { + PLOG(ERROR) << "Failed to fstat after fallocate failure: " << file_path; + return FiemapStatus::FromErrno(errno); + } + if (!prev_size) { + prev_size = {s.st_size}; + continue; + } + if (*prev_size >= s.st_size) { + LOG(ERROR) << "Fallocate retry failed, got " << s.st_size << ", asked for " + << file_size; + return FiemapStatus(FiemapStatus::ErrorCode::NO_SPACE); + } + LOG(INFO) << "Retrying fallocate, got " << s.st_size << ", asked for " << file_size; } if (need_explicit_writes) { diff --git a/fs_mgr/libfiemap/include/libfiemap/fiemap_status.h b/fs_mgr/libfiemap/include/libfiemap/fiemap_status.h index d7b2cf18ecb7..1365ba4be54b 100644 --- a/fs_mgr/libfiemap/include/libfiemap/fiemap_status.h +++ b/fs_mgr/libfiemap/include/libfiemap/fiemap_status.h @@ -56,8 +56,7 @@ class FiemapStatus { // For logging and debugging only. std::string string() const; - protected: - FiemapStatus(ErrorCode code) : error_code_(code) {} + explicit FiemapStatus(ErrorCode code) : error_code_(code) {} private: ErrorCode error_code_; From 16e08075bad3340832a860d90a959e9e1996a392 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 17 May 2023 23:18:48 +0000 Subject: [PATCH 0057/1487] init_kill_services_test: log state It can be difficult to figure out where this test is while it's executing, so I've added logs. Bug: 280514080 Test: init_kill_services_test (w/o tradefed to avoid reboot), then: :) adb logcat -d | grep init_kill_services_test ... I init_kill_services_test: hello lmkd! ... I init_kill_services_test: okay, now goodbye lmkd ... I init_kill_services_test: I said goodbye lmkd! ... I init_kill_services_test: are you still there lmkd? ... I init_kill_services_test: I'm done with lmkd ... I init_kill_services_test: hello ueventd! ... I init_kill_services_test: okay, now goodbye ueventd ... I init_kill_services_test: I said goodbye ueventd! ... I init_kill_services_test: are you still there ueventd? ... I init_kill_services_test: I'm done with ueventd ... I init_kill_services_test: hello hwservicemanager! ... I init_kill_services_test: okay, now goodbye hwservicemanager ... I init_kill_services_test: I said goodbye hwservicemanager! ... I init_kill_services_test: I said goodbye hwservicemanager! ... I init_kill_services_test: I said goodbye hwservicemanager! ... I init_kill_services_test: I said goodbye hwservicemanager! ... I init_kill_services_test: I said goodbye hwservicemanager! ... I init_kill_services_test: I said goodbye hwservicemanager! ... I init_kill_services_test: I said goodbye hwservicemanager! ... I init_kill_services_test: I said goodbye hwservicemanager! ... I init_kill_services_test: I said goodbye hwservicemanager! ... I init_kill_services_test: I said goodbye hwservicemanager! ... I init_kill_services_test: I said goodbye hwservicemanager! ... I init_kill_services_test: I said goodbye hwservicemanager! ... I init_kill_services_test: I said goodbye hwservicemanager! ... I init_kill_services_test: I said goodbye hwservicemanager! ... I init_kill_services_test: I said goodbye hwservicemanager! ... I init_kill_services_test: are you still there hwservicemanager? ... I init_kill_services_test: I'm done with hwservicemanager ... I init_kill_services_test: hello servicemanager! ... I init_kill_services_test: okay, now goodbye servicemanager ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: I said goodbye servicemanager! ... I init_kill_services_test: are you still there servicemanager? ... I init_kill_services_test: I'm done with servicemanager Change-Id: I2466f574fc06cdf1b01db82f89649f39b0f34345 --- init/test_kill_services/init_kill_services_test.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/init/test_kill_services/init_kill_services_test.cpp b/init/test_kill_services/init_kill_services_test.cpp index 53557032153f..227380d719dc 100644 --- a/init/test_kill_services/init_kill_services_test.cpp +++ b/init/test_kill_services/init_kill_services_test.cpp @@ -16,6 +16,7 @@ #include +#include #include #include @@ -24,6 +25,7 @@ using ::android::base::GetProperty; using ::android::base::SetProperty; void ExpectKillingServiceRecovers(const std::string& service_name) { + LOG(INFO) << "hello " << service_name << "!"; const std::string status_prop = "init.svc." + service_name; const std::string pid_prop = "init.svc_debug_pid." + service_name; @@ -32,6 +34,7 @@ void ExpectKillingServiceRecovers(const std::string& service_name) { ASSERT_EQ("running", GetProperty(status_prop, "")) << status_prop; ASSERT_NE("", initial_pid) << pid_prop; + LOG(INFO) << "okay, now goodbye " << service_name; EXPECT_EQ(0, system(("kill -9 " + initial_pid).c_str())); constexpr size_t kMaxWaitMilliseconds = 10000; @@ -42,11 +45,16 @@ void ExpectKillingServiceRecovers(const std::string& service_name) { for (size_t retry = 0; retry < kRetryTimes; retry++) { const std::string& pid = GetProperty(pid_prop, ""); if (pid != initial_pid && pid != "") break; + LOG(INFO) << "I said goodbye " << service_name << "!"; usleep(kRetryWaitMilliseconds * 1000); } + LOG(INFO) << "are you still there " << service_name << "?"; + // svc_debug_pid is set after svc property EXPECT_EQ("running", GetProperty(status_prop, "")); + + LOG(INFO) << "I'm done with " << service_name; } class InitKillServicesTest : public ::testing::TestWithParam {}; From eb13daf905d2a49f02a71629947f604834a0e08c Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 18 May 2023 14:36:02 -0700 Subject: [PATCH 0058/1487] NetlinkEvent: use isKernel64Bit in KernelUtils.h Now that the code has moved, delete the local implementation in favor of the common one. Test: builds Change-Id: Ic29d7c9bcd3d623204f3e4de3a3434483021cbac --- libsysutils/Android.bp | 4 +++ libsysutils/src/NetlinkEvent.cpp | 56 ++------------------------------ 2 files changed, 6 insertions(+), 54 deletions(-) diff --git a/libsysutils/Android.bp b/libsysutils/Android.bp index 5f472b2abd2c..1b41a6b177cf 100644 --- a/libsysutils/Android.bp +++ b/libsysutils/Android.bp @@ -29,6 +29,10 @@ cc_library { "liblog", ], + header_libs: [ + "bpf_headers", + ], + export_include_dirs: ["include"], tidy: true, diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp index 515cc1047cbf..cd9db54fa6f4 100644 --- a/libsysutils/src/NetlinkEvent.cpp +++ b/libsysutils/src/NetlinkEvent.cpp @@ -37,10 +37,12 @@ #include #include +#include #include #include using android::base::ParseInt; +using android::bpf::isKernel64Bit; /* From kernel's net/netfilter/xt_quota2.c */ const int LOCAL_QLOG_NL_EVENT = 112; @@ -138,60 +140,6 @@ static_assert(sizeof(ulog_packet_msg_t) == sizeof(ulog_packet_msg32_t) || static_assert(sizeof(ulog_packet_msg32_t) == 168); static_assert(sizeof(ulog_packet_msg64_t) == 192); -// Figure out the bitness of userspace. -// Trivial and known at compile time. -static bool isUserspace64bit(void) { - return sizeof(long) == 8; -} - -// Figure out the bitness of the kernel. -static bool isKernel64Bit(void) { - // a 64-bit userspace requires a 64-bit kernel - if (isUserspace64bit()) return true; - - static bool init = false; - static bool cache = false; - if (init) return cache; - - // Retrieve current personality - on Linux this system call *cannot* fail. - int p = personality(0xffffffff); - // But if it does just assume kernel and userspace (which is 32-bit) match... - if (p == -1) return false; - - // This will effectively mask out the bottom 8 bits, and switch to 'native' - // personality, and then return the previous personality of this thread - // (likely PER_LINUX or PER_LINUX32) with any extra options unmodified. - int q = personality((p & ~PER_MASK) | PER_LINUX); - // Per man page this theoretically could error out with EINVAL, - // but kernel code analysis suggests setting PER_LINUX cannot fail. - // Either way, assume kernel and userspace (which is 32-bit) match... - if (q != p) return false; - - struct utsname u; - (void)uname(&u); // only possible failure is EFAULT, but u is on stack. - - // Switch back to previous personality. - // Theoretically could fail with EINVAL on arm64 with no 32-bit support, - // but then we wouldn't have fetched 'p' from the kernel in the first place. - // Either way there's nothing meaningul we can do in case of error. - // Since PER_LINUX32 vs PER_LINUX only affects uname.machine it doesn't - // really hurt us either. We're really just switching back to be 'clean'. - (void)personality(p); - - // Possible values of utsname.machine observed on x86_64 desktop (arm via qemu): - // x86_64 i686 aarch64 armv7l - // additionally observed on arm device: - // armv8l - // presumably also might just be possible: - // i386 i486 i586 - // and there might be other weird arm32 cases. - // We note that the 64 is present in both 64-bit archs, - // and in general is likely to be present in only 64-bit archs. - cache = !!strstr(u.machine, "64"); - init = true; - return cache; -} - /******************************************************************************/ NetlinkEvent::NetlinkEvent() { From 5be6ec751c88726ff809d9fa0b35a587660d36d4 Mon Sep 17 00:00:00 2001 From: Jack Wu Date: Thu, 13 Apr 2023 19:37:46 +0800 Subject: [PATCH 0059/1487] BatteryMonitor: support battery health NOT_AVAILABLE from health status Battery health is supported but there is not enough information to determine an accurate value This is a temporary state. Bug: 276400004 Test: m Ignore-AOSP-First: cherry-pick from aosp Change-Id: I0d422db20c51ef7e9dc4fa904729beda625c9fea Merged-In: I0d422db20c51ef7e9dc4fa904729beda625c9fea Signed-off-by: Jack Wu --- healthd/BatteryMonitor.cpp | 2 ++ healthd/include/healthd/BatteryMonitor.h | 1 + 2 files changed, 3 insertions(+) diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp index 66e1e63ef62e..f68d65a54d70 100644 --- a/healthd/BatteryMonitor.cpp +++ b/healthd/BatteryMonitor.cpp @@ -242,6 +242,8 @@ BatteryHealth getBatteryHealthStatus(int status) { value = BatteryHealth::DEAD; else if (status == BatteryMonitor::BH_FAILED) value = BatteryHealth::UNSPECIFIED_FAILURE; + else if (status == BatteryMonitor::BH_NOT_AVAILABLE) + value = BatteryHealth::NOT_AVAILABLE; else value = BatteryHealth::UNKNOWN; diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h index 7b4f46c8abab..a4c013b86b33 100644 --- a/healthd/include/healthd/BatteryMonitor.h +++ b/healthd/include/healthd/BatteryMonitor.h @@ -62,6 +62,7 @@ class BatteryMonitor { BH_MARGINAL, BH_NEEDS_REPLACEMENT, BH_FAILED, + BH_NOT_AVAILABLE, }; BatteryMonitor(); From 56abaa0959e8cf691d176517b1cea276da01a638 Mon Sep 17 00:00:00 2001 From: Frederick Mayle Date: Tue, 13 Dec 2022 15:40:57 -0800 Subject: [PATCH 0060/1487] debuggerd: simplify output handling Just noticed some opportunities while skimming. Test: adb shell debuggerd $(adb shell pidof com.android.systemui) Test: All unit tests pass (both 32 bit and 64 bit). Test: Ran unit tests in a loop hundreds of times. Change-Id: I428d0cf599ed603a21944b084b95594db893cbd5 --- debuggerd/client/debuggerd_client.cpp | 7 +++++++ debuggerd/debuggerd.cpp | 28 ++++----------------------- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp index c9e097ea35b2..bd1e91d3459d 100644 --- a/debuggerd/client/debuggerd_client.cpp +++ b/debuggerd/client/debuggerd_client.cpp @@ -276,6 +276,13 @@ bool debuggerd_trigger_dump(pid_t tid, DebuggerdDumpType dump_type, unsigned int return false; } + // WARNING: It's not possible to replace the below with a splice call. + // Due to the way debuggerd does many small writes across the pipe, + // this would cause splice to copy a page for each write. The second + // pipe fills up based on the number of pages being copied, even + // though there is not much data being transferred per page. When + // the second pipe is full, everything stops since there is nothing + // reading the second pipe to clear it. char buf[1024]; rc = TEMP_FAILURE_RETRY(read(pipe_read.get(), buf, sizeof(buf))); if (rc == 0) { diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp index e20e8d9e1613..26726cf89747 100644 --- a/debuggerd/debuggerd.cpp +++ b/debuggerd/debuggerd.cpp @@ -41,22 +41,6 @@ static void usage(int exit_code) { _exit(exit_code); } -static std::thread spawn_redirect_thread(unique_fd fd) { - return std::thread([fd{ std::move(fd) }]() { - while (true) { - char buf[BUFSIZ]; - ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), buf, sizeof(buf))); - if (rc <= 0) { - return; - } - - if (!android::base::WriteFully(STDOUT_FILENO, buf, rc)) { - return; - } - } - }); -} - int main(int argc, char* argv[]) { if (argc <= 1) usage(0); if (argc > 3) usage(1); @@ -107,14 +91,11 @@ int main(int argc, char* argv[]) { } } - unique_fd piperead, pipewrite; - if (!Pipe(&piperead, &pipewrite)) { - err(1, "failed to create pipe"); + unique_fd output_fd(fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0)); + if (output_fd.get() == -1) { + err(1, "failed to fcntl dup stdout"); } - - std::thread redirect_thread = spawn_redirect_thread(std::move(piperead)); - if (!debuggerd_trigger_dump(proc_info.pid, dump_type, 0, std::move(pipewrite))) { - redirect_thread.join(); + if (!debuggerd_trigger_dump(proc_info.pid, dump_type, 0, std::move(output_fd))) { if (pid == proc_info.pid) { errx(1, "failed to dump process %d", pid); } else { @@ -122,6 +103,5 @@ int main(int argc, char* argv[]) { } } - redirect_thread.join(); return 0; } From d70a174e95d20788a8fba9795f9562ce601a6d96 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 2 May 2023 09:12:00 -0700 Subject: [PATCH 0061/1487] libsnapshot: Split CowReader into CowParserV2. Remove format-specific logic from CowReader and split it out into a new class called CowParserV2. To make reading the header easier, the version and size bits are now in a separate CowHeaderPrefix struct. Bug: 280529365 Test: apply OTA on CF inspect_cow Change-Id: I29b5617ec094d4fb0c284485883d2e921a5bdbf8 --- fs_mgr/libsnapshot/Android.bp | 1 + .../include/libsnapshot/cow_format.h | 20 +- .../include/libsnapshot/cow_writer.h | 2 +- .../libsnapshot_cow/cow_api_test.cpp | 18 +- .../libsnapshot_cow/cow_reader.cpp | 226 +---------------- .../libsnapshot_cow/cow_writer.cpp | 23 +- .../libsnapshot_cow/inspect_cow.cpp | 5 +- .../libsnapshot/libsnapshot_cow/parser_v2.cpp | 238 ++++++++++++++++++ .../libsnapshot/libsnapshot_cow/parser_v2.h | 55 ++++ .../snapuserd/dm-snapshot-merge/snapuserd.cpp | 10 +- .../user-space-merge/snapuserd_core.cpp | 10 +- 11 files changed, 342 insertions(+), 266 deletions(-) create mode 100644 fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.cpp create mode 100644 fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.h diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index d3bd904dcb00..cba68446792a 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -179,6 +179,7 @@ cc_library_static { "libsnapshot_cow/cow_writer.cpp", "libsnapshot_cow/cow_format.cpp", "libsnapshot_cow/cow_compress.cpp", + "libsnapshot_cow/parser_v2.cpp", ], host_supported: true, recovery_available: true, diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h index c3ca00ae034e..9f9469910dbd 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h @@ -52,13 +52,15 @@ static constexpr uint32_t kCowVersionManifest = 2; // between writing the last operation/data pair, or the footer itself. In this // case, the safest way to proceed is to assume the last operation is faulty. -struct CowHeader { +struct CowHeaderPrefix { uint64_t magic; uint16_t major_version; uint16_t minor_version; + uint16_t header_size; // size of CowHeader. +} __attribute__((packed)); - // Size of this struct. - uint16_t header_size; +struct CowHeader { + CowHeaderPrefix prefix; // Size of footer struct uint16_t footer_size; @@ -88,7 +90,7 @@ struct CowFooterOperation { // the compression type of that data (see constants below). uint8_t compression; - // Length of Footer Data. Currently 64 for both checksums + // Length of Footer Data. Currently 64. uint16_t data_length; // The amount of file space used by Cow operations @@ -98,14 +100,6 @@ struct CowFooterOperation { uint64_t num_ops; } __attribute__((packed)); -struct CowFooterData { - // SHA256 checksums of Footer op - uint8_t footer_checksum[32]; - - // SHA256 of the operation sequence. - uint8_t ops_checksum[32]; -} __attribute__((packed)); - // Cow operations are currently fixed-size entries, but this may change if // needed. struct CowOperation { @@ -167,7 +161,7 @@ static constexpr uint8_t kCowReadAheadDone = 2; struct CowFooter { CowFooterOperation op; - CowFooterData data; + uint8_t unused[64]; } __attribute__((packed)); struct ScratchMetadata { diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h index c7b83a8386f5..4151b0121cba 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h @@ -171,7 +171,7 @@ class CowWriter : public ICowWriter { uint64_t GetCowSize() override; - uint32_t GetCowVersion() { return header_.major_version; } + uint32_t GetCowVersion() { return header_.prefix.major_version; } protected: virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_api_test.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_api_test.cpp index edc9d65b230a..8f80bb34533b 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_api_test.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_api_test.cpp @@ -65,9 +65,9 @@ TEST_F(CowTest, CopyContiguous) { ASSERT_TRUE(reader.Parse(cow_->fd)); const auto& header = reader.GetHeader(); - ASSERT_EQ(header.magic, kCowMagicNumber); - ASSERT_EQ(header.major_version, kCowVersionMajor); - ASSERT_EQ(header.minor_version, kCowVersionMinor); + ASSERT_EQ(header.prefix.magic, kCowMagicNumber); + ASSERT_EQ(header.prefix.major_version, kCowVersionMajor); + ASSERT_EQ(header.prefix.minor_version, kCowVersionMinor); ASSERT_EQ(header.block_size, options.block_size); CowFooter footer; @@ -114,9 +114,9 @@ TEST_F(CowTest, ReadWrite) { ASSERT_TRUE(reader.Parse(cow_->fd)); const auto& header = reader.GetHeader(); - ASSERT_EQ(header.magic, kCowMagicNumber); - ASSERT_EQ(header.major_version, kCowVersionMajor); - ASSERT_EQ(header.minor_version, kCowVersionMinor); + ASSERT_EQ(header.prefix.magic, kCowMagicNumber); + ASSERT_EQ(header.prefix.major_version, kCowVersionMajor); + ASSERT_EQ(header.prefix.minor_version, kCowVersionMinor); ASSERT_EQ(header.block_size, options.block_size); CowFooter footer; @@ -193,9 +193,9 @@ TEST_F(CowTest, ReadWriteXor) { ASSERT_TRUE(reader.Parse(cow_->fd)); const auto& header = reader.GetHeader(); - ASSERT_EQ(header.magic, kCowMagicNumber); - ASSERT_EQ(header.major_version, kCowVersionMajor); - ASSERT_EQ(header.minor_version, kCowVersionMinor); + ASSERT_EQ(header.prefix.magic, kCowMagicNumber); + ASSERT_EQ(header.prefix.major_version, kCowVersionMajor); + ASSERT_EQ(header.prefix.minor_version, kCowVersionMinor); ASSERT_EQ(header.block_size, options.block_size); CowFooter footer; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp index 6749cf1b0363..c2a7fdb39519 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp @@ -30,7 +30,7 @@ #include #include "cow_decompress.h" -#include "libsnapshot/cow_format.h" +#include "parser_v2.h" namespace android { namespace snapshot { @@ -43,15 +43,6 @@ CowReader::CowReader(ReaderFlags reader_flag, bool is_merge) reader_flag_(reader_flag), is_merge_(is_merge) {} -static void SHA256(const void*, size_t, uint8_t[]) { -#if 0 - SHA256_CTX c; - SHA256_Init(&c); - SHA256_Update(&c, data, length); - SHA256_Final(out, &c); -#endif -} - std::unique_ptr CowReader::CloneCowReader() { auto cow = std::make_unique(); cow->owned_fd_.reset(); @@ -63,7 +54,6 @@ std::unique_ptr CowReader::CloneCowReader() { cow->merge_op_start_ = merge_op_start_; cow->num_total_data_ops_ = num_total_data_ops_; cow->num_ordered_ops_to_merge_ = num_ordered_ops_to_merge_; - cow->has_seq_ops_ = has_seq_ops_; cow->data_loc_ = data_loc_; cow->block_pos_index_ = block_pos_index_; cow->is_merge_ = is_merge_; @@ -101,217 +91,26 @@ bool CowReader::Parse(android::base::unique_fd&& fd, std::optional lab bool CowReader::Parse(android::base::borrowed_fd fd, std::optional label) { fd_ = fd; - auto pos = lseek(fd_.get(), 0, SEEK_END); - if (pos < 0) { - PLOG(ERROR) << "lseek end failed"; - return false; - } - fd_size_ = pos; - - if (lseek(fd_.get(), 0, SEEK_SET) < 0) { - PLOG(ERROR) << "lseek header failed"; - return false; - } - if (!android::base::ReadFully(fd_, &header_, sizeof(header_))) { - PLOG(ERROR) << "read header failed"; + if (!ReadCowHeader(fd, &header_)) { return false; } - if (header_.magic != kCowMagicNumber) { - LOG(ERROR) << "Header Magic corrupted. Magic: " << header_.magic - << "Expected: " << kCowMagicNumber; - return false; - } - if (header_.footer_size != sizeof(CowFooter)) { - LOG(ERROR) << "Footer size unknown, read " << header_.footer_size << ", expected " - << sizeof(CowFooter); - return false; - } - if (header_.op_size != sizeof(CowOperation)) { - LOG(ERROR) << "Operation size unknown, read " << header_.op_size << ", expected " - << sizeof(CowOperation); - return false; - } - if (header_.cluster_ops == 1) { - LOG(ERROR) << "Clusters must contain at least two operations to function."; - return false; - } - if (header_.op_size != sizeof(CowOperation)) { - LOG(ERROR) << "Operation size unknown, read " << header_.op_size << ", expected " - << sizeof(CowOperation); - return false; - } - if (header_.cluster_ops == 1) { - LOG(ERROR) << "Clusters must contain at least two operations to function."; + CowParserV2 parser; + if (!parser.Parse(fd, header_, label)) { return false; } - if ((header_.major_version > kCowVersionMajor) || (header_.minor_version != kCowVersionMinor)) { - LOG(ERROR) << "Header version mismatch"; - LOG(ERROR) << "Major version: " << header_.major_version - << "Expected: " << kCowVersionMajor; - LOG(ERROR) << "Minor version: " << header_.minor_version - << "Expected: " << kCowVersionMinor; - return false; - } + footer_ = parser.footer(); + fd_size_ = parser.fd_size(); + last_label_ = parser.last_label(); + ops_ = std::move(parser.ops()); + data_loc_ = parser.data_loc(); - if (!ParseOps(label)) { - return false; - } // If we're resuming a write, we're not ready to merge if (label.has_value()) return true; return PrepMergeOps(); } -bool CowReader::ParseOps(std::optional label) { - uint64_t pos; - auto data_loc = std::make_shared>(); - - // Skip the scratch space - if (header_.major_version >= 2 && (header_.buffer_size > 0)) { - LOG(DEBUG) << " Scratch space found of size: " << header_.buffer_size; - size_t init_offset = header_.header_size + header_.buffer_size; - pos = lseek(fd_.get(), init_offset, SEEK_SET); - if (pos != init_offset) { - PLOG(ERROR) << "lseek ops failed"; - return false; - } - } else { - pos = lseek(fd_.get(), header_.header_size, SEEK_SET); - if (pos != header_.header_size) { - PLOG(ERROR) << "lseek ops failed"; - return false; - } - // Reading a v1 version of COW which doesn't have buffer_size. - header_.buffer_size = 0; - } - uint64_t data_pos = 0; - - if (header_.cluster_ops) { - data_pos = pos + header_.cluster_ops * sizeof(CowOperation); - } else { - data_pos = pos + sizeof(CowOperation); - } - - auto ops_buffer = std::make_shared>(); - uint64_t current_op_num = 0; - uint64_t cluster_ops = header_.cluster_ops ?: 1; - bool done = false; - - // Alternating op clusters and data - while (!done) { - uint64_t to_add = std::min(cluster_ops, (fd_size_ - pos) / sizeof(CowOperation)); - if (to_add == 0) break; - ops_buffer->resize(current_op_num + to_add); - if (!android::base::ReadFully(fd_, &ops_buffer->data()[current_op_num], - to_add * sizeof(CowOperation))) { - PLOG(ERROR) << "read op failed"; - return false; - } - // Parse current cluster to find start of next cluster - while (current_op_num < ops_buffer->size()) { - auto& current_op = ops_buffer->data()[current_op_num]; - current_op_num++; - if (current_op.type == kCowXorOp) { - data_loc->insert({current_op.new_block, data_pos}); - } - pos += sizeof(CowOperation) + GetNextOpOffset(current_op, header_.cluster_ops); - data_pos += current_op.data_length + GetNextDataOffset(current_op, header_.cluster_ops); - - if (current_op.type == kCowClusterOp) { - break; - } else if (current_op.type == kCowLabelOp) { - last_label_ = {current_op.source}; - - // If we reach the requested label, stop reading. - if (label && label.value() == current_op.source) { - done = true; - break; - } - } else if (current_op.type == kCowFooterOp) { - footer_.emplace(); - CowFooter* footer = &footer_.value(); - memcpy(&footer_->op, ¤t_op, sizeof(footer->op)); - off_t offs = lseek(fd_.get(), pos, SEEK_SET); - if (offs < 0 || pos != static_cast(offs)) { - PLOG(ERROR) << "lseek next op failed " << offs; - return false; - } - if (!android::base::ReadFully(fd_, &footer->data, sizeof(footer->data))) { - LOG(ERROR) << "Could not read COW footer"; - return false; - } - - // Drop the footer from the op stream. - current_op_num--; - done = true; - break; - } else if (current_op.type == kCowSequenceOp) { - has_seq_ops_ = true; - } - } - - // Position for next cluster read - off_t offs = lseek(fd_.get(), pos, SEEK_SET); - if (offs < 0 || pos != static_cast(offs)) { - PLOG(ERROR) << "lseek next op failed " << offs; - return false; - } - ops_buffer->resize(current_op_num); - } - - LOG(DEBUG) << "COW file read complete. Total ops: " << ops_buffer->size(); - // To successfully parse a COW file, we need either: - // (1) a label to read up to, and for that label to be found, or - // (2) a valid footer. - if (label) { - if (!last_label_) { - LOG(ERROR) << "Did not find label " << label.value() - << " while reading COW (no labels found)"; - return false; - } - if (last_label_.value() != label.value()) { - LOG(ERROR) << "Did not find label " << label.value() - << ", last label=" << last_label_.value(); - return false; - } - } else if (!footer_) { - LOG(ERROR) << "No COW footer found"; - return false; - } - - uint8_t csum[32]; - memset(csum, 0, sizeof(uint8_t) * 32); - - if (footer_) { - if (ops_buffer->size() != footer_->op.num_ops) { - LOG(ERROR) << "num ops does not match, expected " << footer_->op.num_ops << ", found " - << ops_buffer->size(); - return false; - } - if (ops_buffer->size() * sizeof(CowOperation) != footer_->op.ops_size) { - LOG(ERROR) << "ops size does not match "; - return false; - } - SHA256(&footer_->op, sizeof(footer_->op), footer_->data.footer_checksum); - if (memcmp(csum, footer_->data.ops_checksum, sizeof(csum)) != 0) { - LOG(ERROR) << "ops checksum does not match"; - return false; - } - SHA256(ops_buffer->data(), footer_->op.ops_size, csum); - if (memcmp(csum, footer_->data.ops_checksum, sizeof(csum)) != 0) { - LOG(ERROR) << "ops checksum does not match"; - return false; - } - } - - ops_ = ops_buffer; - ops_->shrink_to_fit(); - data_loc_ = data_loc; - - return true; -} - // // This sets up the data needed for MergeOpIter. MergeOpIter presents // data in the order we intend to merge in. @@ -446,7 +245,8 @@ bool CowReader::PrepMergeOps() { continue; } - if (!has_seq_ops_ && IsOrderedOp(current_op)) { + // Sequence ops must be the first ops in the stream. + if (seq_ops_set.empty() && IsOrderedOp(current_op)) { merge_op_blocks->emplace_back(current_op.new_block); } else if (seq_ops_set.count(current_op.new_block) == 0) { other_ops.push_back(current_op.new_block); @@ -718,8 +518,8 @@ std::unique_ptr CowReader::GetMergeOpIter(bool ignore_progress) { bool CowReader::GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read) { // Validate the offset, taking care to acknowledge possible overflow of offset+len. - if (offset < header_.header_size || offset >= fd_size_ - sizeof(CowFooter) || len >= fd_size_ || - offset + len > fd_size_ - sizeof(CowFooter)) { + if (offset < header_.prefix.header_size || offset >= fd_size_ - sizeof(CowFooter) || + len >= fd_size_ || offset + len > fd_size_ - sizeof(CowFooter)) { LOG(ERROR) << "invalid data offset: " << offset << ", " << len << " bytes"; return false; } diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp index 0e189794713e..1eaa0385ee26 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp @@ -186,10 +186,10 @@ void CowWriter::SetupWriteOptions() { void CowWriter::SetupHeaders() { header_ = {}; - header_.magic = kCowMagicNumber; - header_.major_version = kCowVersionMajor; - header_.minor_version = kCowVersionMinor; - header_.header_size = sizeof(CowHeader); + header_.prefix.magic = kCowMagicNumber; + header_.prefix.major_version = kCowVersionMajor; + header_.prefix.minor_version = kCowVersionMinor; + header_.prefix.header_size = sizeof(CowHeader); header_.footer_size = sizeof(CowFooter); header_.op_size = sizeof(CowOperation); header_.block_size = options_.block_size; @@ -614,17 +614,6 @@ bool CowWriter::EmitClusterIfNeeded() { return true; } -// TODO: Fix compilation issues when linking libcrypto library -// when snapuserd is compiled as part of ramdisk. -static void SHA256(const void*, size_t, uint8_t[]) { -#if 0 - SHA256_CTX c; - SHA256_Init(&c); - SHA256_Update(&c, data, length); - SHA256_Final(out, &c); -#endif -} - bool CowWriter::Finalize() { if (!FlushCluster()) { LOG(ERROR) << "Finalize: FlushCluster() failed"; @@ -665,10 +654,8 @@ bool CowWriter::Finalize() { PLOG(ERROR) << "Failed to seek to footer position."; return false; } - memset(&footer_.data.ops_checksum, 0, sizeof(uint8_t) * 32); - memset(&footer_.data.footer_checksum, 0, sizeof(uint8_t) * 32); + memset(&footer_.unused, 0, sizeof(footer_.unused)); - SHA256(&footer_.op, sizeof(footer_.op), footer_.data.footer_checksum); // Write out footer at end of file if (!android::base::WriteFully(fd_, reinterpret_cast(&footer_), sizeof(footer_))) { diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp index 917cec4242b3..c2c86eefdda3 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp @@ -104,8 +104,9 @@ static bool Inspect(const std::string& path, Options opt) { if (reader.GetFooter(&footer)) has_footer = true; if (!opt.silent) { - std::cout << "Version: " << header.major_version << "." << header.minor_version << "\n"; - std::cout << "Header size: " << header.header_size << "\n"; + std::cout << "Version: " << header.prefix.major_version << "." + << header.prefix.minor_version << "\n"; + std::cout << "Header size: " << header.prefix.header_size << "\n"; std::cout << "Footer size: " << header.footer_size << "\n"; std::cout << "Block size: " << header.block_size << "\n"; std::cout << "Merge ops: " << header.num_merge_ops << "\n"; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.cpp new file mode 100644 index 000000000000..fdb5c5911d1c --- /dev/null +++ b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.cpp @@ -0,0 +1,238 @@ +// Copyright (C) 2023 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 "parser_v2.h" + +#include + +#include +#include + +namespace android { +namespace snapshot { + +using android::base::borrowed_fd; + +bool ReadCowHeader(android::base::borrowed_fd fd, CowHeader* header) { + if (lseek(fd.get(), 0, SEEK_SET) < 0) { + PLOG(ERROR) << "lseek header failed"; + return false; + } + + memset(header, 0, sizeof(*header)); + + if (!android::base::ReadFully(fd, &header->prefix, sizeof(header->prefix))) { + return false; + } + if (header->prefix.magic != kCowMagicNumber) { + LOG(ERROR) << "Header Magic corrupted. Magic: " << header->prefix.magic + << "Expected: " << kCowMagicNumber; + return false; + } + if (header->prefix.header_size > sizeof(CowHeader)) { + LOG(ERROR) << "Unknown CowHeader size (got " << header->prefix.header_size + << " bytes, expected at most " << sizeof(CowHeader) << " bytes)"; + return false; + } + + if (lseek(fd.get(), 0, SEEK_SET) < 0) { + PLOG(ERROR) << "lseek header failed"; + return false; + } + return android::base::ReadFully(fd, header, header->prefix.header_size); +} + +bool CowParserV2::Parse(borrowed_fd fd, const CowHeader& header, std::optional label) { + auto pos = lseek(fd.get(), 0, SEEK_END); + if (pos < 0) { + PLOG(ERROR) << "lseek end failed"; + return false; + } + fd_size_ = pos; + header_ = header; + + if (header_.footer_size != sizeof(CowFooter)) { + LOG(ERROR) << "Footer size unknown, read " << header_.footer_size << ", expected " + << sizeof(CowFooter); + return false; + } + if (header_.op_size != sizeof(CowOperation)) { + LOG(ERROR) << "Operation size unknown, read " << header_.op_size << ", expected " + << sizeof(CowOperation); + return false; + } + if (header_.cluster_ops == 1) { + LOG(ERROR) << "Clusters must contain at least two operations to function."; + return false; + } + if (header_.op_size != sizeof(CowOperation)) { + LOG(ERROR) << "Operation size unknown, read " << header_.op_size << ", expected " + << sizeof(CowOperation); + return false; + } + if (header_.cluster_ops == 1) { + LOG(ERROR) << "Clusters must contain at least two operations to function."; + return false; + } + + if ((header_.prefix.major_version > kCowVersionMajor) || + (header_.prefix.minor_version != kCowVersionMinor)) { + LOG(ERROR) << "Header version mismatch, " + << "major version: " << header_.prefix.major_version + << ", expected: " << kCowVersionMajor + << ", minor version: " << header_.prefix.minor_version + << ", expected: " << kCowVersionMinor; + return false; + } + + return ParseOps(fd, label); +} + +bool CowParserV2::ParseOps(borrowed_fd fd, std::optional label) { + uint64_t pos; + auto data_loc = std::make_shared>(); + + // Skip the scratch space + if (header_.prefix.major_version >= 2 && (header_.buffer_size > 0)) { + LOG(DEBUG) << " Scratch space found of size: " << header_.buffer_size; + size_t init_offset = header_.prefix.header_size + header_.buffer_size; + pos = lseek(fd.get(), init_offset, SEEK_SET); + if (pos != init_offset) { + PLOG(ERROR) << "lseek ops failed"; + return false; + } + } else { + pos = lseek(fd.get(), header_.prefix.header_size, SEEK_SET); + if (pos != header_.prefix.header_size) { + PLOG(ERROR) << "lseek ops failed"; + return false; + } + // Reading a v1 version of COW which doesn't have buffer_size. + header_.buffer_size = 0; + } + uint64_t data_pos = 0; + + if (header_.cluster_ops) { + data_pos = pos + header_.cluster_ops * sizeof(CowOperation); + } else { + data_pos = pos + sizeof(CowOperation); + } + + auto ops_buffer = std::make_shared>(); + uint64_t current_op_num = 0; + uint64_t cluster_ops = header_.cluster_ops ?: 1; + bool done = false; + + // Alternating op clusters and data + while (!done) { + uint64_t to_add = std::min(cluster_ops, (fd_size_ - pos) / sizeof(CowOperation)); + if (to_add == 0) break; + ops_buffer->resize(current_op_num + to_add); + if (!android::base::ReadFully(fd, &ops_buffer->data()[current_op_num], + to_add * sizeof(CowOperation))) { + PLOG(ERROR) << "read op failed"; + return false; + } + // Parse current cluster to find start of next cluster + while (current_op_num < ops_buffer->size()) { + auto& current_op = ops_buffer->data()[current_op_num]; + current_op_num++; + if (current_op.type == kCowXorOp) { + data_loc->insert({current_op.new_block, data_pos}); + } + pos += sizeof(CowOperation) + GetNextOpOffset(current_op, header_.cluster_ops); + data_pos += current_op.data_length + GetNextDataOffset(current_op, header_.cluster_ops); + + if (current_op.type == kCowClusterOp) { + break; + } else if (current_op.type == kCowLabelOp) { + last_label_ = {current_op.source}; + + // If we reach the requested label, stop reading. + if (label && label.value() == current_op.source) { + done = true; + break; + } + } else if (current_op.type == kCowFooterOp) { + footer_.emplace(); + CowFooter* footer = &footer_.value(); + memcpy(&footer_->op, ¤t_op, sizeof(footer->op)); + off_t offs = lseek(fd.get(), pos, SEEK_SET); + if (offs < 0 || pos != static_cast(offs)) { + PLOG(ERROR) << "lseek next op failed " << offs; + return false; + } + if (!android::base::ReadFully(fd, &footer->unused, sizeof(footer->unused))) { + LOG(ERROR) << "Could not read COW footer"; + return false; + } + + // Drop the footer from the op stream. + current_op_num--; + done = true; + break; + } + } + + // Position for next cluster read + off_t offs = lseek(fd.get(), pos, SEEK_SET); + if (offs < 0 || pos != static_cast(offs)) { + PLOG(ERROR) << "lseek next op failed " << offs; + return false; + } + ops_buffer->resize(current_op_num); + } + + LOG(DEBUG) << "COW file read complete. Total ops: " << ops_buffer->size(); + // To successfully parse a COW file, we need either: + // (1) a label to read up to, and for that label to be found, or + // (2) a valid footer. + if (label) { + if (!last_label_) { + LOG(ERROR) << "Did not find label " << label.value() + << " while reading COW (no labels found)"; + return false; + } + if (last_label_.value() != label.value()) { + LOG(ERROR) << "Did not find label " << label.value() + << ", last label=" << last_label_.value(); + return false; + } + } else if (!footer_) { + LOG(ERROR) << "No COW footer found"; + return false; + } + + uint8_t csum[32]; + memset(csum, 0, sizeof(uint8_t) * 32); + + if (footer_) { + if (ops_buffer->size() != footer_->op.num_ops) { + LOG(ERROR) << "num ops does not match, expected " << footer_->op.num_ops << ", found " + << ops_buffer->size(); + return false; + } + if (ops_buffer->size() * sizeof(CowOperation) != footer_->op.ops_size) { + LOG(ERROR) << "ops size does not match "; + return false; + } + } + + ops_ = ops_buffer; + ops_->shrink_to_fit(); + data_loc_ = data_loc; + return true; +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.h b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.h new file mode 100644 index 000000000000..afcf687fd67a --- /dev/null +++ b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.h @@ -0,0 +1,55 @@ +// Copyright (C) 2023 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. +#pragma once + +#include + +#include +#include +#include +#include + +#include +#include + +namespace android { +namespace snapshot { + +class CowParserV2 { + public: + bool Parse(android::base::borrowed_fd fd, const CowHeader& header, + std::optional label = {}); + + const CowHeader& header() const { return header_; } + const std::optional& footer() const { return footer_; } + std::shared_ptr> ops() { return ops_; } + std::shared_ptr> data_loc() const { return data_loc_; } + uint64_t fd_size() const { return fd_size_; } + const std::optional& last_label() const { return last_label_; } + + private: + bool ParseOps(android::base::borrowed_fd fd, std::optional label); + + CowHeader header_ = {}; + std::optional footer_; + std::shared_ptr> ops_; + std::shared_ptr> data_loc_; + uint64_t fd_size_; + std::optional last_label_; +}; + +bool ReadCowHeader(android::base::borrowed_fd fd, CowHeader* header); + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp index efa43b79d03e..da9bd113f6d4 100644 --- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp +++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp @@ -628,8 +628,8 @@ bool Snapuserd::ReadMetadata() { bool Snapuserd::MmapMetadata() { const auto& header = reader_->GetHeader(); - if (header.major_version >= 2 && header.buffer_size > 0) { - total_mapped_addr_length_ = header.header_size + BUFFER_REGION_DEFAULT_SIZE; + if (header.prefix.major_version >= 2 && header.buffer_size > 0) { + total_mapped_addr_length_ = header.prefix.header_size + BUFFER_REGION_DEFAULT_SIZE; read_ahead_feature_ = true; } else { // mmap the first 4k page - older COW format @@ -823,7 +823,7 @@ bool Snapuserd::Start() { uint64_t Snapuserd::GetBufferMetadataOffset() { const auto& header = reader_->GetHeader(); - size_t size = header.header_size + sizeof(BufferState); + size_t size = header.prefix.header_size + sizeof(BufferState); return size; } @@ -845,7 +845,7 @@ size_t Snapuserd::GetBufferMetadataSize() { size_t Snapuserd::GetBufferDataOffset() { const auto& header = reader_->GetHeader(); - return (header.header_size + GetBufferMetadataSize()); + return (header.prefix.header_size + GetBufferMetadataSize()); } /* @@ -862,7 +862,7 @@ struct BufferState* Snapuserd::GetBufferState() { const auto& header = reader_->GetHeader(); struct BufferState* ra_state = - reinterpret_cast((char*)mapped_addr_ + header.header_size); + reinterpret_cast((char*)mapped_addr_ + header.prefix.header_size); return ra_state; } 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 a51963985381..c3343b8c642a 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -240,9 +240,9 @@ bool SnapshotHandler::ReadMetadata() { bool SnapshotHandler::MmapMetadata() { const auto& header = reader_->GetHeader(); - total_mapped_addr_length_ = header.header_size + BUFFER_REGION_DEFAULT_SIZE; + total_mapped_addr_length_ = header.prefix.header_size + BUFFER_REGION_DEFAULT_SIZE; - if (header.major_version >= 2 && header.buffer_size > 0) { + if (header.prefix.major_version >= 2 && header.buffer_size > 0) { scratch_space_ = true; } @@ -362,7 +362,7 @@ bool SnapshotHandler::Start() { uint64_t SnapshotHandler::GetBufferMetadataOffset() { const auto& header = reader_->GetHeader(); - return (header.header_size + sizeof(BufferState)); + return (header.prefix.header_size + sizeof(BufferState)); } /* @@ -390,7 +390,7 @@ size_t SnapshotHandler::GetBufferMetadataSize() { size_t SnapshotHandler::GetBufferDataOffset() { const auto& header = reader_->GetHeader(); - return (header.header_size + GetBufferMetadataSize()); + return (header.prefix.header_size + GetBufferMetadataSize()); } /* @@ -413,7 +413,7 @@ struct BufferState* SnapshotHandler::GetBufferState() { const auto& header = reader_->GetHeader(); struct BufferState* ra_state = - reinterpret_cast((char*)mapped_addr_ + header.header_size); + reinterpret_cast((char*)mapped_addr_ + header.prefix.header_size); return ra_state; } From 85c65e98cd7ec5f774f1f874d86aebdd2bfe59dd Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 8 May 2023 14:48:45 -0700 Subject: [PATCH 0062/1487] libsnapshot: Remove unused SupportsCopyOperation. This function is never used. It was intended to allow update_engine to unify all writes through ISnapshotWriter, but that never came to pass. Bug: 280529365 Test: builds Change-Id: I7e418ffee404cd63faa5a5659d8971988f8d0e03 --- fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h | 3 --- fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h | 3 --- 2 files changed, 6 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h index 8458517994fe..7881f35099dd 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h @@ -93,9 +93,6 @@ class ICowWriter { // Return number of bytes the cow image occupies on disk. virtual uint64_t GetCowSize() = 0; - // Returns true if AddCopy() operations are supported. - virtual bool SupportsCopyOperation() const { return true; } - const CowOptions& options() { return options_; } protected: diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h index 29828bcfba63..d798e25e3c4c 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h @@ -31,9 +31,6 @@ class MockSnapshotWriter : public ISnapshotWriter { // Return number of bytes the cow image occupies on disk. MOCK_METHOD(uint64_t, GetCowSize, (), (override)); - // Returns true if AddCopy() operations are supported. - MOCK_METHOD(bool, SupportsCopyOperation, (), (const override)); - MOCK_METHOD(bool, EmitCopy, (uint64_t, uint64_t, uint64_t), (override)); MOCK_METHOD(bool, EmitRawBlocks, (uint64_t, const void*, size_t), (override)); MOCK_METHOD(bool, EmitXorBlocks, (uint32_t, const void*, size_t, uint32_t, uint16_t), From 0ec7115779ff9002353c31b82d4b4a75c15599b5 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 4 May 2023 09:39:58 -0700 Subject: [PATCH 0063/1487] libsnapshot: Reject bad cow versions. Remove CowWriter::GetCowVersion. Instead, reject any update that asks for VABC but has an unsupported version field. Do not fallback to legacy VAB as the update was likely built improperly. Bug: 280529365 Test: vts_libsnapshot_test Change-Id: Ibc0f981801fd47bf39d7a19944134e4b3c66e5bf --- .../include/libsnapshot/cow_format.h | 3 ++ .../include/libsnapshot/cow_writer.h | 2 - fs_mgr/libsnapshot/snapshot.cpp | 40 +++++++++---------- fs_mgr/libsnapshot/snapshot_test.cpp | 18 +++++++++ 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h index 9f9469910dbd..b228dff8d72c 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h @@ -28,6 +28,9 @@ static constexpr uint32_t kCowVersionMinor = 0; static constexpr uint32_t kCowVersionManifest = 2; +static constexpr uint32_t kMinCowVersion = 1; +static constexpr uint32_t kMaxCowVersion = 2; + // This header appears as the first sequence of bytes in the COW. All fields // in the layout are little-endian encoded. The on-disk layout is: // diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h index 4151b0121cba..8458517994fe 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h @@ -171,8 +171,6 @@ class CowWriter : public ICowWriter { uint64_t GetCowSize() override; - uint32_t GetCowVersion() { return header_.prefix.major_version; } - protected: virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override; virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override; diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index 26614827ba64..b0c4a8371e01 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -3202,39 +3202,20 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife CHECK(current_metadata->GetBlockDevicePartitionName(0) == LP_METADATA_DEFAULT_PARTITION_NAME && target_metadata->GetBlockDevicePartitionName(0) == LP_METADATA_DEFAULT_PARTITION_NAME); - std::map all_snapshot_status; - - // In case of error, automatically delete devices that are created along the way. - // Note that "lock" is destroyed after "created_devices", so it is safe to use |lock| for - // these devices. - AutoDeviceList created_devices; - const auto& dap_metadata = manifest.dynamic_partition_metadata(); - CowOptions options; - CowWriter writer(options); - bool cow_format_support = true; - if (dap_metadata.cow_version() < writer.GetCowVersion()) { - cow_format_support = false; - } - - LOG(INFO) << " dap_metadata.cow_version(): " << dap_metadata.cow_version() - << " writer.GetCowVersion(): " << writer.GetCowVersion(); - - // Deduce supported features. - bool userspace_snapshots = CanUseUserspaceSnapshots(); - bool legacy_compression = GetLegacyCompressionEnabledProperty(); std::string vabc_disable_reason; if (!dap_metadata.vabc_enabled()) { vabc_disable_reason = "not enabled metadata"; } else if (device_->IsRecovery()) { vabc_disable_reason = "recovery"; - } else if (!cow_format_support) { - vabc_disable_reason = "cow format not supported"; } else if (!KernelSupportsCompressedSnapshots()) { vabc_disable_reason = "kernel missing userspace block device support"; } + // Deduce supported features. + bool userspace_snapshots = CanUseUserspaceSnapshots(); + bool legacy_compression = GetLegacyCompressionEnabledProperty(); if (!vabc_disable_reason.empty()) { if (userspace_snapshots) { LOG(INFO) << "Userspace snapshots disabled: " << vabc_disable_reason; @@ -3246,6 +3227,16 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife legacy_compression = false; } + if (legacy_compression || userspace_snapshots) { + if (dap_metadata.cow_version() < kMinCowVersion || + dap_metadata.cow_version() > kMaxCowVersion) { + LOG(ERROR) << "Manifest cow version is out of bounds (got: " + << dap_metadata.cow_version() << ", min: " << kMinCowVersion + << ", max: " << kMaxCowVersion << ")"; + return Return::Error(); + } + } + const bool using_snapuserd = userspace_snapshots || legacy_compression; if (!using_snapuserd) { LOG(INFO) << "Using legacy Virtual A/B (dm-snapshot)"; @@ -3278,6 +3269,11 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife cow_creator.batched_writes = dap_metadata.vabc_feature_set().batch_writes(); } + // In case of error, automatically delete devices that are created along the way. + // Note that "lock" is destroyed after "created_devices", so it is safe to use |lock| for + // these devices. + AutoDeviceList created_devices; + std::map all_snapshot_status; auto ret = CreateUpdateSnapshotsInternal(lock.get(), manifest, &cow_creator, &created_devices, &all_snapshot_status); if (!ret.is_ok()) { diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index 22731e7b7487..f08f9139ccbb 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -2688,6 +2688,24 @@ TEST_F(SnapshotUpdateTest, QueryStatusError) { ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState()); } +TEST_F(SnapshotUpdateTest, BadCowVersion) { + if (!snapuserd_required_) { + GTEST_SKIP() << "VABC only"; + } + + ASSERT_TRUE(sm->BeginUpdate()); + + auto dynamic_partition_metadata = manifest_.mutable_dynamic_partition_metadata(); + dynamic_partition_metadata->set_cow_version(kMinCowVersion - 1); + ASSERT_FALSE(sm->CreateUpdateSnapshots(manifest_)); + + dynamic_partition_metadata->set_cow_version(kMaxCowVersion + 1); + ASSERT_FALSE(sm->CreateUpdateSnapshots(manifest_)); + + dynamic_partition_metadata->set_cow_version(kMaxCowVersion); + ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_)); +} + class FlashAfterUpdateTest : public SnapshotUpdateTest, public WithParamInterface> { public: From 95b26e1d0cddec1e0063c4238842d45fa95dc2be Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 9 May 2023 12:30:06 -0700 Subject: [PATCH 0064/1487] libsnapshot: Remove OnlineKernelSnapshotWriter. This was never used or tested. The idea was to unify update_engine's write paths on ISnapshotWriter. But given that legacy VAB is "legacy", it doesn't make sense to begin refactoring that code and potentially introducing bugs. Let's just remove this instead. Bug: 280529365 Test: builds Change-Id: Ie2f531bd140e183dfde4b65a144f3b4acc28e78a --- .../include/libsnapshot/snapshot.h | 4 - .../include/libsnapshot/snapshot_writer.h | 33 ------- fs_mgr/libsnapshot/snapshot.cpp | 39 ++------ fs_mgr/libsnapshot/snapshot_test.cpp | 39 +++++--- fs_mgr/libsnapshot/snapshot_writer.cpp | 90 ------------------- 5 files changed, 34 insertions(+), 171 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h index 9eb89b6124d3..ecf1d1531710 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h @@ -697,10 +697,6 @@ class SnapshotManager final : public ISnapshotManager { LockedFile* lock, const std::optional& source_device, const std::string& partition_name, const SnapshotStatus& status, const SnapshotPaths& paths); - std::unique_ptr OpenKernelSnapshotWriter( - LockedFile* lock, const std::optional& source_device, - const std::string& partition_name, const SnapshotStatus& status, - const SnapshotPaths& paths); // Map the base device, COW devices, and snapshot device. bool MapPartitionWithSnapshot(LockedFile* lock, CreateLogicalPartitionParams params, diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h index 0e3b1db6b90e..8f6344c3b741 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h @@ -89,38 +89,5 @@ class CompressedSnapshotWriter final : public ISnapshotWriter { std::unique_ptr cow_; }; -// Write directly to a dm-snapshot device. -class OnlineKernelSnapshotWriter final : public ISnapshotWriter { - public: - OnlineKernelSnapshotWriter(const CowOptions& options); - - // Set the device used for all writes. - void SetSnapshotDevice(android::base::unique_fd&& snapshot_fd, uint64_t cow_size); - - bool Initialize() override { return true; } - bool InitializeAppend(uint64_t) override { return true; } - - bool Finalize() override; - uint64_t GetCowSize() override { return cow_size_; } - std::unique_ptr 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; - bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block, - uint16_t offset) override; - bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override; - bool EmitLabel(uint64_t label) override; - bool EmitSequenceData(size_t num_ops, const uint32_t* data) override; - - private: - android::base::unique_fd snapshot_fd_; - uint64_t cow_size_ = 0; -}; - } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index b0c4a8371e01..e114d255654e 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -3647,12 +3647,13 @@ std::unique_ptr SnapshotManager::OpenSnapshotWriter( return nullptr; } - if (status.using_snapuserd()) { - return OpenCompressedSnapshotWriter(lock.get(), source_device, params.GetPartitionName(), - status, paths); + if (!status.using_snapuserd()) { + LOG(ERROR) << "Can only create snapshot writers with userspace or compressed snapshots"; + return nullptr; } - return OpenKernelSnapshotWriter(lock.get(), source_device, params.GetPartitionName(), status, - paths); + + return OpenCompressedSnapshotWriter(lock.get(), source_device, params.GetPartitionName(), + status, paths); #endif } @@ -3700,34 +3701,6 @@ std::unique_ptr SnapshotManager::OpenCompressedSnapshotWriter( return writer; } - -std::unique_ptr SnapshotManager::OpenKernelSnapshotWriter( - LockedFile* lock, const std::optional& source_device, - [[maybe_unused]] const std::string& partition_name, const SnapshotStatus& status, - const SnapshotPaths& paths) { - CHECK(lock); - - CowOptions cow_options; - cow_options.max_blocks = {status.device_size() / cow_options.block_size}; - - auto writer = std::make_unique(cow_options); - - std::string path = paths.snapshot_device.empty() ? paths.target_device : paths.snapshot_device; - unique_fd fd(open(path.c_str(), O_RDWR | O_CLOEXEC)); - if (fd < 0) { - PLOG(ERROR) << "open failed: " << path; - return nullptr; - } - - if (source_device) { - writer->SetSourceDevice(*source_device); - } - - uint64_t cow_size = status.cow_partition_size() + status.cow_file_size(); - writer->SetSnapshotDevice(std::move(fd), cow_size); - - return writer; -} #endif // !defined(LIBSNAPSHOT_NO_COW_WRITE) bool SnapshotManager::UnmapUpdateSnapshot(const std::string& target_partition_name) { diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index f08f9139ccbb..7cdb8ed0aef1 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -643,21 +643,38 @@ TEST_F(SnapshotTest, FirstStageMountAfterRollback) { TEST_F(SnapshotTest, Merge) { ASSERT_TRUE(AcquireLock()); - static const uint64_t kDeviceSize = 1024 * 1024; + static constexpr uint64_t kDeviceSize = 1024 * 1024; + static constexpr uint32_t kBlockSize = 4096; + + std::string test_string = "This is a test string."; + test_string.resize(kBlockSize); - std::unique_ptr writer; - ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize, &writer)); + bool userspace_snapshots = false; + if (snapuserd_required_) { + std::unique_ptr writer; + ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize, &writer)); - bool userspace_snapshots = sm->UpdateUsesUserSnapshots(lock_.get()); + userspace_snapshots = sm->UpdateUsesUserSnapshots(lock_.get()); - // Release the lock. - lock_ = nullptr; + // Release the lock. + lock_ = nullptr; - std::string test_string = "This is a test string."; - test_string.resize(writer->options().block_size); - ASSERT_TRUE(writer->AddRawBlocks(0, test_string.data(), test_string.size())); - ASSERT_TRUE(writer->Finalize()); - writer = nullptr; + ASSERT_TRUE(writer->AddRawBlocks(0, test_string.data(), test_string.size())); + ASSERT_TRUE(writer->Finalize()); + writer = nullptr; + } else { + ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize)); + + // Release the lock. + lock_ = nullptr; + + std::string path; + ASSERT_TRUE(dm_.GetDmDevicePathByName("test_partition_b", &path)); + + unique_fd fd(open(path.c_str(), O_WRONLY)); + ASSERT_GE(fd, 0); + ASSERT_TRUE(android::base::WriteFully(fd, test_string.data(), test_string.size())); + } // Done updating. ASSERT_TRUE(sm->FinishedSnapshotWrites(false)); diff --git a/fs_mgr/libsnapshot/snapshot_writer.cpp b/fs_mgr/libsnapshot/snapshot_writer.cpp index 82a7fd7d6343..6a3906ead22c 100644 --- a/fs_mgr/libsnapshot/snapshot_writer.cpp +++ b/fs_mgr/libsnapshot/snapshot_writer.cpp @@ -149,95 +149,5 @@ bool CompressedSnapshotWriter::InitializeAppend(uint64_t label) { return cow_->InitializeAppend(cow_device_, label); } -OnlineKernelSnapshotWriter::OnlineKernelSnapshotWriter(const CowOptions& options) - : ISnapshotWriter(options) {} - -void OnlineKernelSnapshotWriter::SetSnapshotDevice(android::base::unique_fd&& snapshot_fd, - uint64_t cow_size) { - snapshot_fd_ = std::move(snapshot_fd); - cow_size_ = cow_size; -} - -bool OnlineKernelSnapshotWriter::Finalize() { - if (fsync(snapshot_fd_.get()) < 0) { - PLOG(ERROR) << "fsync"; - return false; - } - return true; -} - -bool OnlineKernelSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const void* data, - size_t size) { - uint64_t offset = new_block_start * options_.block_size; - if (lseek(snapshot_fd_.get(), offset, SEEK_SET) < 0) { - PLOG(ERROR) << "EmitRawBlocks lseek to offset " << offset; - return false; - } - if (!android::base::WriteFully(snapshot_fd_, data, size)) { - PLOG(ERROR) << "EmitRawBlocks write"; - return false; - } - return true; -} - -bool OnlineKernelSnapshotWriter::EmitXorBlocks(uint32_t, const void*, size_t, uint32_t, uint16_t) { - LOG(ERROR) << "EmitXorBlocks not implemented."; - return false; -} - -bool OnlineKernelSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { - std::string zeroes(options_.block_size, 0); - for (uint64_t i = 0; i < num_blocks; i++) { - if (!EmitRawBlocks(new_block_start + i, zeroes.data(), zeroes.size())) { - return false; - } - } - return true; -} - -bool OnlineKernelSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block, - uint64_t num_blocks) { - auto source_fd = GetSourceFd(); - if (source_fd < 0) { - return false; - } - - CHECK(num_blocks != 0); - - for (size_t i = 0; i < num_blocks; i++) { - std::string buffer(options_.block_size, 0); - uint64_t offset = (old_block + i) * options_.block_size; - if (!android::base::ReadFullyAtOffset(source_fd, buffer.data(), buffer.size(), offset)) { - PLOG(ERROR) << "EmitCopy read"; - return false; - } - if (!EmitRawBlocks(new_block + i, buffer.data(), buffer.size())) { - PLOG(ERROR) << "EmitRawBlocks failed"; - return false; - } - } - - return true; -} - -bool OnlineKernelSnapshotWriter::EmitLabel(uint64_t) { - // Not Needed - return true; -} - -bool OnlineKernelSnapshotWriter::EmitSequenceData(size_t, const uint32_t*) { - // Not Needed - return true; -} - -std::unique_ptr OnlineKernelSnapshotWriter::OpenReader() { - unique_fd fd(dup(snapshot_fd_.get())); - if (fd < 0) { - PLOG(ERROR) << "dup2 failed in OpenReader"; - return nullptr; - } - return std::make_unique(std::move(fd)); -} - } // namespace snapshot } // namespace android From 5729d860cd543ff504efcd08e3e6da579e05c79e Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Tue, 23 May 2023 00:24:04 +0000 Subject: [PATCH 0065/1487] Remove libdiskconfig as it is no longer used Test: m Bug: 280829178 Change-Id: I1da275ef13dea92b8c1021aa3d658569c4cf782e --- libdiskconfig/Android.bp | 36 -- libdiskconfig/config_mbr.c | 351 ------------ libdiskconfig/diskconfig.c | 535 ------------------ libdiskconfig/diskutils.c | 118 ---- libdiskconfig/dump_diskconfig.c | 43 -- libdiskconfig/include/diskconfig/diskconfig.h | 130 ----- libdiskconfig/write_lst.c | 92 --- 7 files changed, 1305 deletions(-) delete mode 100644 libdiskconfig/Android.bp delete mode 100644 libdiskconfig/config_mbr.c delete mode 100644 libdiskconfig/diskconfig.c delete mode 100644 libdiskconfig/diskutils.c delete mode 100644 libdiskconfig/dump_diskconfig.c delete mode 100644 libdiskconfig/include/diskconfig/diskconfig.h delete mode 100644 libdiskconfig/write_lst.c diff --git a/libdiskconfig/Android.bp b/libdiskconfig/Android.bp deleted file mode 100644 index f523d4e70c28..000000000000 --- a/libdiskconfig/Android.bp +++ /dev/null @@ -1,36 +0,0 @@ -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -cc_library { - name: "libdiskconfig", - vendor_available: true, - vndk: { - enabled: true, - }, - srcs: [ - "diskconfig.c", - "diskutils.c", - "write_lst.c", - "config_mbr.c", - ], - - shared_libs: [ - "libcutils", - "liblog", - ], - cflags: ["-Werror"], - export_include_dirs: ["include"], - local_include_dirs: ["include"], - - target: { - darwin: { - enabled: false, - }, - host_linux: { - cflags: [ - "-D_LARGEFILE64_SOURCE", - ], - }, - }, -} diff --git a/libdiskconfig/config_mbr.c b/libdiskconfig/config_mbr.c deleted file mode 100644 index ace9bbfb1ea2..000000000000 --- a/libdiskconfig/config_mbr.c +++ /dev/null @@ -1,351 +0,0 @@ -/* libs/diskconfig/diskconfig.c - * - * Copyright 2008, 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. - */ - -#define LOG_TAG "config_mbr" - -#include -#include -#include -#include - -#include -#include - -/* start and len are in LBA units */ -static void -cfg_pentry(struct pc_partition *pentry, uint8_t status, uint8_t type, - uint32_t start, uint32_t len) -{ - if (len > 0) { - /* seems that somes BIOSens can get wedged on boot while verifying - * the mbr if these are 0 */ - memset(&pentry->start, 0xff, sizeof(struct chs)); - memset(&pentry->end, 0xff, sizeof(struct chs)); - } else { - /* zero out the c/h/s entries.. they are not used */ - memset(&pentry->start, 0, sizeof(struct chs)); - memset(&pentry->end, 0, sizeof(struct chs)); - } - - pentry->status = status; - pentry->type = type; - pentry->start_lba = start; - pentry->len_lba = len; - - ALOGI("Configuring pentry. status=0x%x type=0x%x start_lba=%u len_lba=%u", - pentry->status, pentry->type, pentry->start_lba, pentry->len_lba); -} - - -static inline uint32_t -kb_to_lba(uint32_t len_kb, uint32_t sect_size) -{ - uint64_t lba; - - lba = (uint64_t)len_kb * 1024; - /* bump it up to the next LBA boundary just in case */ - lba = (lba + (uint64_t)sect_size - 1) & ~((uint64_t)sect_size - 1); - lba /= (uint64_t)sect_size; - if (lba >= 0xffffffffULL) - ALOGE("Error converting kb -> lba. 32bit overflow, expect weirdness"); - return (uint32_t)(lba & 0xffffffffULL); -} - - -static struct write_list * -mk_pri_pentry(struct disk_info *dinfo, struct part_info *pinfo, int pnum, - uint32_t *lba) -{ - struct write_list *item; - struct pc_partition *pentry; - - if (pnum >= PC_NUM_BOOT_RECORD_PARTS) { - ALOGE("Maximum number of primary partition exceeded."); - return NULL; - } - - if (!(item = alloc_wl(sizeof(struct pc_partition)))) { - ALOGE("Unable to allocate memory for partition entry."); - return NULL; - } - - { - /* DO NOT DEREFERENCE */ - struct pc_boot_record *mbr = (void *)PC_MBR_DISK_OFFSET; - /* grab the offset in mbr where to write this partition entry. */ - item->offset = (loff_t)((uintptr_t)((uint8_t *)(&mbr->ptable[pnum]))); - } - - pentry = (struct pc_partition *) &item->data; - - /* need a standard primary partition entry */ - if (pinfo) { - /* need this to be 64 bit in case len_kb is large */ - uint64_t len_lba; - - if (pinfo->len_kb != (uint32_t)-1) { - /* bump it up to the next LBA boundary just in case */ - len_lba = ((uint64_t)pinfo->len_kb * 1024); - len_lba += ((uint64_t)dinfo->sect_size - 1); - len_lba &= ~((uint64_t)dinfo->sect_size - 1); - len_lba /= (uint64_t)dinfo->sect_size; - } else { - /* make it fill the rest of disk */ - len_lba = dinfo->num_lba - *lba; - } - - cfg_pentry(pentry, ((pinfo->flags & PART_ACTIVE_FLAG) ? - PC_PART_ACTIVE : PC_PART_NORMAL), - pinfo->type, *lba, (uint32_t)len_lba); - - pinfo->start_lba = *lba; - *lba += (uint32_t)len_lba; - } else { - /* this should be made an extended partition, and should take - * up the rest of the disk as a primary partition */ - cfg_pentry(pentry, PC_PART_NORMAL, PC_PART_TYPE_EXTENDED, - *lba, dinfo->num_lba - *lba); - - /* note that we do not update the *lba because we now have to - * create a chain of extended partition tables, and first one is at - * *lba */ - } - - return item; -} - - -/* This function configures an extended boot record at the beginning of an - * extended partition. This creates a logical partition and a pointer to - * the next EBR. - * - * ext_lba == The start of the toplevel extended partition (pointed to by the - * entry in the MBR). - */ -static struct write_list * -mk_ext_pentry(struct disk_info *dinfo, struct part_info *pinfo, uint32_t *lba, - uint32_t ext_lba, struct part_info *pnext) -{ - struct write_list *item; - struct pc_boot_record *ebr; - uint32_t len; /* in lba units */ - - if (!(item = alloc_wl(sizeof(struct pc_boot_record)))) { - ALOGE("Unable to allocate memory for EBR."); - return NULL; - } - - /* we are going to write the ebr at the current LBA, and then bump the - * lba counter since that is where the logical data partition will start */ - item->offset = ((loff_t)(*lba)) * dinfo->sect_size; - (*lba)++; - - ebr = (struct pc_boot_record *) &item->data; - memset(ebr, 0, sizeof(struct pc_boot_record)); - ebr->mbr_sig = PC_BIOS_BOOT_SIG; - - if (pinfo->len_kb != (uint32_t)-1) - len = kb_to_lba(pinfo->len_kb, dinfo->sect_size); - else { - if (pnext) { - ALOGE("Only the last partition can be specified to fill the disk " - "(name = '%s')", pinfo->name); - goto fail; - } - len = dinfo->num_lba - *lba; - /* update the pinfo structure to reflect the new size, for - * bookkeeping */ - pinfo->len_kb = - (uint32_t)(((uint64_t)len * (uint64_t)dinfo->sect_size) / - ((uint64_t)1024)); - } - - cfg_pentry(&ebr->ptable[PC_EBR_LOGICAL_PART], PC_PART_NORMAL, - pinfo->type, 1, len); - - pinfo->start_lba = *lba; - *lba += len; - - /* If this is not the last partition, we have to create a link to the - * next extended partition. - * - * Otherwise, there's nothing to do since the "pointer entry" is - * already zero-filled. - */ - if (pnext) { - /* The start lba for next partition is an offset from the beginning - * of the top-level extended partition */ - uint32_t next_start_lba = *lba - ext_lba; - uint32_t next_len_lba; - if (pnext->len_kb != (uint32_t)-1) - next_len_lba = 1 + kb_to_lba(pnext->len_kb, dinfo->sect_size); - else - next_len_lba = dinfo->num_lba - *lba; - cfg_pentry(&ebr->ptable[PC_EBR_NEXT_PTR_PART], PC_PART_NORMAL, - PC_PART_TYPE_EXTENDED, next_start_lba, next_len_lba); - } - - return item; - -fail: - free_wl(item); - return NULL; -} - - -static struct write_list * -mk_mbr_sig() -{ - struct write_list *item; - if (!(item = alloc_wl(sizeof(uint16_t)))) { - ALOGE("Unable to allocate memory for MBR signature."); - return NULL; - } - - { - /* DO NOT DEREFERENCE */ - struct pc_boot_record *mbr = (void *)PC_MBR_DISK_OFFSET; - /* grab the offset in mbr where to write mbr signature. */ - item->offset = (loff_t)((uintptr_t)((uint8_t *)(&mbr->mbr_sig))); - } - - *((uint16_t*)item->data) = PC_BIOS_BOOT_SIG; - return item; -} - -struct write_list * -config_mbr(struct disk_info *dinfo) -{ - struct part_info *pinfo; - uint32_t cur_lba = dinfo->skip_lba; - uint32_t ext_lba = 0; - struct write_list *wr_list = NULL; - struct write_list *temp_wr = NULL; - int cnt = 0; - int extended = 0; - - if (!dinfo->part_lst) - return NULL; - - for (cnt = 0; cnt < dinfo->num_parts; ++cnt) { - pinfo = &dinfo->part_lst[cnt]; - - /* Should we create an extedned partition? */ - if (cnt == (PC_NUM_BOOT_RECORD_PARTS - 1)) { - if (cnt + 1 < dinfo->num_parts) { - extended = 1; - ext_lba = cur_lba; - if ((temp_wr = mk_pri_pentry(dinfo, NULL, cnt, &cur_lba))) - wlist_add(&wr_list, temp_wr); - else { - ALOGE("Cannot create primary extended partition."); - goto fail; - } - } - } - - /* if extended, need 1 lba for ebr */ - if ((cur_lba + extended) >= dinfo->num_lba) - goto nospace; - else if (pinfo->len_kb != (uint32_t)-1) { - uint32_t sz_lba = (pinfo->len_kb / dinfo->sect_size) * 1024; - if ((cur_lba + sz_lba + extended) > dinfo->num_lba) - goto nospace; - } - - if (!extended) - temp_wr = mk_pri_pentry(dinfo, pinfo, cnt, &cur_lba); - else { - struct part_info *pnext; - pnext = cnt + 1 < dinfo->num_parts ? &dinfo->part_lst[cnt+1] : NULL; - temp_wr = mk_ext_pentry(dinfo, pinfo, &cur_lba, ext_lba, pnext); - } - - if (temp_wr) - wlist_add(&wr_list, temp_wr); - else { - ALOGE("Cannot create partition %d (%s).", cnt, pinfo->name); - goto fail; - } - } - - /* fill in the rest of the MBR with empty parts (if needed). */ - for (; cnt < PC_NUM_BOOT_RECORD_PARTS; ++cnt) { - struct part_info blank; - cur_lba = 0; - memset(&blank, 0, sizeof(struct part_info)); - if (!(temp_wr = mk_pri_pentry(dinfo, &blank, cnt, &cur_lba))) { - ALOGE("Cannot create blank partition %d.", cnt); - goto fail; - } - wlist_add(&wr_list, temp_wr); - } - - if ((temp_wr = mk_mbr_sig())) - wlist_add(&wr_list, temp_wr); - else { - ALOGE("Cannot set MBR signature"); - goto fail; - } - - return wr_list; - -nospace: - ALOGE("Not enough space to add parttion '%s'.", pinfo->name); - -fail: - wlist_free(wr_list); - return NULL; -} - - -/* Returns the device path of the partition referred to by 'name' - * Must be freed by the caller. - */ -char * -find_mbr_part(struct disk_info *dinfo, const char *name) -{ - struct part_info *plist = dinfo->part_lst; - int num = 0; - char *dev_name = NULL; - int has_extended = (dinfo->num_parts > PC_NUM_BOOT_RECORD_PARTS); - - for(num = 1; num <= dinfo->num_parts; ++num) { - if (!strcmp(plist[num-1].name, name)) - break; - } - - if (num > dinfo->num_parts) - return NULL; - - if (has_extended && (num >= PC_NUM_BOOT_RECORD_PARTS)) - num++; - - if (!(dev_name = malloc(MAX_NAME_LEN))) { - ALOGE("Cannot allocate memory."); - return NULL; - } - - num = snprintf(dev_name, MAX_NAME_LEN, "%s%d", dinfo->device, num); - if (num >= MAX_NAME_LEN) { - ALOGE("Device name is too long?!"); - free(dev_name); - return NULL; - } - - return dev_name; -} diff --git a/libdiskconfig/diskconfig.c b/libdiskconfig/diskconfig.c deleted file mode 100644 index 5f34748b0989..000000000000 --- a/libdiskconfig/diskconfig.c +++ /dev/null @@ -1,535 +0,0 @@ -/* libs/diskconfig/diskconfig.c - * - * Copyright 2008, 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. - */ - -#define LOG_TAG "diskconfig" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -static int -parse_len(const char *str, uint64_t *plen) -{ - char tmp[64]; - int len_str; - uint32_t multiple = 1; - - strncpy(tmp, str, sizeof(tmp)); - tmp[sizeof(tmp)-1] = '\0'; - len_str = strlen(tmp); - if (!len_str) { - ALOGE("Invalid disk length specified."); - return 1; - } - - switch(tmp[len_str - 1]) { - case 'M': case 'm': - /* megabyte */ - multiple <<= 10; - case 'K': case 'k': - /* kilobytes */ - multiple <<= 10; - tmp[len_str - 1] = '\0'; - break; - default: - break; - } - - *plen = strtoull(tmp, NULL, 0); - if (!*plen) { - ALOGE("Invalid length specified: %s", str); - return 1; - } - - if (*plen == (uint64_t)-1) { - if (multiple > 1) { - ALOGE("Size modifier illegal when len is -1"); - return 1; - } - } else { - /* convert len to kilobytes */ - if (multiple > 1024) - multiple >>= 10; - *plen *= multiple; - - if (*plen > 0xffffffffULL) { - ALOGE("Length specified is too large!: %"PRIu64" KB", *plen); - return 1; - } - } - - return 0; -} - - -static int -load_partitions(cnode *root, struct disk_info *dinfo) -{ - cnode *partnode; - - dinfo->num_parts = 0; - for (partnode = root->first_child; partnode; partnode = partnode->next) { - struct part_info *pinfo = &dinfo->part_lst[dinfo->num_parts]; - const char *tmp; - - /* bleh, i will leak memory here, but i DONT CARE since - * the only right thing to do when this function fails - * is to quit */ - pinfo->name = strdup(partnode->name); - - if(config_bool(partnode, "active", 0)) - pinfo->flags |= PART_ACTIVE_FLAG; - - if (!(tmp = config_str(partnode, "type", NULL))) { - ALOGE("Partition type required: %s", pinfo->name); - return 1; - } - - /* possible values are: linux, fat32 */ - if (!strcmp(tmp, "linux")) { - pinfo->type = PC_PART_TYPE_LINUX; - } else if (!strcmp(tmp, "fat32")) { - pinfo->type = PC_PART_TYPE_FAT32; - } else { - ALOGE("Unsupported partition type found: %s", tmp); - return 1; - } - - if ((tmp = config_str(partnode, "len", NULL)) != NULL) { - uint64_t len; - if (parse_len(tmp, &len)) - return 1; - pinfo->len_kb = (uint32_t) len; - } else - pinfo->len_kb = 0; - - ++dinfo->num_parts; - } - - return 0; -} - -struct disk_info * -load_diskconfig(const char *fn, char *path_override) -{ - struct disk_info *dinfo; - cnode *devroot; - cnode *partnode; - cnode *root = config_node("", ""); - const char *tmp; - - if (!(dinfo = malloc(sizeof(struct disk_info)))) { - ALOGE("Could not malloc disk_info"); - return NULL; - } - memset(dinfo, 0, sizeof(struct disk_info)); - - if (!(dinfo->part_lst = malloc(MAX_NUM_PARTS * sizeof(struct part_info)))) { - ALOGE("Could not malloc part_lst"); - goto fail; - } - memset(dinfo->part_lst, 0, - (MAX_NUM_PARTS * sizeof(struct part_info))); - - config_load_file(root, fn); - if (root->first_child == NULL) { - ALOGE("Could not read config file %s", fn); - goto fail; - } - - if (!(devroot = config_find(root, "device"))) { - ALOGE("Could not find device section in config file '%s'", fn); - goto fail; - } - - - if (!(tmp = config_str(devroot, "path", path_override))) { - ALOGE("device path is requried"); - goto fail; - } - dinfo->device = strdup(tmp); - - /* find the partition scheme */ - if (!(tmp = config_str(devroot, "scheme", NULL))) { - ALOGE("partition scheme is required"); - goto fail; - } else if (!strcmp(tmp, "mbr")) { - dinfo->scheme = PART_SCHEME_MBR; - } else if (!strcmp(tmp, "gpt")) { - ALOGE("'gpt' partition scheme not supported yet."); - goto fail; - } else { - ALOGE("Unknown partition scheme specified: %s", tmp); - goto fail; - } - - /* grab the sector size (in bytes) */ - tmp = config_str(devroot, "sector_size", "512"); - dinfo->sect_size = strtol(tmp, NULL, 0); - if (!dinfo->sect_size) { - ALOGE("Invalid sector size: %s", tmp); - goto fail; - } - - /* first lba where the partitions will start on disk */ - if (!(tmp = config_str(devroot, "start_lba", NULL))) { - ALOGE("start_lba must be provided"); - goto fail; - } - - if (!(dinfo->skip_lba = strtol(tmp, NULL, 0))) { - ALOGE("Invalid starting LBA (or zero): %s", tmp); - goto fail; - } - - /* Number of LBAs on disk */ - if (!(tmp = config_str(devroot, "num_lba", NULL))) { - ALOGE("num_lba is required"); - goto fail; - } - dinfo->num_lba = strtoul(tmp, NULL, 0); - - if (!(partnode = config_find(devroot, "partitions"))) { - ALOGE("Device must specify partition list"); - goto fail; - } - - if (load_partitions(partnode, dinfo)) - goto fail; - - return dinfo; - -fail: - if (dinfo->part_lst) - free(dinfo->part_lst); - if (dinfo->device) - free(dinfo->device); - free(dinfo); - return NULL; -} - -static int -sync_ptable(int fd) -{ - struct stat stat; - int rv; - - sync(); - - if (fstat(fd, &stat)) { - ALOGE("Cannot stat, errno=%d.", errno); - return -1; - } - - if (S_ISBLK(stat.st_mode) && ((rv = ioctl(fd, BLKRRPART, NULL)) < 0)) { - ALOGE("Could not re-read partition table. REBOOT!. (errno=%d)", errno); - return -1; - } - - return 0; -} - -/* This function verifies that the disk info provided is valid, and if so, - * returns an open file descriptor. - * - * This does not necessarily mean that it will later be successfully written - * though. If we use the pc-bios partitioning scheme, we must use extended - * partitions, which eat up some hd space. If the user manually provisioned - * every single partition, but did not account for the extra needed space, - * then we will later fail. - * - * TODO: Make validation more complete. - */ -static int -validate(struct disk_info *dinfo) -{ - int fd; - int sect_sz; - uint64_t disk_size; - uint64_t total_size; - int cnt; - struct stat stat; - - if (!dinfo) - return -1; - - if ((fd = open(dinfo->device, O_RDWR)) < 0) { - ALOGE("Cannot open device '%s' (errno=%d)", dinfo->device, errno); - return -1; - } - - if (fstat(fd, &stat)) { - ALOGE("Cannot stat file '%s', errno=%d.", dinfo->device, errno); - goto fail; - } - - - /* XXX: Some of the code below is kind of redundant and should probably - * be refactored a little, but it will do for now. */ - - /* Verify that we can operate on the device that was requested. - * We presently only support block devices and regular file images. */ - if (S_ISBLK(stat.st_mode)) { - /* get the sector size and make sure we agree */ - if (ioctl(fd, BLKSSZGET, §_sz) < 0) { - ALOGE("Cannot get sector size (errno=%d)", errno); - goto fail; - } - - if (!sect_sz || sect_sz != dinfo->sect_size) { - ALOGE("Device sector size is zero or sector sizes do not match!"); - goto fail; - } - - /* allow the user override the "disk size" if they provided num_lba */ - if (!dinfo->num_lba) { - if (ioctl(fd, BLKGETSIZE64, &disk_size) < 0) { - ALOGE("Could not get block device size (errno=%d)", errno); - goto fail; - } - /* XXX: we assume that the disk has < 2^32 sectors :-) */ - dinfo->num_lba = (uint32_t)(disk_size / (uint64_t)dinfo->sect_size); - } else - disk_size = (uint64_t)dinfo->num_lba * (uint64_t)dinfo->sect_size; - } else if (S_ISREG(stat.st_mode)) { - ALOGI("Requesting operation on a regular file, not block device."); - if (!dinfo->sect_size) { - ALOGE("Sector size for regular file images cannot be zero"); - goto fail; - } - if (dinfo->num_lba) - disk_size = (uint64_t)dinfo->num_lba * (uint64_t)dinfo->sect_size; - else { - dinfo->num_lba = (uint32_t)(stat.st_size / dinfo->sect_size); - disk_size = (uint64_t)stat.st_size; - } - } else { - ALOGE("Device does not refer to a regular file or a block device!"); - goto fail; - } - -#if 1 - ALOGV("Device/file %s: size=%" PRIu64 " bytes, num_lba=%u, sect_size=%d", - dinfo->device, disk_size, dinfo->num_lba, dinfo->sect_size); -#endif - - /* since this is our offset into the disk, we start off with that as - * our size of needed partitions */ - total_size = dinfo->skip_lba * dinfo->sect_size; - - /* add up all the partition sizes and make sure it fits */ - for (cnt = 0; cnt < dinfo->num_parts; ++cnt) { - struct part_info *part = &dinfo->part_lst[cnt]; - if (part->len_kb != (uint32_t)-1) { - total_size += part->len_kb * 1024; - } else if (part->len_kb == 0) { - ALOGE("Zero-size partition '%s' is invalid.", part->name); - goto fail; - } else { - /* the partition requests the rest of the disk. */ - if (cnt + 1 != dinfo->num_parts) { - ALOGE("Only the last partition in the list can request to fill " - "the rest of disk."); - goto fail; - } - } - - if ((part->type != PC_PART_TYPE_LINUX) && - (part->type != PC_PART_TYPE_FAT32)) { - ALOGE("Unknown partition type (0x%x) encountered for partition " - "'%s'\n", part->type, part->name); - goto fail; - } - } - - /* only matters for disks, not files */ - if (S_ISBLK(stat.st_mode) && total_size > disk_size) { - ALOGE("Total requested size of partitions (%"PRIu64") is greater than disk " - "size (%"PRIu64").", total_size, disk_size); - goto fail; - } - - return fd; - -fail: - close(fd); - return -1; -} - -static int -validate_and_config(struct disk_info *dinfo, int *fd, struct write_list **lst) -{ - *lst = NULL; - *fd = -1; - - if ((*fd = validate(dinfo)) < 0) - return 1; - - switch (dinfo->scheme) { - case PART_SCHEME_MBR: - *lst = config_mbr(dinfo); - return *lst == NULL; - case PART_SCHEME_GPT: - /* not supported yet */ - default: - ALOGE("Unknown partition scheme."); - break; - } - - close(*fd); - *lst = NULL; - return 1; -} - -/* validate and process the disk layout configuration. - * This will cause an update to the partitions' start lba. - * - * Basically, this does the same thing as apply_disk_config in test mode, - * except that wlist_commit is not called to print out the data to be - * written. - */ -int -process_disk_config(struct disk_info *dinfo) -{ - struct write_list *lst; - int fd; - - if (validate_and_config(dinfo, &fd, &lst) != 0) - return 1; - - close(fd); - wlist_free(lst); - return 0; -} - - -int -apply_disk_config(struct disk_info *dinfo, int test) -{ - int fd; - struct write_list *wr_lst = NULL; - int rv; - - if (validate_and_config(dinfo, &fd, &wr_lst) != 0) { - ALOGE("Configuration is invalid."); - goto fail; - } - - if ((rv = wlist_commit(fd, wr_lst, test)) >= 0) - rv = test ? 0 : sync_ptable(fd); - - close(fd); - wlist_free(wr_lst); - return rv; - -fail: - close(fd); - if (wr_lst) - wlist_free(wr_lst); - return 1; -} - -int -dump_disk_config(struct disk_info *dinfo) -{ - int cnt; - struct part_info *part; - - printf("Device: %s\n", dinfo->device); - printf("Scheme: "); - switch (dinfo->scheme) { - case PART_SCHEME_MBR: - printf("MBR"); - break; - case PART_SCHEME_GPT: - printf("GPT (unsupported)"); - break; - default: - printf("Unknown"); - break; - } - printf ("\n"); - - printf("Sector size: %d\n", dinfo->sect_size); - printf("Skip leading LBAs: %u\n", dinfo->skip_lba); - printf("Number of LBAs: %u\n", dinfo->num_lba); - printf("Partitions:\n"); - - for (cnt = 0; cnt < dinfo->num_parts; ++cnt) { - part = &dinfo->part_lst[cnt]; - printf("\tname = %s\n", part->name); - printf("\t\tflags = %s\n", - part->flags & PART_ACTIVE_FLAG ? "Active" : "None"); - printf("\t\ttype = %s\n", - part->type == PC_PART_TYPE_LINUX ? "Linux" : "Unknown"); - if (part->len_kb == (uint32_t)-1) - printf("\t\tlen = rest of disk\n"); - else - printf("\t\tlen = %uKB\n", part->len_kb); - } - printf("Total number of partitions: %d\n", cnt); - printf("\n"); - - return 0; -} - -struct part_info * -find_part(struct disk_info *dinfo, const char *name) -{ - struct part_info *pinfo; - int cnt; - - for (cnt = 0; cnt < dinfo->num_parts; ++cnt) { - pinfo = &dinfo->part_lst[cnt]; - if (!strcmp(pinfo->name, name)) - return pinfo; - } - - return NULL; -} - -/* NOTE: If the returned ptr is non-NULL, it must be freed by the caller. */ -char * -find_part_device(struct disk_info *dinfo, const char *name) -{ - switch (dinfo->scheme) { - case PART_SCHEME_MBR: - return find_mbr_part(dinfo, name); - case PART_SCHEME_GPT: - ALOGE("GPT is presently not supported"); - break; - default: - ALOGE("Unknown partition table scheme"); - break; - } - - return NULL; -} - - diff --git a/libdiskconfig/diskutils.c b/libdiskconfig/diskutils.c deleted file mode 100644 index fe1b4c180a79..000000000000 --- a/libdiskconfig/diskutils.c +++ /dev/null @@ -1,118 +0,0 @@ -/* libs/diskconfig/diskutils.c - * - * Copyright 2008, 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. - */ - -#define LOG_TAG "diskutils" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -int -write_raw_image(const char *dst, const char *src, loff_t offset, int test) -{ - int dst_fd = -1; - int src_fd = -1; - uint8_t buffer[2048]; - ssize_t nr_bytes; - ssize_t tmp; - int done = 0; - uint64_t total = 0; - - ALOGI("Writing RAW image '%s' to '%s' (offset=%llu)", src, dst, (unsigned long long)offset); - if ((src_fd = open(src, O_RDONLY)) < 0) { - ALOGE("Could not open %s for reading (errno=%d).", src, errno); - goto fail; - } - - if (!test) { - if ((dst_fd = open(dst, O_RDWR)) < 0) { - ALOGE("Could not open '%s' for read/write (errno=%d).", dst, errno); - goto fail; - } - - if (lseek64(dst_fd, offset, SEEK_SET) != offset) { - ALOGE("Could not seek to offset %lld in %s.", (long long)offset, dst); - goto fail; - } - } - - while (!done) { - if ((nr_bytes = read(src_fd, buffer, sizeof(buffer))) < 0) { - /* XXX: Should we not even bother with EINTR? */ - if (errno == EINTR) - continue; - ALOGE("Error (%d) while reading from '%s'", errno, src); - goto fail; - } - - if (!nr_bytes) { - /* we're done. */ - done = 1; - break; - } - - total += nr_bytes; - - /* skip the write loop if we're testing */ - if (test) - nr_bytes = 0; - - while (nr_bytes > 0) { - if ((tmp = write(dst_fd, buffer, nr_bytes)) < 0) { - /* XXX: Should we not even bother with EINTR? */ - if (errno == EINTR) - continue; - ALOGE("Error (%d) while writing to '%s'", errno, dst); - goto fail; - } - if (!tmp) - continue; - nr_bytes -= tmp; - } - } - - if (!done) { - ALOGE("Exited read/write loop without setting flag! WTF?!"); - goto fail; - } - - if (dst_fd >= 0) - fsync(dst_fd); - - ALOGI("Wrote %" PRIu64 " bytes to %s @ %lld", total, dst, (long long)offset); - - close(src_fd); - if (dst_fd >= 0) - close(dst_fd); - return 0; - -fail: - if (dst_fd >= 0) - close(dst_fd); - if (src_fd >= 0) - close(src_fd); - return 1; -} diff --git a/libdiskconfig/dump_diskconfig.c b/libdiskconfig/dump_diskconfig.c deleted file mode 100644 index 3c4f620058e6..000000000000 --- a/libdiskconfig/dump_diskconfig.c +++ /dev/null @@ -1,43 +0,0 @@ -/* libs/diskconfig/dump_diskconfig.c - * - * Copyright 2008, 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. - */ - -#define LOG_TAG "dump_diskconfig" - -#include - -#include - -#include "diskconfig.h" - -int -main(int argc, char *argv[]) -{ - struct disk_info *dinfo; - - if (argc < 2) { - ALOGE("usage: %s ", argv[0]); - return 1; - } - - if (!(dinfo = load_diskconfig(argv[1], NULL))) - return 1; - - dump_disk_config(dinfo); - - return 0; -} - diff --git a/libdiskconfig/include/diskconfig/diskconfig.h b/libdiskconfig/include/diskconfig/diskconfig.h deleted file mode 100644 index d45b99e24872..000000000000 --- a/libdiskconfig/include/diskconfig/diskconfig.h +++ /dev/null @@ -1,130 +0,0 @@ -/* system/core/include/diskconfig/diskconfig.h - * - * Copyright 2008, 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. - */ - -#ifndef __LIBS_DISKCONFIG_H -#define __LIBS_DISKCONFIG_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define MAX_NAME_LEN 512 -#define MAX_NUM_PARTS 16 - -/* known partition schemes */ -#define PART_SCHEME_MBR 0x1 -#define PART_SCHEME_GPT 0x2 - -/* PC Bios partition status */ -#define PC_PART_ACTIVE 0x80 -#define PC_PART_NORMAL 0x0 - -/* Known (rather, used by us) partition types */ -#define PC_PART_TYPE_LINUX 0x83 -#define PC_PART_TYPE_EXTENDED 0x05 -#define PC_PART_TYPE_FAT32 0x0c - -#define PC_NUM_BOOT_RECORD_PARTS 4 - -#define PC_EBR_LOGICAL_PART 0 -#define PC_EBR_NEXT_PTR_PART 1 - -#define PC_BIOS_BOOT_SIG 0xAA55 - -#define PC_MBR_DISK_OFFSET 0 -#define PC_MBR_SIZE 512 - -#define PART_ACTIVE_FLAG 0x1 - -struct chs { - uint8_t head; - uint8_t sector; - uint8_t cylinder; -} __attribute__((__packed__)); - -/* 16 byte pc partition descriptor that sits in MBR and EPBR. - * Note: multi-byte entities have little-endian layout on disk */ -struct pc_partition { - uint8_t status; /* byte 0 */ - struct chs start; /* bytes 1-3 */ - uint8_t type; /* byte 4 */ - struct chs end; /* bytes 5-7 */ - uint32_t start_lba; /* bytes 8-11 */ - uint32_t len_lba; /* bytes 12-15 */ -} __attribute__((__packed__)); - -struct pc_boot_record { - uint8_t code[440]; /* bytes 0-439 */ - uint32_t disk_sig; /* bytes 440-443 */ - uint16_t pad; /* bytes 444-445 */ - struct pc_partition ptable[PC_NUM_BOOT_RECORD_PARTS]; /* bytes 446-509 */ - uint16_t mbr_sig; /* bytes 510-511 */ -} __attribute__((__packed__)); - -struct part_info { - char *name; - uint8_t flags; - uint8_t type; - uint32_t len_kb; /* in 1K-bytes */ - uint32_t start_lba; /* the LBA where this partition begins */ -}; - -struct disk_info { - char *device; - uint8_t scheme; - int sect_size; /* expected sector size in bytes. MUST BE POWER OF 2 */ - uint32_t skip_lba; /* in sectors (1 unit of LBA) */ - uint32_t num_lba; /* the size of the disk in LBA units */ - struct part_info *part_lst; - int num_parts; -}; - -struct write_list { - struct write_list *next; - loff_t offset; - uint32_t len; - uint8_t data[0]; -}; - - -struct write_list *alloc_wl(uint32_t data_len); -void free_wl(struct write_list *item); -struct write_list *wlist_add(struct write_list **lst, struct write_list *item); -void wlist_free(struct write_list *lst); -int wlist_commit(int fd, struct write_list *lst, int test); - -struct disk_info *load_diskconfig(const char *fn, char *path_override); -int dump_disk_config(struct disk_info *dinfo); -int apply_disk_config(struct disk_info *dinfo, int test); -char *find_part_device(struct disk_info *dinfo, const char *name); -int process_disk_config(struct disk_info *dinfo); -struct part_info *find_part(struct disk_info *dinfo, const char *name); - -int write_raw_image(const char *dst, const char *src, loff_t offset, int test); - -/* For MBR partition schemes */ -struct write_list *config_mbr(struct disk_info *dinfo); -char *find_mbr_part(struct disk_info *dinfo, const char *name); - -#ifdef __cplusplus -} -#endif - -#endif /* __LIBS_DISKCONFIG_H */ diff --git a/libdiskconfig/write_lst.c b/libdiskconfig/write_lst.c deleted file mode 100644 index c3d5c0ac1b9c..000000000000 --- a/libdiskconfig/write_lst.c +++ /dev/null @@ -1,92 +0,0 @@ -/* libs/diskconfig/write_lst.c - * - * Copyright 2008, 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. - */ - -#define LOG_TAG "write_lst" - -#include -#include -#include -#include -#include - -#include -#include - -struct write_list * -alloc_wl(uint32_t data_len) -{ - struct write_list *item; - - if (!(item = malloc(sizeof(struct write_list) + data_len))) { - ALOGE("Unable to allocate memory."); - return NULL; - } - - item->len = data_len; - return item; -} - -void -free_wl(struct write_list *item) -{ - if (item) - free(item); -} - -struct write_list * -wlist_add(struct write_list **lst, struct write_list *item) -{ - item->next = (*lst); - *lst = item; - return item; -} - -void -wlist_free(struct write_list *lst) -{ - struct write_list *temp_wr; - while (lst) { - temp_wr = lst->next; - free_wl(lst); - lst = temp_wr; - } -} - -int -wlist_commit(int fd, struct write_list *lst, int test) -{ - for(; lst; lst = lst->next) { - if (lseek64(fd, lst->offset, SEEK_SET) != (loff_t)lst->offset) { - ALOGE("Cannot seek to the specified position (%lld).", (long long)lst->offset); - goto fail; - } - - if (!test) { - if (write(fd, lst->data, lst->len) != (int)lst->len) { - ALOGE("Failed writing %u bytes at position %lld.", lst->len, - (long long)lst->offset); - goto fail; - } - } else - ALOGI("Would write %d bytes @ offset %lld.", lst->len, (long long)lst->offset); - } - - return 0; - -fail: - return -1; -} From 702a779edb5d71d9f1be82713482a51ff69a8a3d Mon Sep 17 00:00:00 2001 From: Ray Chin Date: Tue, 23 May 2023 17:43:50 +0800 Subject: [PATCH 0066/1487] Fix overflow issue when computing ideal size of scratch partition The type of f_frsize is `unsigned long` which is 32 bit for some system so it will overflow after multiplied by f_bfree. This solution adds one more type casting to ensure the type is 64 bit unsigned integer during the computing. Bug: 281599020 Test: adb root; adb shell disable-verity Change-Id: I377ed722d5e245c235c3ae12ff66ac7e91d1d6e8 --- fs_mgr/fs_mgr_overlayfs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index ef436e580023..f04fc8d2f1b5 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -1083,7 +1083,7 @@ static inline uint64_t GetIdealDataScratchSize() { return 0; } - auto ideal_size = std::min(super_info.size, uint64_t(s.f_frsize * s.f_bfree * 0.85)); + auto ideal_size = std::min(super_info.size, uint64_t(uint64_t(s.f_frsize) * s.f_bfree * 0.85)); // Align up to the filesystem block size. if (auto remainder = ideal_size % s.f_bsize; remainder > 0) { From 5a9905a62bf819d9eca4a7439ee51a8b5d12ef9d Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 23 May 2023 10:51:01 -0700 Subject: [PATCH 0067/1487] Fixing constructors to match header files Constructor in cpp file doesn't match header file Test: m fastboot, fastboot flashall -w Change-Id: I2c720bb594efca5af1e5a374277543a522ced5ef --- fastboot/task.cpp | 4 ++-- fastboot/task.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fastboot/task.cpp b/fastboot/task.cpp index ce46e91d5095..e98effb26d26 100644 --- a/fastboot/task.cpp +++ b/fastboot/task.cpp @@ -26,9 +26,9 @@ #include "util.h" using namespace std::string_literals; -FlashTask::FlashTask(const std::string& _slot, const std::string& _pname, const std::string& _fname, +FlashTask::FlashTask(const std::string& slot, const std::string& pname, const std::string& fname, const bool apply_vbmeta) - : pname_(_pname), fname_(_fname), slot_(_slot), apply_vbmeta_(apply_vbmeta) {} + : pname_(pname), fname_(fname), slot_(slot), apply_vbmeta_(apply_vbmeta) {} void FlashTask::Run() { auto flash = [&](const std::string& partition) { diff --git a/fastboot/task.h b/fastboot/task.h index 34e3e92aaebd..d113f18d585b 100644 --- a/fastboot/task.h +++ b/fastboot/task.h @@ -118,7 +118,7 @@ class ResizeTask : public Task { class DeleteTask : public Task { public: - DeleteTask(const FlashingPlan* _fp, const std::string& _pname); + DeleteTask(const FlashingPlan* fp, const std::string& pname); void Run() override; private: From 4350592133f3b52671d680f91203f1596183033c Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 22 May 2023 22:21:46 +0000 Subject: [PATCH 0068/1487] init_kill_services_test: special case apexd apexd restarts the device, so it causes flakes here, especially in presubmit. Bug: 280514080 Test: init_kill_services_test Change-Id: I4455704795961f3ae94e29bdf098eca739130973 --- init/test_kill_services/init_kill_services_test.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/init/test_kill_services/init_kill_services_test.cpp b/init/test_kill_services/init_kill_services_test.cpp index 227380d719dc..d9fcd9d45376 100644 --- a/init/test_kill_services/init_kill_services_test.cpp +++ b/init/test_kill_services/init_kill_services_test.cpp @@ -23,8 +23,15 @@ using ::android::base::GetProperty; using ::android::base::SetProperty; +using ::android::base::WaitForProperty; +using std::literals::chrono_literals::operator""s; void ExpectKillingServiceRecovers(const std::string& service_name) { + // b/280514080 - servicemanager will restart apexd, and apexd will restart the + // system when crashed. This is fine as the device recovers, but it causes + // flakes in this test. + ASSERT_TRUE(WaitForProperty("init.svc.apexd", "stopped", 60s)) << "apexd won't stop"; + LOG(INFO) << "hello " << service_name << "!"; const std::string status_prop = "init.svc." + service_name; const std::string pid_prop = "init.svc_debug_pid." + service_name; From 8231c3fe2da24bacdeb0d38edecd99aa098fa34c Mon Sep 17 00:00:00 2001 From: Jack Wu Date: Fri, 19 May 2023 14:31:53 +0800 Subject: [PATCH 0069/1487] BatteryMonitor: support battery health INCONSISTENT from health status Report Battery health INCONSISTENT when there is a battery recalibration pending. Bug: 283182048 Test: m Change-Id: I8b944ddac7cc919fc95b1b71b015101642a62f96 Signed-off-by: Jack Wu --- healthd/BatteryMonitor.cpp | 2 ++ healthd/include/healthd/BatteryMonitor.h | 1 + 2 files changed, 3 insertions(+) diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp index f68d65a54d70..bd7955a7f8b4 100644 --- a/healthd/BatteryMonitor.cpp +++ b/healthd/BatteryMonitor.cpp @@ -244,6 +244,8 @@ BatteryHealth getBatteryHealthStatus(int status) { value = BatteryHealth::UNSPECIFIED_FAILURE; else if (status == BatteryMonitor::BH_NOT_AVAILABLE) value = BatteryHealth::NOT_AVAILABLE; + else if (status == BatteryMonitor::BH_INCONSISTENT) + value = BatteryHealth::INCONSISTENT; else value = BatteryHealth::UNKNOWN; diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h index a4c013b86b33..e9998ba7a3af 100644 --- a/healthd/include/healthd/BatteryMonitor.h +++ b/healthd/include/healthd/BatteryMonitor.h @@ -63,6 +63,7 @@ class BatteryMonitor { BH_NEEDS_REPLACEMENT, BH_FAILED, BH_NOT_AVAILABLE, + BH_INCONSISTENT, }; BatteryMonitor(); From 98d6242dc767d6f5fa15e4f63643391ae8e7c47f Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Wed, 24 May 2023 20:01:10 +0000 Subject: [PATCH 0070/1487] Limit the number of log messages in a tombstone. Some testing environments can have a test that is sending many thousands of messages to the log. When this type of process crashes all of these log messages are captured and can cause OOM errors while creating the tombstone. Added a test to verify the log messages are truncated. Leaving this test disabled for now since it is inherently flaky due to having to assume that 500 messages are in the log. Added a test for a newline in a log message since it's somewhat related to this change. NOTE: The total number of messages is capped at 500, but if a message contains multiple newlines, the total messages will exceed 500. Counting messages this way seems to be in the spirit of the cap, that a process logging a large message with multiple newlines does not completely fill the tombstone log data. Bug: 269182937 Bug: 282661754 Test: All unit tests pass. Test: The disabled max_log_messages test passes. Change-Id: If18e62b29f899c2c4670101b402e37762bffbec6 --- debuggerd/debuggerd_test.cpp | 45 ++++++++++++++++++++++ debuggerd/libdebuggerd/tombstone_proto.cpp | 7 +++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index 39d7fff1ca86..4cd619337167 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -2759,3 +2759,48 @@ TEST_F(CrasherTest, logd_skips_reading_logs_not_main_thread) { ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal"); ASSERT_NOT_MATCH(result, kLogMessage); } + +// Disable this test since there is a high liklihood that this would +// be flaky since it requires 500 messages being in the log. +TEST_F(CrasherTest, DISABLED_max_log_messages) { + StartProcess([]() { + for (size_t i = 0; i < 600; i++) { + LOG(INFO) << "Message number " << i; + } + abort(); + }); + + unique_fd output_fd; + StartIntercept(&output_fd); + FinishCrasher(); + AssertDeath(SIGABRT); + int intercept_result; + FinishIntercept(&intercept_result); + ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; + + std::string result; + ConsumeFd(std::move(output_fd), &result); + ASSERT_NOT_MATCH(result, "Message number 99"); + ASSERT_MATCH(result, "Message number 100"); + ASSERT_MATCH(result, "Message number 599"); +} + +TEST_F(CrasherTest, log_with_newline) { + StartProcess([]() { + LOG(INFO) << "This line has a newline.\nThis is on the next line."; + abort(); + }); + + unique_fd output_fd; + StartIntercept(&output_fd); + FinishCrasher(); + AssertDeath(SIGABRT); + int intercept_result; + FinishIntercept(&intercept_result); + ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; + + std::string result; + ConsumeFd(std::move(output_fd), &result); + ASSERT_MATCH(result, ":\\s*This line has a newline."); + ASSERT_MATCH(result, ":\\s*This is on the next line."); +} diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp index acd814efa68b..7b2e0689e440 100644 --- a/debuggerd/libdebuggerd/tombstone_proto.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto.cpp @@ -70,6 +70,9 @@ using android::base::StringPrintf; +// The maximum number of messages to save in the protobuf per file. +static constexpr size_t kMaxLogMessages = 500; + // Use the demangler from libc++. extern "C" char* __cxa_demangle(const char*, char*, size_t*, int* status); @@ -491,8 +494,8 @@ static void dump_mappings(Tombstone* tombstone, unwindstack::Maps* maps, } static void dump_log_file(Tombstone* tombstone, const char* logger, pid_t pid) { - logger_list* logger_list = - android_logger_list_open(android_name_to_log_id(logger), ANDROID_LOG_NONBLOCK, 0, pid); + logger_list* logger_list = android_logger_list_open(android_name_to_log_id(logger), + ANDROID_LOG_NONBLOCK, kMaxLogMessages, pid); LogBuffer buffer; From 7003fba5f2864ad5138a42fb4bef36bea0cbc944 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Wed, 24 May 2023 20:01:10 +0000 Subject: [PATCH 0071/1487] Limit the number of log messages in a tombstone. Some testing environments can have a test that is sending many thousands of messages to the log. When this type of process crashes all of these log messages are captured and can cause OOM errors while creating the tombstone. Added a test to verify the log messages are truncated. Leaving this test disabled for now since it is inherently flaky due to having to assume that 500 messages are in the log. Added a test for a newline in a log message since it's somewhat related to this change. NOTE: The total number of messages is capped at 500, but if a message contains multiple newlines, the total messages will exceed 500. Counting messages this way seems to be in the spirit of the cap, that a process logging a large message with multiple newlines does not completely fill the tombstone log data. Bug: 269182937 Bug: 282661754 Test: All unit tests pass. Test: The disabled max_log_messages test passes. Change-Id: If18e62b29f899c2c4670101b402e37762bffbec6 Merged-In: If18e62b29f899c2c4670101b402e37762bffbec6 (cherry picked from commit 98d6242dc767d6f5fa15e4f63643391ae8e7c47f) --- debuggerd/debuggerd_test.cpp | 45 ++++++++++++++++++++++ debuggerd/libdebuggerd/tombstone_proto.cpp | 7 +++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index 39d7fff1ca86..4cd619337167 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -2759,3 +2759,48 @@ TEST_F(CrasherTest, logd_skips_reading_logs_not_main_thread) { ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal"); ASSERT_NOT_MATCH(result, kLogMessage); } + +// Disable this test since there is a high liklihood that this would +// be flaky since it requires 500 messages being in the log. +TEST_F(CrasherTest, DISABLED_max_log_messages) { + StartProcess([]() { + for (size_t i = 0; i < 600; i++) { + LOG(INFO) << "Message number " << i; + } + abort(); + }); + + unique_fd output_fd; + StartIntercept(&output_fd); + FinishCrasher(); + AssertDeath(SIGABRT); + int intercept_result; + FinishIntercept(&intercept_result); + ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; + + std::string result; + ConsumeFd(std::move(output_fd), &result); + ASSERT_NOT_MATCH(result, "Message number 99"); + ASSERT_MATCH(result, "Message number 100"); + ASSERT_MATCH(result, "Message number 599"); +} + +TEST_F(CrasherTest, log_with_newline) { + StartProcess([]() { + LOG(INFO) << "This line has a newline.\nThis is on the next line."; + abort(); + }); + + unique_fd output_fd; + StartIntercept(&output_fd); + FinishCrasher(); + AssertDeath(SIGABRT); + int intercept_result; + FinishIntercept(&intercept_result); + ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; + + std::string result; + ConsumeFd(std::move(output_fd), &result); + ASSERT_MATCH(result, ":\\s*This line has a newline."); + ASSERT_MATCH(result, ":\\s*This is on the next line."); +} diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp index acd814efa68b..7b2e0689e440 100644 --- a/debuggerd/libdebuggerd/tombstone_proto.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto.cpp @@ -70,6 +70,9 @@ using android::base::StringPrintf; +// The maximum number of messages to save in the protobuf per file. +static constexpr size_t kMaxLogMessages = 500; + // Use the demangler from libc++. extern "C" char* __cxa_demangle(const char*, char*, size_t*, int* status); @@ -491,8 +494,8 @@ static void dump_mappings(Tombstone* tombstone, unwindstack::Maps* maps, } static void dump_log_file(Tombstone* tombstone, const char* logger, pid_t pid) { - logger_list* logger_list = - android_logger_list_open(android_name_to_log_id(logger), ANDROID_LOG_NONBLOCK, 0, pid); + logger_list* logger_list = android_logger_list_open(android_name_to_log_id(logger), + ANDROID_LOG_NONBLOCK, kMaxLogMessages, pid); LogBuffer buffer; From 4d8f37edae8e471e8524a3bd3b88f46700200d4d Mon Sep 17 00:00:00 2001 From: liwentao Date: Thu, 25 May 2023 18:03:43 +0800 Subject: [PATCH 0072/1487] Updated the policy file associated with riscv64 The generate.sh script can generate the file, but current policy file does not match it. And the rules are not appropriate, like missing "sysinfo", causing the debuggerd_test to fail in system model. So we match the policy to what it should be. Test: make debuggerd_test Change-Id: I57ebd7713f2ab939d01bfefcc7935e234fdd3e13 Signed-off-by: liwentao --- debuggerd/seccomp_policy/crash_dump.riscv64.policy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debuggerd/seccomp_policy/crash_dump.riscv64.policy b/debuggerd/seccomp_policy/crash_dump.riscv64.policy index 21887abe0799..281e231b0135 100644 --- a/debuggerd/seccomp_policy/crash_dump.riscv64.policy +++ b/debuggerd/seccomp_policy/crash_dump.riscv64.policy @@ -19,12 +19,13 @@ getdents64: 1 faccessat: 1 recvmsg: 1 recvfrom: 1 +sysinfo: 1 process_vm_readv: 1 tgkill: 1 rt_sigprocmask: 1 rt_sigaction: 1 rt_tgsigqueueinfo: 1 -prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41 || arg0 == PR_PAC_RESET_KEYS +prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41 madvise: 1 mprotect: arg2 in 0x1|0x2 munmap: 1 From 004a16739d4c746b3b5e082d986a30bb21476f40 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Wed, 24 May 2023 13:47:37 -0700 Subject: [PATCH 0073/1487] Check get_gwp_asan_callbacks before calling. When using the bootstrap linker, the get_gwp_asan_callbacks is not set. Therefore, check it is not nullptr before calling it during crash processing. Bug: 284098779 Test: Ran crasher64 using /system/bin/bootstrap/linker64 and verify Test: debuggerd code does not crash. Test: All unit tests pass. Change-Id: Ifc710fe4bef24661700444a1b69432bfc29d580f --- debuggerd/handler/debuggerd_handler.cpp | 32 ++++++++++++++----------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp index baa5bfb50677..c6a535ad6d7f 100644 --- a/debuggerd/handler/debuggerd_handler.cpp +++ b/debuggerd/handler/debuggerd_handler.cpp @@ -566,20 +566,23 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c process_info = g_callbacks.get_process_info(); } - // GWP-ASan catches use-after-free and heap-buffer-overflow by using PROT_NONE - // guard pages, which lead to SEGV. Normally, debuggerd prints a bug report - // and the process terminates, but in some cases, we actually want to print - // the bug report and let the signal handler return, and restart the process. - // In order to do that, we need to disable GWP-ASan's guard pages. The - // following callbacks handle this case. - gwp_asan_callbacks_t gwp_asan_callbacks = g_callbacks.get_gwp_asan_callbacks(); - if (signal_number == SIGSEGV && signal_has_si_addr(info) && - gwp_asan_callbacks.debuggerd_needs_gwp_asan_recovery && - gwp_asan_callbacks.debuggerd_gwp_asan_pre_crash_report && - gwp_asan_callbacks.debuggerd_gwp_asan_post_crash_report && - gwp_asan_callbacks.debuggerd_needs_gwp_asan_recovery(info->si_addr)) { - gwp_asan_callbacks.debuggerd_gwp_asan_pre_crash_report(info->si_addr); - process_info.recoverable_gwp_asan_crash = true; + gwp_asan_callbacks_t gwp_asan_callbacks = {}; + if (g_callbacks.get_gwp_asan_callbacks != nullptr) { + // GWP-ASan catches use-after-free and heap-buffer-overflow by using PROT_NONE + // guard pages, which lead to SEGV. Normally, debuggerd prints a bug report + // and the process terminates, but in some cases, we actually want to print + // the bug report and let the signal handler return, and restart the process. + // In order to do that, we need to disable GWP-ASan's guard pages. The + // following callbacks handle this case. + gwp_asan_callbacks = g_callbacks.get_gwp_asan_callbacks(); + if (signal_number == SIGSEGV && signal_has_si_addr(info) && + gwp_asan_callbacks.debuggerd_needs_gwp_asan_recovery && + gwp_asan_callbacks.debuggerd_gwp_asan_pre_crash_report && + gwp_asan_callbacks.debuggerd_gwp_asan_post_crash_report && + gwp_asan_callbacks.debuggerd_needs_gwp_asan_recovery(info->si_addr)) { + gwp_asan_callbacks.debuggerd_gwp_asan_pre_crash_report(info->si_addr); + process_info.recoverable_gwp_asan_crash = true; + } } // If sival_int is ~0, it means that the fallback handler has been called @@ -764,6 +767,7 @@ void debuggerd_init(debuggerd_callbacks_t* callbacks) { bool debuggerd_handle_signal(int signal_number, siginfo_t* info, void* context) { if (signal_number != SIGSEGV || !signal_has_si_addr(info)) return false; + if (g_callbacks.get_gwp_asan_callbacks == nullptr) return false; gwp_asan_callbacks_t gwp_asan_callbacks = g_callbacks.get_gwp_asan_callbacks(); if (gwp_asan_callbacks.debuggerd_needs_gwp_asan_recovery == nullptr || gwp_asan_callbacks.debuggerd_gwp_asan_pre_crash_report == nullptr || From 791a83bb4565b3b2a4e3d40ea2c0ec592cfb0d04 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 23 May 2023 10:42:39 -0700 Subject: [PATCH 0074/1487] Chang flash task to take in source Old changes didn't actually take into account sources. fastboot update {update.zip} should read fastboot-info from the update package. It was instead flashing local images + reading local fastboot-info.txt Test: m fastboot, fastboot update, fastboot flashall Bug: 283330320 Change-Id: I9587a7735ddfbfb661153eb12ebc3caa7c32f141 --- fastboot/fastboot.cpp | 47 +++++++++++++++++++++---------------------- fastboot/fastboot.h | 3 ++- fastboot/task.cpp | 6 +++--- fastboot/task.h | 3 ++- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index f09616a49507..f5fd3a1ea350 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1487,13 +1487,20 @@ static std::string repack_ramdisk(const char* pname, struct fastboot_buffer* buf return partition; } -void do_flash(const char* pname, const char* fname, const bool apply_vbmeta) { +void do_flash(const char* pname, const char* fname, const bool apply_vbmeta, + const FlashingPlan* fp) { verbose("Do flash %s %s", pname, fname); struct fastboot_buffer buf; - if (!load_buf(fname, &buf)) { + if (fp->source) { + unique_fd fd = fp->source->OpenFile(fname); + if (fd < 0 || !load_buf_fd(std::move(fd), &buf)) { + die("could not load '%s': %s", fname, strerror(errno)); + } + } else if (!load_buf(fname, &buf)) { die("cannot load '%s': %s", fname, strerror(errno)); } + if (is_logical(pname)) { fb->ResizePartition(pname, std::to_string(buf.image_size)); } @@ -1592,7 +1599,7 @@ std::unique_ptr ParseFlashCommand(const FlashingPlan* fp, if (img_name.empty()) { img_name = partition + ".img"; } - return std::make_unique(slot, partition, img_name, apply_vbmeta); + return std::make_unique(slot, partition, img_name, apply_vbmeta, fp); } std::unique_ptr ParseRebootCommand(const FlashingPlan* fp, @@ -1666,7 +1673,7 @@ void AddResizeTasks(const FlashingPlan* fp, std::vector>* } static bool IsIgnore(const std::vector& command) { - if (command[0][0] == '#') { + if (command.size() == 0 || command[0][0] == '#') { return true; } return false; @@ -1748,16 +1755,6 @@ std::vector> ParseFastbootInfo(const FlashingPlan* fp, return tasks; } -std::vector> ParseFastbootInfo(const FlashingPlan* fp, std::ifstream& fs) { - std::string text; - std::vector file; - // Get os_partitions that need to be resized - while (std::getline(fs, text)) { - file.emplace_back(text); - } - return ParseFastbootInfo(fp, file); -} - FlashAllTool::FlashAllTool(FlashingPlan* fp) : fp_(fp) {} void FlashAllTool::Flash() { @@ -1777,16 +1774,17 @@ void FlashAllTool::Flash() { CancelSnapshotIfNeeded(); - std::string path = find_item_given_name("fastboot-info.txt"); - std::ifstream stream(path); - if (!stream || stream.eof()) { + std::vector contents; + if (!fp_->source->ReadFile("fastboot-info.txt", &contents)) { LOG(VERBOSE) << "Flashing from hardcoded images. fastboot-info.txt is empty or does not " "exist"; HardcodedFlash(); return; } - std::vector> tasks = ParseFastbootInfo(fp_, stream); + std::vector> tasks = + ParseFastbootInfo(fp_, Split({contents.data(), contents.size()}, "\n")); + if (tasks.empty()) { LOG(FATAL) << "Invalid fastboot-info.txt file."; } @@ -2115,7 +2113,7 @@ bool should_flash_in_userspace(const std::string& partition_name) { } static bool wipe_super(const android::fs_mgr::LpMetadata& metadata, const std::string& slot, - std::string* message) { + std::string* message, const FlashingPlan* fp) { auto super_device = GetMetadataSuperBlockDevice(metadata); auto block_size = metadata.geometry.logical_block_size; auto super_bdev_name = android::fs_mgr::GetBlockDevicePartitionName(*super_device); @@ -2155,7 +2153,7 @@ static bool wipe_super(const android::fs_mgr::LpMetadata& metadata, const std::s auto image_path = temp_dir.path + "/"s + image_name; auto flash = [&](const std::string& partition_name) { - do_flash(partition_name.c_str(), image_path.c_str(), false); + do_flash(partition_name.c_str(), image_path.c_str(), false, fp); }; do_for_partitions(partition, slot, flash, force_slot); @@ -2164,7 +2162,8 @@ static bool wipe_super(const android::fs_mgr::LpMetadata& metadata, const std::s return true; } -static void do_wipe_super(const std::string& image, const std::string& slot_override) { +static void do_wipe_super(const std::string& image, const std::string& slot_override, + const FlashingPlan* fp) { if (access(image.c_str(), R_OK) != 0) { die("Could not read image: %s", image.c_str()); } @@ -2179,7 +2178,7 @@ static void do_wipe_super(const std::string& image, const std::string& slot_over } std::string message; - if (!wipe_super(*metadata.get(), slot, &message)) { + if (!wipe_super(*metadata.get(), slot, &message, fp)) { die(message); } } @@ -2476,7 +2475,7 @@ int FastBootTool::Main(int argc, char* argv[]) { } if (fname.empty()) die("cannot determine image filename for '%s'", pname.c_str()); - FlashTask task(fp->slot_override, pname, fname, is_vbmeta_partition(pname)); + FlashTask task(fp->slot_override, pname, fname, is_vbmeta_partition(pname), fp.get()); task.Run(); } else if (command == "flash:raw") { std::string partition = next_arg(&args); @@ -2571,7 +2570,7 @@ int FastBootTool::Main(int argc, char* argv[]) { } else { image = next_arg(&args); } - do_wipe_super(image, fp->slot_override); + do_wipe_super(image, fp->slot_override, fp.get()); } else if (command == "snapshot-update") { std::string arg; if (!args.empty()) { diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index 80b77a0e95e3..0a1f1eb66773 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -124,7 +124,8 @@ class FlashAllTool { bool should_flash_in_userspace(const std::string& partition_name); bool is_userspace_fastboot(); -void do_flash(const char* pname, const char* fname, const bool apply_vbmeta); +void do_flash(const char* pname, const char* fname, const bool apply_vbmeta, + const FlashingPlan* fp); void do_for_partitions(const std::string& part, const std::string& slot, const std::function& func, bool force_slot); std::string find_item(const std::string& item); diff --git a/fastboot/task.cpp b/fastboot/task.cpp index e98effb26d26..cb12060b8624 100644 --- a/fastboot/task.cpp +++ b/fastboot/task.cpp @@ -27,8 +27,8 @@ using namespace std::string_literals; FlashTask::FlashTask(const std::string& slot, const std::string& pname, const std::string& fname, - const bool apply_vbmeta) - : pname_(pname), fname_(fname), slot_(slot), apply_vbmeta_(apply_vbmeta) {} + const bool apply_vbmeta, const FlashingPlan* fp) + : pname_(pname), fname_(fname), slot_(slot), apply_vbmeta_(apply_vbmeta), fp_(fp) {} void FlashTask::Run() { auto flash = [&](const std::string& partition) { @@ -41,7 +41,7 @@ void FlashTask::Run() { "And try again. If you are intentionally trying to " "overwrite a fixed partition, use --force."); } - do_flash(partition.c_str(), fname_.c_str(), apply_vbmeta_); + do_flash(partition.c_str(), fname_.c_str(), apply_vbmeta_, fp_); }; do_for_partitions(pname_, slot_, flash, true); } diff --git a/fastboot/task.h b/fastboot/task.h index d113f18d585b..82e8ebf51e01 100644 --- a/fastboot/task.h +++ b/fastboot/task.h @@ -46,7 +46,7 @@ class Task { class FlashTask : public Task { public: FlashTask(const std::string& slot, const std::string& pname, const std::string& fname, - const bool apply_vbmeta); + const bool apply_vbmeta, const FlashingPlan* fp); virtual FlashTask* AsFlashTask() override { return this; } std::string GetPartition() { return pname_; } @@ -60,6 +60,7 @@ class FlashTask : public Task { const std::string fname_; const std::string slot_; const bool apply_vbmeta_; + const FlashingPlan* fp_; }; class RebootTask : public Task { From 2775df617e5ea96e1f9adf9fb55758d7bd0cdfe7 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Thu, 25 May 2023 15:14:59 -0700 Subject: [PATCH 0075/1487] Removing should_flash_in_userspace check This check isn't needed as super_flash_helper.cpp calls a different should_flash_in_userspace that isn't reliant on $ANDROID_PRODUCT_OUT being set. Current code will fail when calling fastboot update Test: fastboot update update.zip without calling lunch Bug: 283330320 Change-Id: Icefe6092befb747b7f419ea997e0834602808d69 --- fastboot/task.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fastboot/task.cpp b/fastboot/task.cpp index cb12060b8624..9ce2cfd201d7 100644 --- a/fastboot/task.cpp +++ b/fastboot/task.cpp @@ -214,11 +214,9 @@ std::unique_ptr FlashSuperLayoutTask::InitializeFromTasks( for (const auto& task : tasks) { if (auto flash_task = task->AsFlashTask()) { - if (should_flash_in_userspace(flash_task->GetPartitionAndSlot())) { - auto partition = flash_task->GetPartitionAndSlot(); - if (!helper->AddPartition(partition, flash_task->GetImageName(), false)) { - return nullptr; - } + auto partition = flash_task->GetPartitionAndSlot(); + if (!helper->AddPartition(partition, flash_task->GetImageName(), false)) { + return nullptr; } } } From 30e648b346599d9bd745e083148e545afa4142f2 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Thu, 25 May 2023 15:56:29 -0700 Subject: [PATCH 0076/1487] Keeping naming consistent Test: m fastboot Change-Id: I46d798fa2ce78a255dc0ea414f5e25782f45c4d1 --- fastboot/fastboot.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index f5fd3a1ea350..fcad0d915ddc 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -775,7 +775,7 @@ static int make_temporary_fd(const char* what) { #endif -static unique_fd unzip_to_file(ZipArchiveHandle zip, const char* entry_name) { +static unique_fd UnzipToFile(ZipArchiveHandle zip, const char* entry_name) { unique_fd fd(make_temporary_fd(entry_name)); ZipEntry64 zip_entry; @@ -1928,7 +1928,7 @@ bool ZipImageSource::ReadFile(const std::string& name, std::vector* out) c } unique_fd ZipImageSource::OpenFile(const std::string& name) const { - return unzip_to_file(zip_, name.c_str()); + return UnzipToFile(zip_, name.c_str()); } static void do_update(const char* filename, FlashingPlan* fp) { From d278f1d01822e47fa1e7292f6bbe87967d8db297 Mon Sep 17 00:00:00 2001 From: Will McVicker Date: Thu, 25 May 2023 16:43:31 -0700 Subject: [PATCH 0077/1487] toolbox/modprobe: Fix fallback path when mod_dirs is empty Due to GKI, the kernel UTS release string will not always (if ever) match the vendor's UTS release string that is used to create the initramfs file structure -- /lib/modules/. This causes module load failures when `-d DIR` is omitted. To fix this, we can include all of the versions under /lib/modules that match the kernel's major and minor version instead of directly using the value of uname(). In addition, we can also support modules being loaded directly from /lib/modules. Test: verify GKI kernel + initramfs with different UTS strings Test: verify GKI kernel + initramfs with modules directly in /lib/modules Fixes: 83207784251c ("toolbox/modprobe: Fallback to /lib/modules/ ") Bug: 282917063 Bug: 254835242 Change-Id: I5368f5cff139ba3165323a6a91066be38bfa0736 --- toolbox/modprobe.cpp | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/toolbox/modprobe.cpp b/toolbox/modprobe.cpp index 17f815697ef3..17d4e319b6b5 100644 --- a/toolbox/modprobe.cpp +++ b/toolbox/modprobe.cpp @@ -85,6 +85,26 @@ void MyLogger(android::base::LogId id, android::base::LogSeverity severity, cons } } +// Find directories in format of "/lib/modules/x.y.z-*". +static int KernelVersionNameFilter(const dirent* de) { + unsigned int major, minor; + static std::string kernel_version; + utsname uts; + + if (kernel_version.empty()) { + if ((uname(&uts) != 0) || (sscanf(uts.release, "%u.%u", &major, &minor) != 2)) { + LOG(ERROR) << "Could not parse the kernel version from uname"; + return 0; + } + kernel_version = android::base::StringPrintf("%u.%u", major, minor); + } + + if (android::base::StartsWith(de->d_name, kernel_version)) { + return 1; + } + return 0; +} + } // anonymous namespace extern "C" int modprobe_main(int argc, char** argv) { @@ -192,9 +212,22 @@ extern "C" int modprobe_main(int argc, char** argv) { } if (mod_dirs.empty()) { - utsname uts; - uname(&uts); - mod_dirs.emplace_back(android::base::StringPrintf("/lib/modules/%s", uts.release)); + static constexpr auto LIB_MODULES_PREFIX = "/lib/modules/"; + dirent** kernel_dirs = NULL; + + int n = scandir(LIB_MODULES_PREFIX, &kernel_dirs, KernelVersionNameFilter, NULL); + if (n == -1) { + PLOG(ERROR) << "Failed to scan dir " << LIB_MODULES_PREFIX; + return EXIT_FAILURE; + } else if (n > 0) { + while (n--) { + mod_dirs.emplace_back(LIB_MODULES_PREFIX + std::string(kernel_dirs[n]->d_name)); + } + } + free(kernel_dirs); + + // Allow modules to be directly inside /lib/modules + mod_dirs.emplace_back(LIB_MODULES_PREFIX); } LOG(DEBUG) << "mode is " << mode; @@ -212,11 +245,6 @@ extern "C" int modprobe_main(int argc, char** argv) { return EXIT_FAILURE; } } - if (mod_dirs.empty()) { - LOG(ERROR) << "No module configuration directories given."; - print_usage(); - return EXIT_FAILURE; - } if (parameter_count && modules.size() > 1) { LOG(ERROR) << "Only one module may be loaded when specifying module parameters."; print_usage(); From cf140fb761dc0437af9c2268d4869e2778c24900 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Wed, 24 May 2023 13:47:37 -0700 Subject: [PATCH 0078/1487] Check get_gwp_asan_callbacks before calling. When using the bootstrap linker, the get_gwp_asan_callbacks is not set. Therefore, check it is not nullptr before calling it during crash processing. Bug: 284098779 Test: Ran crasher64 using /system/bin/bootstrap/linker64 and verify Test: debuggerd code does not crash. Test: All unit tests pass. Change-Id: Ifc710fe4bef24661700444a1b69432bfc29d580f Merged-In: Ifc710fe4bef24661700444a1b69432bfc29d580f (cherry picked from commit 004a16739d4c746b3b5e082d986a30bb21476f40) --- debuggerd/handler/debuggerd_handler.cpp | 32 ++++++++++++++----------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp index baa5bfb50677..c6a535ad6d7f 100644 --- a/debuggerd/handler/debuggerd_handler.cpp +++ b/debuggerd/handler/debuggerd_handler.cpp @@ -566,20 +566,23 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c process_info = g_callbacks.get_process_info(); } - // GWP-ASan catches use-after-free and heap-buffer-overflow by using PROT_NONE - // guard pages, which lead to SEGV. Normally, debuggerd prints a bug report - // and the process terminates, but in some cases, we actually want to print - // the bug report and let the signal handler return, and restart the process. - // In order to do that, we need to disable GWP-ASan's guard pages. The - // following callbacks handle this case. - gwp_asan_callbacks_t gwp_asan_callbacks = g_callbacks.get_gwp_asan_callbacks(); - if (signal_number == SIGSEGV && signal_has_si_addr(info) && - gwp_asan_callbacks.debuggerd_needs_gwp_asan_recovery && - gwp_asan_callbacks.debuggerd_gwp_asan_pre_crash_report && - gwp_asan_callbacks.debuggerd_gwp_asan_post_crash_report && - gwp_asan_callbacks.debuggerd_needs_gwp_asan_recovery(info->si_addr)) { - gwp_asan_callbacks.debuggerd_gwp_asan_pre_crash_report(info->si_addr); - process_info.recoverable_gwp_asan_crash = true; + gwp_asan_callbacks_t gwp_asan_callbacks = {}; + if (g_callbacks.get_gwp_asan_callbacks != nullptr) { + // GWP-ASan catches use-after-free and heap-buffer-overflow by using PROT_NONE + // guard pages, which lead to SEGV. Normally, debuggerd prints a bug report + // and the process terminates, but in some cases, we actually want to print + // the bug report and let the signal handler return, and restart the process. + // In order to do that, we need to disable GWP-ASan's guard pages. The + // following callbacks handle this case. + gwp_asan_callbacks = g_callbacks.get_gwp_asan_callbacks(); + if (signal_number == SIGSEGV && signal_has_si_addr(info) && + gwp_asan_callbacks.debuggerd_needs_gwp_asan_recovery && + gwp_asan_callbacks.debuggerd_gwp_asan_pre_crash_report && + gwp_asan_callbacks.debuggerd_gwp_asan_post_crash_report && + gwp_asan_callbacks.debuggerd_needs_gwp_asan_recovery(info->si_addr)) { + gwp_asan_callbacks.debuggerd_gwp_asan_pre_crash_report(info->si_addr); + process_info.recoverable_gwp_asan_crash = true; + } } // If sival_int is ~0, it means that the fallback handler has been called @@ -764,6 +767,7 @@ void debuggerd_init(debuggerd_callbacks_t* callbacks) { bool debuggerd_handle_signal(int signal_number, siginfo_t* info, void* context) { if (signal_number != SIGSEGV || !signal_has_si_addr(info)) return false; + if (g_callbacks.get_gwp_asan_callbacks == nullptr) return false; gwp_asan_callbacks_t gwp_asan_callbacks = g_callbacks.get_gwp_asan_callbacks(); if (gwp_asan_callbacks.debuggerd_needs_gwp_asan_recovery == nullptr || gwp_asan_callbacks.debuggerd_gwp_asan_pre_crash_report == nullptr || From e067e96da26111e446c5deadefd839a6451dd6d1 Mon Sep 17 00:00:00 2001 From: Will McVicker Date: Thu, 25 May 2023 16:43:31 -0700 Subject: [PATCH 0079/1487] toolbox/modprobe: Fix fallback path when mod_dirs is empty Due to GKI, the kernel UTS release string will not always (if ever) match the vendor's UTS release string that is used to create the initramfs file structure -- /lib/modules/. This causes module load failures when `-d DIR` is omitted. To fix this, we can include all of the versions under /lib/modules that match the kernel's major and minor version instead of directly using the value of uname(). In addition, we can also support modules being loaded directly from /lib/modules. Test: verify GKI kernel + initramfs with different UTS strings Test: verify GKI kernel + initramfs with modules directly in /lib/modules Fixes: 83207784251c ("toolbox/modprobe: Fallback to /lib/modules/ ") Bug: 282917063 Bug: 254835242 Merged-In: I5368f5cff139ba3165323a6a91066be38bfa0736 Change-Id: I5368f5cff139ba3165323a6a91066be38bfa0736 --- toolbox/modprobe.cpp | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/toolbox/modprobe.cpp b/toolbox/modprobe.cpp index 17f815697ef3..17d4e319b6b5 100644 --- a/toolbox/modprobe.cpp +++ b/toolbox/modprobe.cpp @@ -85,6 +85,26 @@ void MyLogger(android::base::LogId id, android::base::LogSeverity severity, cons } } +// Find directories in format of "/lib/modules/x.y.z-*". +static int KernelVersionNameFilter(const dirent* de) { + unsigned int major, minor; + static std::string kernel_version; + utsname uts; + + if (kernel_version.empty()) { + if ((uname(&uts) != 0) || (sscanf(uts.release, "%u.%u", &major, &minor) != 2)) { + LOG(ERROR) << "Could not parse the kernel version from uname"; + return 0; + } + kernel_version = android::base::StringPrintf("%u.%u", major, minor); + } + + if (android::base::StartsWith(de->d_name, kernel_version)) { + return 1; + } + return 0; +} + } // anonymous namespace extern "C" int modprobe_main(int argc, char** argv) { @@ -192,9 +212,22 @@ extern "C" int modprobe_main(int argc, char** argv) { } if (mod_dirs.empty()) { - utsname uts; - uname(&uts); - mod_dirs.emplace_back(android::base::StringPrintf("/lib/modules/%s", uts.release)); + static constexpr auto LIB_MODULES_PREFIX = "/lib/modules/"; + dirent** kernel_dirs = NULL; + + int n = scandir(LIB_MODULES_PREFIX, &kernel_dirs, KernelVersionNameFilter, NULL); + if (n == -1) { + PLOG(ERROR) << "Failed to scan dir " << LIB_MODULES_PREFIX; + return EXIT_FAILURE; + } else if (n > 0) { + while (n--) { + mod_dirs.emplace_back(LIB_MODULES_PREFIX + std::string(kernel_dirs[n]->d_name)); + } + } + free(kernel_dirs); + + // Allow modules to be directly inside /lib/modules + mod_dirs.emplace_back(LIB_MODULES_PREFIX); } LOG(DEBUG) << "mode is " << mode; @@ -212,11 +245,6 @@ extern "C" int modprobe_main(int argc, char** argv) { return EXIT_FAILURE; } } - if (mod_dirs.empty()) { - LOG(ERROR) << "No module configuration directories given."; - print_usage(); - return EXIT_FAILURE; - } if (parameter_count && modules.size() > 1) { LOG(ERROR) << "Only one module may be loaded when specifying module parameters."; print_usage(); From 4a7d98402c01c896a204e8b428f39e98dac598c6 Mon Sep 17 00:00:00 2001 From: Jack Wu Date: Fri, 19 May 2023 14:31:53 +0800 Subject: [PATCH 0080/1487] BatteryMonitor: support battery health INCONSISTENT from health status Report Battery health INCONSISTENT when there is a battery recalibration pending. Bug: 283182048 Test: m Ignore-AOSP-First: cherry-pick from aosp Change-Id: I8b944ddac7cc919fc95b1b71b015101642a62f96 Merged-In: I8b944ddac7cc919fc95b1b71b015101642a62f96 Signed-off-by: Jack Wu --- healthd/BatteryMonitor.cpp | 2 ++ healthd/include/healthd/BatteryMonitor.h | 1 + 2 files changed, 3 insertions(+) diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp index f68d65a54d70..bd7955a7f8b4 100644 --- a/healthd/BatteryMonitor.cpp +++ b/healthd/BatteryMonitor.cpp @@ -244,6 +244,8 @@ BatteryHealth getBatteryHealthStatus(int status) { value = BatteryHealth::UNSPECIFIED_FAILURE; else if (status == BatteryMonitor::BH_NOT_AVAILABLE) value = BatteryHealth::NOT_AVAILABLE; + else if (status == BatteryMonitor::BH_INCONSISTENT) + value = BatteryHealth::INCONSISTENT; else value = BatteryHealth::UNKNOWN; diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h index a4c013b86b33..e9998ba7a3af 100644 --- a/healthd/include/healthd/BatteryMonitor.h +++ b/healthd/include/healthd/BatteryMonitor.h @@ -63,6 +63,7 @@ class BatteryMonitor { BH_NEEDS_REPLACEMENT, BH_FAILED, BH_NOT_AVAILABLE, + BH_INCONSISTENT, }; BatteryMonitor(); From 997ce15d5e50e1e8ff5b8f7ac3a8d45f4519ea47 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 30 May 2023 09:24:46 -0700 Subject: [PATCH 0081/1487] Update add resizetasks to work in update Old should_flash_in_userspace doesn't work if $ANDROID_PRODUCT_OUT is not set. Also adding in a check to see if resizetasks were added correctly Test: fastboot update update.zip without $ANDROID_PRODUCT_OUT and removing the flashsuperlayout code. Bug: 283330320 Change-Id: Ib72f6a1cf07745daf70fffae3d1a6b8352e3f79c --- fastboot/fastboot.cpp | 20 +++++++++++++++----- fastboot/fastboot.h | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index fcad0d915ddc..3a135bc4699d 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1646,14 +1646,22 @@ std::unique_ptr ParseFastbootInfoLine(const FlashingPlan* fp, return task; } -void AddResizeTasks(const FlashingPlan* fp, std::vector>* tasks) { +bool AddResizeTasks(const FlashingPlan* fp, std::vector>* tasks) { // expands "resize-partitions" into individual commands : resize {os_partition_1}, resize // {os_partition_2}, etc. std::vector> resize_tasks; std::optional loc; + std::vector contents; + if (!fp->source->ReadFile("super_empty.img", &contents)) { + return false; + } + auto metadata = android::fs_mgr::ReadFromImageBlob(contents.data(), contents.size()); + if (!metadata) { + return false; + } for (size_t i = 0; i < tasks->size(); i++) { if (auto flash_task = tasks->at(i)->AsFlashTask()) { - if (should_flash_in_userspace(flash_task->GetPartitionAndSlot())) { + if (should_flash_in_userspace(*metadata.get(), flash_task->GetPartitionAndSlot())) { if (!loc) { loc = i; } @@ -1665,11 +1673,11 @@ void AddResizeTasks(const FlashingPlan* fp, std::vector>* // if no logical partitions (although should never happen since system will always need to be // flashed) if (!loc) { - return; + return false; } tasks->insert(tasks->begin() + loc.value(), std::make_move_iterator(resize_tasks.begin()), std::make_move_iterator(resize_tasks.end())); - return; + return true; } static bool IsIgnore(const std::vector& command) { @@ -1750,7 +1758,9 @@ std::vector> ParseFastbootInfo(const FlashingPlan* fp, } tasks.insert(it, std::move(flash_super_task)); } else { - AddResizeTasks(fp, &tasks); + if (!AddResizeTasks(fp, &tasks)) { + LOG(WARNING) << "Failed to add resize tasks"; + }; } return tasks; } diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index 0a1f1eb66773..abdf63695053 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -144,7 +144,7 @@ std::unique_ptr ParseWipeCommand(const FlashingPlan* fp, const std::vector& parts); std::unique_ptr ParseFastbootInfoLine(const FlashingPlan* fp, const std::vector& command); -void AddResizeTasks(const FlashingPlan* fp, std::vector>& tasks); +bool AddResizeTasks(const FlashingPlan* fp, std::vector>& tasks); std::vector> ParseFastbootInfo(const FlashingPlan* fp, const std::vector& file); From 3e8ad4d546d401ad9da77c3d67ebd6ca19cd2c59 Mon Sep 17 00:00:00 2001 From: Hans Boehm Date: Wed, 31 May 2023 10:19:54 -0700 Subject: [PATCH 0082/1487] Halve iteration count for some RefBase tests The RacingDestructors test was occasionally timing out, by non-huge amounts. Halve the number of iterations for long-running tests here. Bug: 284964396 Test: Treehugger Change-Id: If639ce98fbeb783431f07006dece4cd69f9f8b50 --- libutils/RefBase_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libutils/RefBase_test.cpp b/libutils/RefBase_test.cpp index aed3b9b40b4f..d6755980508e 100644 --- a/libutils/RefBase_test.cpp +++ b/libutils/RefBase_test.cpp @@ -28,7 +28,7 @@ using namespace android; -static constexpr int NITERS = 1000000; +static constexpr int NITERS = 500000; static constexpr int INITIAL_STRONG_VALUE = 1 << 28; // Mirroring RefBase definition. From f8a9ba13f5a1202a8b2d4cf53f69ca1226df6b8c Mon Sep 17 00:00:00 2001 From: Edward Liaw Date: Wed, 31 May 2023 17:29:17 +0000 Subject: [PATCH 0083/1487] TEST_MAPPING: enable KernelLibcutilsTest in kernel-presubmit Bug: 284307085 Bug: 258819618 Test: atest :kernel-presubmit Change-Id: Ifa3427d3b7ff66d25ba58f5d16d0d62a709274a0 Signed-off-by: Edward Liaw --- libcutils/TEST_MAPPING | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libcutils/TEST_MAPPING b/libcutils/TEST_MAPPING index eb63aa5e7ce9..78b3e44e276d 100644 --- a/libcutils/TEST_MAPPING +++ b/libcutils/TEST_MAPPING @@ -12,6 +12,9 @@ "kernel-presubmit": [ { "name": "libcutils_test" + }, + { + "name": "KernelLibcutilsTest" } ] } From 2a56592d589e52928d86729301a367efd0c9817f Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Wed, 31 May 2023 11:20:08 -0700 Subject: [PATCH 0084/1487] Reverting code to old flashing code Falling back on old flashing code until fastboot-info is fixed Test: m fastboot, fastboot flashall Change-Id: I10146ec75f75d57d4a4049d35def370533619401 --- fastboot/fastboot.cpp | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 3a135bc4699d..bec4ef1e9447 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1784,28 +1784,8 @@ void FlashAllTool::Flash() { CancelSnapshotIfNeeded(); - std::vector contents; - if (!fp_->source->ReadFile("fastboot-info.txt", &contents)) { - LOG(VERBOSE) << "Flashing from hardcoded images. fastboot-info.txt is empty or does not " - "exist"; - HardcodedFlash(); - return; - } - - std::vector> tasks = - ParseFastbootInfo(fp_, Split({contents.data(), contents.size()}, "\n")); - - if (tasks.empty()) { - LOG(FATAL) << "Invalid fastboot-info.txt file."; - } - LOG(VERBOSE) << "Flashing from fastboot-info.txt"; - for (auto& task : tasks) { - task->Run(); - } - if (fp_->wants_wipe) { - // avoid adding duplicate wipe tasks in fastboot main code. - fp_->wants_wipe = false; - } + HardcodedFlash(); + return; } void FlashAllTool::CheckRequirements() { From c786b6d332266c5f6ab877fa04805cb4c176a536 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 12 Aug 2022 23:43:43 -0700 Subject: [PATCH 0085/1487] libsnapshot: Use SnapshotManager to delete devices. Diagnosing DM_DEV_REMOVE failures in the test harness is quite difficult, and it's not clear if failures are spurious or not. Instead use SnapshotManager's helper function, which can retry on failure, and will self-diagnose issues on legitimate failures. Bug: N/A Test: vts_libsnapshot_test Change-Id: Ibcaa8406e8b1e8758b99a8e9b58c58d68ed57685 Merged-In: Ibcaa8406e8b1e8758b99a8e9b58c58d68ed57685 (cherry picked from commit e02ef9e9ce4203c9132779521fb4118dd5667a79) --- fs_mgr/libsnapshot/snapshot_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index 9291b03f89a4..027e10fea673 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -289,7 +289,7 @@ class SnapshotTest : public ::testing::Test { } AssertionResult DeleteDevice(const std::string& device) { - if (!dm_.DeleteDeviceIfExists(device)) { + if (!sm->DeleteDeviceIfExists(device, 1s)) { return AssertionFailure() << "Can't delete " << device; } return AssertionSuccess(); From 1136e2fc30f3cf30a8ced10f9cf85a22760ab5df Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 11 Aug 2022 22:12:19 -0700 Subject: [PATCH 0086/1487] libsnapshot: Remove flaky image creation test. This test has always been flaky, and is not testing something super valuable: we know that image creation succeeds throughout the rest of the suite, so it's not very interesting to know that it can succeed in a low-space scenario. The inverse test is much more valuable, since we want the correct status code when creation fails due to low space. Bug: 240391002 Test: vts_libsnapshot_test Merged-In: I6235d11033d2f30efe530077b877863ba2574810 Change-Id: I6235d11033d2f30efe530077b877863ba2574810 (cherry picked from commit 97e8a2f0e963cea957ffd135be4436de3b3afd6a) --- fs_mgr/libsnapshot/snapshot_test.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index 9291b03f89a4..381497c68ec3 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -2417,7 +2417,6 @@ class ImageManagerTest : public SnapshotTest, public WithParamInterfaceBackingImageExists(kImageName) || image_manager_->DeleteBackingImage(kImageName)); @@ -2426,19 +2425,6 @@ class ImageManagerTest : public SnapshotTest, public WithParamInterface userdata_; }; -TEST_P(ImageManagerTest, CreateImageEnoughAvailSpace) { - if (userdata_->available_space() == 0) { - GTEST_SKIP() << "/data is full (" << userdata_->available_space() - << " bytes available), skipping"; - } - ASSERT_TRUE(image_manager_->CreateBackingImage(kImageName, userdata_->available_space(), - IImageManager::CREATE_IMAGE_DEFAULT)) - << "Should be able to create image with size = " << userdata_->available_space() - << " bytes"; - ASSERT_TRUE(image_manager_->DeleteBackingImage(kImageName)) - << "Should be able to delete created image"; -} - TEST_P(ImageManagerTest, CreateImageNoSpace) { uint64_t to_allocate = userdata_->free_space() + userdata_->bsize(); auto res = image_manager_->CreateBackingImage(kImageName, to_allocate, From ab5e5250509e06ce3f6cf7cdbd106909870086b4 Mon Sep 17 00:00:00 2001 From: Vova Sharaienko Date: Tue, 30 May 2023 19:47:07 +0000 Subject: [PATCH 0087/1487] Increasing length of the datagram for Unix Domain Socket - address p99 StatsD socket loss issue Bug: 284508851 Test: atest statsd_test Test: atest statsd_benchmark Ignore-AOSP-First: mitigate data loss in Android U Change-Id: I4124ba8d4d78733eb666073f6d29dfe0c0552c0f Merged-In: I4124ba8d4d78733eb666073f6d29dfe0c0552c0f --- rootdir/init.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index fdad27397473..0ee85c7412b9 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -295,7 +295,7 @@ on init write /proc/sys/kernel/randomize_va_space 2 write /proc/sys/vm/mmap_min_addr 32768 write /proc/sys/net/ipv4/ping_group_range "0 2147483647" - write /proc/sys/net/unix/max_dgram_qlen 600 + write /proc/sys/net/unix/max_dgram_qlen 2400 # Assign reasonable ceiling values for socket rcv/snd buffers. # These should almost always be overridden by the target per the From 99b308c9f6ce20a8758e8b5295268fc69602d42a Mon Sep 17 00:00:00 2001 From: Vova Sharaienko Date: Tue, 30 May 2023 19:47:07 +0000 Subject: [PATCH 0088/1487] Increasing length of the datagram for Unix Domain Socket - address p99 StatsD socket loss issue Bug: 284508851 Test: atest statsd_test Test: atest statsd_benchmark Ignore-AOSP-First: mitigate data loss in Android U Change-Id: I4124ba8d4d78733eb666073f6d29dfe0c0552c0f Merged-In: I4124ba8d4d78733eb666073f6d29dfe0c0552c0f --- rootdir/init.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 41c60a7f9dda..1e6918d0022c 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -315,7 +315,7 @@ on init write /proc/sys/kernel/randomize_va_space 2 write /proc/sys/vm/mmap_min_addr 32768 write /proc/sys/net/ipv4/ping_group_range "0 2147483647" - write /proc/sys/net/unix/max_dgram_qlen 600 + write /proc/sys/net/unix/max_dgram_qlen 2400 # Assign reasonable ceiling values for socket rcv/snd buffers. # These should almost always be overridden by the target per the From 6c008ff888c8c79c3322f8d06587407cf5a098b0 Mon Sep 17 00:00:00 2001 From: Dmitrii Merkurev Date: Fri, 2 Jun 2023 12:44:31 +0100 Subject: [PATCH 0089/1487] Avoid creating a storage folder for fastboot devices command Bug: 284267164 Bug: 284786311 Test: fastboot devices doesn't create a .fastboot folder Change-Id: I3e44c2a838e4287e6220c18f6e805cc71e0c9669 Signed-off-by: Dmitrii Merkurev --- fastboot/fastboot.cpp | 2 +- fastboot/filesystem.h | 1 + fastboot/storage.cpp | 22 ++++++++++------------ fastboot/storage.h | 4 +++- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index bec4ef1e9447..ee99c1788747 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -396,7 +396,7 @@ static Transport* NetworkDeviceConnected(bool print = false) { ConnectedDevicesStorage storage; std::set devices; - { + if (storage.Exists()) { FileLock lock = storage.Lock(); devices = storage.ReadDevices(lock); } diff --git a/fastboot/filesystem.h b/fastboot/filesystem.h index 5f41fbc9fcfa..c5f9c948d68f 100644 --- a/fastboot/filesystem.h +++ b/fastboot/filesystem.h @@ -31,6 +31,7 @@ const char kPathSeparator = #endif std::string GetHomeDirPath(); +bool FileExists(const std::string& path); bool EnsureDirectoryExists(const std::string& directory_path); class FileLock { diff --git a/fastboot/storage.cpp b/fastboot/storage.cpp index d6e00cffaf73..dc733b99464e 100644 --- a/fastboot/storage.cpp +++ b/fastboot/storage.cpp @@ -23,24 +23,19 @@ #include "util.h" ConnectedDevicesStorage::ConnectedDevicesStorage() { - const std::string home_path = GetHomeDirPath(); - if (home_path.empty()) { - return; - } - - const std::string home_fastboot_path = home_path + kPathSeparator + ".fastboot"; - - if (!EnsureDirectoryExists(home_fastboot_path)) { - LOG(FATAL) << "Cannot create directory: " << home_fastboot_path; - } + home_fastboot_path_ = GetHomeDirPath() + kPathSeparator + ".fastboot"; + devices_path_ = home_fastboot_path_ + kPathSeparator + "devices"; // We're using a separate file for locking because the Windows LockFileEx does not // permit opening a file stream for the locked file, even within the same process. So, // we have to use fd or handle API to manipulate the storage files, which makes it // nearly impossible to fully rewrite a file content without having to recreate it. // Unfortunately, this is not an option during holding a lock. - devices_path_ = home_fastboot_path + kPathSeparator + "devices"; - devices_lock_path_ = home_fastboot_path + kPathSeparator + "devices.lock"; + devices_lock_path_ = home_fastboot_path_ + kPathSeparator + "devices.lock"; +} + +bool ConnectedDevicesStorage::Exists() const { + return FileExists(devices_path_); } void ConnectedDevicesStorage::WriteDevices(const FileLock&, const std::set& devices) { @@ -63,5 +58,8 @@ void ConnectedDevicesStorage::Clear(const FileLock&) { } FileLock ConnectedDevicesStorage::Lock() const { + if (!EnsureDirectoryExists(home_fastboot_path_)) { + LOG(FATAL) << "Cannot create directory: " << home_fastboot_path_; + } return FileLock(devices_lock_path_); } \ No newline at end of file diff --git a/fastboot/storage.h b/fastboot/storage.h index 0cc3d86d670a..ae9d846e65b1 100644 --- a/fastboot/storage.h +++ b/fastboot/storage.h @@ -24,13 +24,15 @@ class ConnectedDevicesStorage { public: ConnectedDevicesStorage(); + + bool Exists() const; void WriteDevices(const FileLock&, const std::set& devices); std::set ReadDevices(const FileLock&); void Clear(const FileLock&); - FileLock Lock() const; private: + std::string home_fastboot_path_; std::string devices_path_; std::string devices_lock_path_; }; \ No newline at end of file From e2aba20f1997857f8ec11c2baf89fc1102db02bf Mon Sep 17 00:00:00 2001 From: Edward Liaw Date: Fri, 2 Jun 2023 23:33:41 +0000 Subject: [PATCH 0090/1487] KernelLibcutilsTest: change test file push location Upload files to /data/local/tests/unrestricted instead to improve data collection in the event of a crash. Bug: 284307085 Bug: 258819618 Bug: 199904562 Test: atest KernelLibcutilsTest Change-Id: Iff816fd3276b24507c60eddc1bcd3f2c2184c27d Signed-off-by: Edward Liaw --- libcutils/KernelLibcutilsTest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcutils/KernelLibcutilsTest.xml b/libcutils/KernelLibcutilsTest.xml index 40e4ef414be8..9750cbfa28b0 100644 --- a/libcutils/KernelLibcutilsTest.xml +++ b/libcutils/KernelLibcutilsTest.xml @@ -22,11 +22,11 @@ - From cc4a15b97a642a35a014e14dc8e5105b02695615 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 5 Jun 2023 14:35:11 +0000 Subject: [PATCH 0091/1487] fs_mgr_fstab: allow fileencryption without equals sign A point of confusion that has been encountered recently is that the fileencryption argument is optional (since Android 11), yet the fstab parser requires the equals sign in "fileencryption=". Thus, someone wanting to use the default options must use "...,fileencryption=,...". Make "fileencryption" by itself mean the same thing so that it works as expected. Test: atest CtsFsMgrTestCases Change-Id: I65ce6b9513942bec2107838396835e7aafb3bf37 --- fs_mgr/fs_mgr_fstab.cpp | 4 +++- fs_mgr/tests/fs_mgr_test.cpp | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index 598a3d2ecb4d..c3c10ba62701 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -242,7 +242,9 @@ bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) { LWARNING << "Warning: zramsize= flag malformed: " << arg; } } - } else if (StartsWith(flag, "fileencryption=")) { + } else if (StartsWith(flag, "fileencryption=") || flag == "fileencryption") { + // "fileencryption" enables file-based encryption. It's normally followed by an = and + // then the encryption options. But that can be omitted to use the default options. ParseFileEncryption(arg, entry); } else if (StartsWith(flag, "max_comp_streams=")) { if (!ParseInt(arg, &entry->max_comp_streams)) { diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp index e33681c3f66d..5f889caee5e7 100644 --- a/fs_mgr/tests/fs_mgr_test.cpp +++ b/fs_mgr/tests/fs_mgr_test.cpp @@ -497,6 +497,7 @@ source none1 swap defaults fileencryption=,keydirectory=,length=,sw EXPECT_EQ("none0", entry->mount_point); { FstabEntry::FsMgrFlags flags = {}; + flags.file_encryption = true; EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); } EXPECT_EQ("", entry->metadata_key_dir); From 303fb49cc042d029cbbbba7c35a5d00116014a1c Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Mon, 5 Jun 2023 10:30:44 -0700 Subject: [PATCH 0092/1487] Adding in wipe tasks before other tasks run. if we call -w and a reboot task runs beforehand, we don't actually wipe the given partitions. We want the wipe to occur before reboots. Test: fastboot flashall -w Change-Id: If327c5de0858e222cf5fc14531bc20fb741c2960 --- fastboot/fastboot.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index bec4ef1e9447..3c34ec259281 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -2583,10 +2583,13 @@ int FastBootTool::Main(int argc, char* argv[]) { if (fp->force_flash) { CancelSnapshotIfNeeded(); } + std::vector> wipe_tasks; std::vector partitions = {"userdata", "cache", "metadata"}; for (const auto& partition : partitions) { - tasks.emplace_back(std::make_unique(fp.get(), partition)); + wipe_tasks.emplace_back(std::make_unique(fp.get(), partition)); } + tasks.insert(tasks.begin(), std::make_move_iterator(wipe_tasks.begin()), + std::make_move_iterator(wipe_tasks.end())); } if (fp->wants_set_active) { fb->SetActive(next_active); From 07533c520c428932945cdbdc73c25fe27bd376e2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 2 Jun 2023 12:00:12 -0700 Subject: [PATCH 0093/1487] init: Fix ramdump when enabling shutdown animations. Fix a bug where services weren't stopped properly if shutdown animations were enabled. Bug: 285241485 Test: Pixel w/ ro.init.shutdown_animation=true Change-Id: I7f35572b5223f03f3f5a341fa7b5e90c01d56ce3 --- init/reboot.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/init/reboot.cpp b/init/reboot.cpp index 27a7876db881..3351c4c452da 100644 --- a/init/reboot.cpp +++ b/init/reboot.cpp @@ -680,8 +680,8 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str << "': " << result.error(); } s->SetShutdownCritical(); - } else if (do_shutdown_animation) { - continue; + } else if (do_shutdown_animation && s->classnames().count("animation") > 0) { + // Need these for shutdown animations. } else if (s->IsShutdownCritical()) { // Start shutdown critical service if not started. if (auto result = s->Start(); !result.ok()) { From b3e1993ee55269694c345743191a67fbdc443e97 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Wed, 31 May 2023 14:18:59 -0700 Subject: [PATCH 0094/1487] Add the Missing Header `stderror` is used in this file and it is defined in `string.h/cstring`, so the header file needs to be directly included. Test: build Bug: 285204695 Change-Id: Idf34126626ad0e9bb397df3d5da50439bf18381d --- libutils/Errors.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libutils/Errors.cpp b/libutils/Errors.cpp index 74f3befacf31..dfb4d9b95c05 100644 --- a/libutils/Errors.cpp +++ b/libutils/Errors.cpp @@ -15,6 +15,8 @@ */ #include +#include + namespace android { std::string statusToString(status_t s) { From 665a460e8a2409040e2965d1ca920e98bc8a2ed4 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Mon, 5 Jun 2023 11:24:59 -0700 Subject: [PATCH 0095/1487] Adding GetInfo method for tasks Using for easier debugging. Replacing old getter methods in flash task with GetInfo(key) Test: fastboot_test Change-Id: If42df86c4b0278c3dc5525b1058f1947f0b34794 --- fastboot/task.cpp | 30 ++++++++++++++++++++++++++++++ fastboot/task.h | 14 +++++++++++--- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/fastboot/task.cpp b/fastboot/task.cpp index 9ce2cfd201d7..03f9b8942bb2 100644 --- a/fastboot/task.cpp +++ b/fastboot/task.cpp @@ -46,6 +46,14 @@ void FlashTask::Run() { do_for_partitions(pname_, slot_, flash, true); } +std::string FlashTask::ToString() { + std::string apply_vbmeta_string = ""; + if (apply_vbmeta_) { + apply_vbmeta_string = " --apply_vbmeta"; + } + return "flash" + apply_vbmeta_string + " " + pname_ + " " + fname_; +} + std::string FlashTask::GetPartitionAndSlot() { auto slot = slot_; if (slot.empty()) { @@ -84,6 +92,10 @@ void RebootTask::Run() { } } +std::string RebootTask::ToString() { + return "reboot " + reboot_target_; +} + FlashSuperLayoutTask::FlashSuperLayoutTask(const std::string& super_name, std::unique_ptr helper, SparsePtr sparse_layout, uint64_t super_size) @@ -106,6 +118,9 @@ void FlashSuperLayoutTask::Run() { // Send the data to the device. flash_partition_files(super_name_, files); } +std::string FlashSuperLayoutTask::ToString() { + return "optimized-flash-super"; +} std::unique_ptr FlashSuperLayoutTask::Initialize( const FlashingPlan* fp, std::vector& os_images) { @@ -263,6 +278,9 @@ void UpdateSuperTask::Run() { } fp_->fb->RawCommand(command, "Updating super partition"); } +std::string UpdateSuperTask::ToString() { + return "update-super"; +} ResizeTask::ResizeTask(const FlashingPlan* fp, const std::string& pname, const std::string& size, const std::string& slot) @@ -277,12 +295,20 @@ void ResizeTask::Run() { do_for_partitions(pname_, slot_, resize_partition, false); } +std::string ResizeTask::ToString() { + return "resize " + pname_; +} + DeleteTask::DeleteTask(const FlashingPlan* fp, const std::string& pname) : fp_(fp), pname_(pname){}; void DeleteTask::Run() { fp_->fb->DeletePartition(pname_); } +std::string DeleteTask::ToString() { + return "delete " + pname_; +} + WipeTask::WipeTask(const FlashingPlan* fp, const std::string& pname) : fp_(fp), pname_(pname){}; void WipeTask::Run() { @@ -298,3 +324,7 @@ void WipeTask::Run() { } fb_perform_format(pname_, 1, partition_type, "", fp_->fs_options); } + +std::string WipeTask::ToString() { + return "erase " + pname_; +} diff --git a/fastboot/task.h b/fastboot/task.h index 82e8ebf51e01..500655dbb7c3 100644 --- a/fastboot/task.h +++ b/fastboot/task.h @@ -35,6 +35,8 @@ class Task { public: Task() = default; virtual void Run() = 0; + virtual std::string ToString() = 0; + virtual FlashTask* AsFlashTask() { return nullptr; } virtual RebootTask* AsRebootTask() { return nullptr; } virtual UpdateSuperTask* AsUpdateSuperTask() { return nullptr; } @@ -49,11 +51,12 @@ class FlashTask : public Task { const bool apply_vbmeta, const FlashingPlan* fp); virtual FlashTask* AsFlashTask() override { return this; } + void Run() override; + std::string ToString() override; std::string GetPartition() { return pname_; } std::string GetImageName() { return fname_; } - std::string GetPartitionAndSlot(); std::string GetSlot() { return slot_; } - void Run() override; + std::string GetPartitionAndSlot(); private: const std::string pname_; @@ -69,6 +72,7 @@ class RebootTask : public Task { RebootTask(const FlashingPlan* fp, const std::string& reboot_target); virtual RebootTask* AsRebootTask() override { return this; } void Run() override; + std::string ToString() override; private: const std::string reboot_target_ = ""; @@ -85,6 +89,7 @@ class FlashSuperLayoutTask : public Task { const FlashingPlan* fp, std::vector>& tasks); using ImageEntry = std::pair; void Run() override; + std::string ToString() override; private: const std::string super_name_; @@ -99,6 +104,7 @@ class UpdateSuperTask : public Task { virtual UpdateSuperTask* AsUpdateSuperTask() override { return this; } void Run() override; + std::string ToString() override; private: const FlashingPlan* fp_; @@ -109,6 +115,7 @@ class ResizeTask : public Task { ResizeTask(const FlashingPlan* fp, const std::string& pname, const std::string& size, const std::string& slot); void Run() override; + std::string ToString() override; private: const FlashingPlan* fp_; @@ -121,6 +128,7 @@ class DeleteTask : public Task { public: DeleteTask(const FlashingPlan* fp, const std::string& pname); void Run() override; + std::string ToString() override; private: const FlashingPlan* fp_; @@ -131,8 +139,8 @@ class WipeTask : public Task { public: WipeTask(const FlashingPlan* fp, const std::string& pname); virtual WipeTask* AsWipeTask() override { return this; } - void Run() override; + std::string ToString() override; private: const FlashingPlan* fp_; From 6cef6905d781e5f676d77f75d39f497e3cbe0b6b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 5 Jun 2023 15:00:30 -0700 Subject: [PATCH 0096/1487] Move ENOSPC tests to libfiemap. These tests are still giving us trouble. Move them to libfiemap, which (1) is closer to the source of implementation, and (2) allows us to re-use the temporary filesystem code. This won't perturb the state of the actual device. The new test creates a 64MB ext4 or f2fs mount point as a sandbox, which should be much safer. Bug: 285197715 Test: fiemap_writer_test Change-Id: I33502d49613be4f269a80e5c632514fc56a0246a --- fs_mgr/libfiemap/Android.bp | 3 + fs_mgr/libfiemap/fiemap_writer_test.cpp | 118 ++++++++++++------ fs_mgr/libsnapshot/snapshot_test.cpp | 86 ------------- .../storage_literals/storage_literals.h | 6 + 4 files changed, 87 insertions(+), 126 deletions(-) diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp index 5deba659dd56..ddda648d8e88 100644 --- a/fs_mgr/libfiemap/Android.bp +++ b/fs_mgr/libfiemap/Android.bp @@ -93,6 +93,9 @@ cc_test { test_options: { min_shipping_api_level: 29, }, + header_libs: [ + "libstorage_literals_headers", + ], require_root: true, } diff --git a/fs_mgr/libfiemap/fiemap_writer_test.cpp b/fs_mgr/libfiemap/fiemap_writer_test.cpp index c65481b78d36..bd97a78ae8f7 100644 --- a/fs_mgr/libfiemap/fiemap_writer_test.cpp +++ b/fs_mgr/libfiemap/fiemap_writer_test.cpp @@ -22,21 +22,25 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include #include +#include #include #include #include #include #include +#include #include "utility.h" @@ -46,6 +50,7 @@ namespace fiemap { using namespace std; using namespace std::string_literals; using namespace android::fiemap; +using namespace android::storage_literals; using unique_fd = android::base::unique_fd; using LoopDevice = android::dm::LoopDevice; @@ -427,90 +432,123 @@ TEST_F(SplitFiemapTest, WritePastEnd) { ASSERT_FALSE(ptr->Write(buffer.get(), kSize)); } -class VerifyBlockWritesExt4 : public ::testing::Test { +// Get max file size and free space. +std::pair GetBigFileLimit(const std::string& mount_point) { + struct statvfs fs; + if (statvfs(mount_point.c_str(), &fs) < 0) { + PLOG(ERROR) << "statfs failed"; + return {0, 0}; + } + + auto fs_limit = static_cast(fs.f_blocks) * (fs.f_bsize - 1); + auto fs_free = static_cast(fs.f_bfree) * fs.f_bsize; + + LOG(INFO) << "Big file limit: " << fs_limit << ", free space: " << fs_free; + + return {fs_limit, fs_free}; +} + +class FsTest : public ::testing::Test { + protected: // 2GB Filesystem and 4k block size by default static constexpr uint64_t block_size = 4096; - static constexpr uint64_t fs_size = 2147483648; + static constexpr uint64_t fs_size = 64 * 1024 * 1024; + + void SetUp() { + android::fs_mgr::Fstab fstab; + ASSERT_TRUE(android::fs_mgr::ReadFstabFromFile("/proc/mounts", &fstab)); + + ASSERT_EQ(access(tmpdir_.path, F_OK), 0); + fs_path_ = tmpdir_.path + "/fs_image"s; + mntpoint_ = tmpdir_.path + "/mnt_point"s; + + auto entry = android::fs_mgr::GetEntryForMountPoint(&fstab, "/data"); + ASSERT_NE(entry, nullptr); + if (entry->fs_type == "ext4") { + SetUpExt4(); + } else if (entry->fs_type == "f2fs") { + SetUpF2fs(); + } else { + FAIL() << "Unrecognized fs_type: " << entry->fs_type; + } + } - protected: - void SetUp() override { - fs_path = std::string(getenv("TMPDIR")) + "/ext4_2G.img"; + void SetUpExt4() { uint64_t count = fs_size / block_size; std::string dd_cmd = ::android::base::StringPrintf("/system/bin/dd if=/dev/zero of=%s bs=%" PRIu64 " count=%" PRIu64 " > /dev/null 2>&1", - fs_path.c_str(), block_size, count); + fs_path_.c_str(), block_size, count); std::string mkfs_cmd = - ::android::base::StringPrintf("/system/bin/mkfs.ext4 -q %s", fs_path.c_str()); + ::android::base::StringPrintf("/system/bin/mkfs.ext4 -q %s", fs_path_.c_str()); // create mount point - mntpoint = std::string(getenv("TMPDIR")) + "/fiemap_mnt"; - ASSERT_EQ(mkdir(mntpoint.c_str(), S_IRWXU), 0); + ASSERT_EQ(mkdir(mntpoint_.c_str(), S_IRWXU), 0); // create file for the file system int ret = system(dd_cmd.c_str()); ASSERT_EQ(ret, 0); // Get and attach a loop device to the filesystem we created - LoopDevice loop_dev(fs_path, 10s); + LoopDevice loop_dev(fs_path_, 10s); ASSERT_TRUE(loop_dev.valid()); // create file system ret = system(mkfs_cmd.c_str()); ASSERT_EQ(ret, 0); // mount the file system - ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint.c_str(), "ext4", 0, nullptr), 0); - } - - void TearDown() override { - umount(mntpoint.c_str()); - rmdir(mntpoint.c_str()); - unlink(fs_path.c_str()); + ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint_.c_str(), "ext4", 0, nullptr), 0); } - std::string mntpoint; - std::string fs_path; -}; - -class VerifyBlockWritesF2fs : public ::testing::Test { - // 2GB Filesystem and 4k block size by default - static constexpr uint64_t block_size = 4096; - static constexpr uint64_t fs_size = 2147483648; - - protected: - void SetUp() override { - fs_path = std::string(getenv("TMPDIR")) + "/f2fs_2G.img"; + void SetUpF2fs() { uint64_t count = fs_size / block_size; std::string dd_cmd = ::android::base::StringPrintf("/system/bin/dd if=/dev/zero of=%s bs=%" PRIu64 " count=%" PRIu64 " > /dev/null 2>&1", - fs_path.c_str(), block_size, count); + fs_path_.c_str(), block_size, count); std::string mkfs_cmd = - ::android::base::StringPrintf("/system/bin/make_f2fs -q %s", fs_path.c_str()); + ::android::base::StringPrintf("/system/bin/make_f2fs -q %s", fs_path_.c_str()); // create mount point - mntpoint = std::string(getenv("TMPDIR")) + "/fiemap_mnt"; - ASSERT_EQ(mkdir(mntpoint.c_str(), S_IRWXU), 0); + ASSERT_EQ(mkdir(mntpoint_.c_str(), S_IRWXU), 0); // create file for the file system int ret = system(dd_cmd.c_str()); ASSERT_EQ(ret, 0); // Get and attach a loop device to the filesystem we created - LoopDevice loop_dev(fs_path, 10s); + LoopDevice loop_dev(fs_path_, 10s); ASSERT_TRUE(loop_dev.valid()); // create file system ret = system(mkfs_cmd.c_str()); ASSERT_EQ(ret, 0); // mount the file system - ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint.c_str(), "f2fs", 0, nullptr), 0); + ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint_.c_str(), "f2fs", 0, nullptr), 0); } void TearDown() override { - umount(mntpoint.c_str()); - rmdir(mntpoint.c_str()); - unlink(fs_path.c_str()); + umount(mntpoint_.c_str()); + rmdir(mntpoint_.c_str()); + unlink(fs_path_.c_str()); } - std::string mntpoint; - std::string fs_path; + TemporaryDir tmpdir_; + std::string mntpoint_; + std::string fs_path_; }; +TEST_F(FsTest, LowSpaceError) { + auto limits = GetBigFileLimit(mntpoint_); + ASSERT_GE(limits.first, 0); + + FiemapUniquePtr ptr; + + auto test_file = mntpoint_ + "/big_file"; + auto status = FiemapWriter::Open(test_file, limits.first, &ptr); + ASSERT_FALSE(status.is_ok()); + ASSERT_EQ(status.error_code(), FiemapStatus::ErrorCode::NO_SPACE); + + // Also test for EFBIG. + status = FiemapWriter::Open(test_file, 16_TiB, &ptr); + ASSERT_FALSE(status.is_ok()); + ASSERT_NE(status.error_code(), FiemapStatus::ErrorCode::NO_SPACE); +} + bool DetermineBlockSize() { struct statfs s; if (statfs(gTestDir.c_str(), &s)) { diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index 22731e7b7487..d45dac134c38 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -2372,60 +2372,6 @@ TEST_F(SnapshotUpdateTest, Overflow) { << "FinishedSnapshotWrites should detect overflow of CoW device."; } -// Get max file size and free space. -std::pair GetBigFileLimit() { - struct statvfs fs; - if (statvfs("/data", &fs) < 0) { - PLOG(ERROR) << "statfs failed"; - return {0, 0}; - } - - auto fs_limit = static_cast(fs.f_blocks) * (fs.f_bsize - 1); - auto fs_free = static_cast(fs.f_bfree) * fs.f_bsize; - - LOG(INFO) << "Big file limit: " << fs_limit << ", free space: " << fs_free; - - return {fs_limit, fs_free}; -} - -TEST_F(SnapshotUpdateTest, LowSpace) { - // To make the low space test more reliable, we force a large cow estimate. - // However legacy VAB ignores the COW estimate and uses InstallOperations - // to compute the exact size required for dm-snapshot. It's difficult to - // make this work reliably (we'd need to somehow fake an extremely large - // super partition, and we don't have that level of dependency injection). - // - // For now, just skip this test on legacy VAB. - if (!snapuserd_required_) { - GTEST_SKIP() << "Skipping test on legacy VAB"; - } - - auto fs = GetBigFileLimit(); - ASSERT_NE(fs.first, 0); - - constexpr uint64_t partition_size = 10_MiB; - SetSize(sys_, partition_size); - SetSize(vnd_, partition_size); - SetSize(prd_, partition_size); - sys_->set_estimate_cow_size(fs.first); - vnd_->set_estimate_cow_size(fs.first); - prd_->set_estimate_cow_size(fs.first); - - AddOperationForPartitions(); - - // Execute the update. - ASSERT_TRUE(sm->BeginUpdate()); - auto res = sm->CreateUpdateSnapshots(manifest_); - ASSERT_FALSE(res); - ASSERT_EQ(Return::ErrorCode::NO_SPACE, res.error_code()); - - // It's hard to predict exactly how much free space is needed, since /data - // is writable and the test is not the only process running. Divide by two - // as a rough lower bound, and adjust this in the future as necessary. - auto expected_delta = fs.first - fs.second; - ASSERT_GE(res.required_size(), expected_delta / 2); -} - TEST_F(SnapshotUpdateTest, AddPartition) { group_->add_partition_names("dlkm"); @@ -2796,38 +2742,6 @@ INSTANTIATE_TEST_SUITE_P(Snapshot, FlashAfterUpdateTest, Combine(Values(0, 1), B "Merge"s; }); -class ImageManagerTest : public SnapshotTest { - protected: - void SetUp() override { - SKIP_IF_NON_VIRTUAL_AB(); - SnapshotTest::SetUp(); - } - void TearDown() override { - RETURN_IF_NON_VIRTUAL_AB(); - CleanUp(); - SnapshotTest::TearDown(); - } - void CleanUp() { - if (!image_manager_) { - return; - } - EXPECT_TRUE(!image_manager_->BackingImageExists(kImageName) || - image_manager_->DeleteBackingImage(kImageName)); - } - - static constexpr const char* kImageName = "my_image"; -}; - -TEST_F(ImageManagerTest, CreateImageNoSpace) { - auto fs = GetBigFileLimit(); - ASSERT_NE(fs.first, 0); - - auto res = image_manager_->CreateBackingImage(kImageName, fs.first, - IImageManager::CREATE_IMAGE_DEFAULT); - ASSERT_FALSE(res); - ASSERT_EQ(res.error_code(), FiemapStatus::ErrorCode::NO_SPACE) << res.string(); -} - bool Mkdir(const std::string& path) { if (mkdir(path.c_str(), 0700) && errno != EEXIST) { std::cerr << "Could not mkdir " << path << ": " << strerror(errno) << std::endl; diff --git a/fs_mgr/libstorage_literals/storage_literals/storage_literals.h b/fs_mgr/libstorage_literals/storage_literals/storage_literals.h index ac0dfbdb7004..bbeabd5c987b 100644 --- a/fs_mgr/libstorage_literals/storage_literals/storage_literals.h +++ b/fs_mgr/libstorage_literals/storage_literals/storage_literals.h @@ -37,6 +37,7 @@ using B = Size<0>; using KiB = Size<10>; using MiB = Size<20>; using GiB = Size<30>; +using TiB = Size<40>; constexpr B operator""_B(unsigned long long v) { // NOLINT return B{v}; @@ -54,6 +55,10 @@ constexpr GiB operator""_GiB(unsigned long long v) { // NOLINT return GiB{v}; } +constexpr TiB operator""_TiB(unsigned long long v) { // NOLINT + return TiB{v}; +} + template constexpr Dest size_cast(Src src) { if (Src::power < Dest::power) { @@ -69,6 +74,7 @@ static_assert(1_B == 1); static_assert(1_KiB == 1 << 10); static_assert(1_MiB == 1 << 20); static_assert(1_GiB == 1 << 30); +static_assert(1_TiB == 1ULL << 40); static_assert(size_cast(1_B).count() == 0); static_assert(size_cast(1024_B).count() == 1); static_assert(size_cast(1_MiB).count() == 1024); From 40b59a61fc92b742814b3d92b6a888bc91b2a880 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 6 Jun 2023 17:52:39 +0000 Subject: [PATCH 0097/1487] libcutils_test: static libjsoncpp The 32-bit variant of libjsoncpp is not always installed on 64-bit devices, so it must always be statically included. We should probably collapse libcutils_test with libcutils_test_static in the future. Bug: 285357054 Test: libcutils_test Change-Id: Ic84901ce5af766338b2cab07c3cf10841ba9a150 --- libcutils/Android.bp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libcutils/Android.bp b/libcutils/Android.bp index b135e57bc378..0b5c1254ea2a 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -286,11 +286,14 @@ cc_defaults { ], } +always_static_test_libraries = [ + "libjsoncpp", +] + test_libraries = [ "libcutils", "liblog", "libbase", - "libjsoncpp", "libprocessgroup", "libcgrouprc", ] @@ -301,6 +304,7 @@ cc_test { defaults: ["libcutils_test_default"], host_supported: true, shared_libs: test_libraries, + static_libs: always_static_test_libraries, require_root: true, } @@ -310,7 +314,7 @@ cc_defaults { static_libs: [ "libc", "libcgrouprc_format", - ] + test_libraries, + ] + test_libraries + always_static_test_libraries, stl: "libc++_static", require_root: true, From 447b4a4bf032a550ada6621a33d6b1e188357eb2 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 6 Jun 2023 17:52:39 +0000 Subject: [PATCH 0098/1487] libcutils_test: static libjsoncpp The 32-bit variant of libjsoncpp is not always installed on 64-bit devices, so it must always be statically included. We should probably collapse libcutils_test with libcutils_test_static in the future. Bug: 285357054 Test: libcutils_test Merged-In: Ic84901ce5af766338b2cab07c3cf10841ba9a150 Change-Id: Ic84901ce5af766338b2cab07c3cf10841ba9a150 --- libcutils/Android.bp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libcutils/Android.bp b/libcutils/Android.bp index 68b21c6a0209..b9e0bb7eecb2 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -302,11 +302,14 @@ cc_defaults { ], } +always_static_test_libraries = [ + "libjsoncpp", +] + test_libraries = [ "libcutils", "liblog", "libbase", - "libjsoncpp", "libprocessgroup", "libcgrouprc", ] @@ -317,6 +320,7 @@ cc_test { defaults: ["libcutils_test_default"], host_supported: true, shared_libs: test_libraries, + static_libs: always_static_test_libraries, require_root: true, } @@ -326,7 +330,7 @@ cc_defaults { static_libs: [ "libc", "libcgrouprc_format", - ] + test_libraries, + ] + test_libraries + always_static_test_libraries, stl: "libc++_static", require_root: true, From 084c94e43eb2916c84c72de524c6e8c3d5ec2d4f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 6 Jun 2023 16:45:05 -0700 Subject: [PATCH 0099/1487] vts_fs_test: Relax filesystem constraints for fixed partitions. Adjust this test to align with VSR. First, skip the test if kernel is < 5.10 or < Android 13. Second, allow non-dynamic partitions to be vfat. Bug: 286038059 Test: vts_fs_test on CF Change-Id: I5bd874f68296f7155d8c4366ebc13fe3d59c3ee6 --- fs_mgr/tests/vts_fs_test.cpp | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/fs_mgr/tests/vts_fs_test.cpp b/fs_mgr/tests/vts_fs_test.cpp index bb2ceb9b5681..4d771fa046d6 100644 --- a/fs_mgr/tests/vts_fs_test.cpp +++ b/fs_mgr/tests/vts_fs_test.cpp @@ -55,6 +55,21 @@ TEST(fs, ErofsSupported) { } TEST(fs, PartitionTypes) { + // Requirements only apply to Android 13+, 5.10+ devices. + int vsr_level = GetVsrLevel(); + if (vsr_level < __ANDROID_API_T__) { + GTEST_SKIP(); + } + + struct utsname uts; + ASSERT_EQ(uname(&uts), 0); + + unsigned int major, minor; + ASSERT_EQ(sscanf(uts.release, "%u.%u", &major, &minor), 2); + if (major < 5 || (major == 5 && minor < 10)) { + GTEST_SKIP(); + } + android::fs_mgr::Fstab fstab; ASSERT_TRUE(android::fs_mgr::ReadFstabFromFile("/proc/mounts", &fstab)); @@ -64,12 +79,7 @@ TEST(fs, PartitionTypes) { ASSERT_TRUE(android::base::Readlink("/dev/block/by-name/super", &super_bdev)); ASSERT_TRUE(android::base::Readlink("/dev/block/by-name/userdata", &userdata_bdev)); - int vsr_level = GetVsrLevel(); - - std::vector must_be_f2fs; - if (vsr_level >= __ANDROID_API_T__) { - must_be_f2fs.emplace_back("/data"); - } + std::vector must_be_f2fs = {"/data"}; if (vsr_level >= __ANDROID_API_U__) { must_be_f2fs.emplace_back("/metadata"); } @@ -98,17 +108,13 @@ TEST(fs, PartitionTypes) { continue; } - if (vsr_level < __ANDROID_API_T__) { - continue; - } - if (vsr_level == __ANDROID_API_T__ && parent_bdev != super_bdev) { - // Only check for dynamic partitions at this VSR level. - continue; - } - if (entry.flags & MS_RDONLY) { - std::vector allowed = {"erofs", "ext4", "f2fs"}; + if (parent_bdev != super_bdev) { + // Ignore non-AOSP partitions (eg anything outside of super). + continue; + } + std::vector allowed = {"erofs", "ext4", "f2fs"}; EXPECT_NE(std::find(allowed.begin(), allowed.end(), entry.fs_type), allowed.end()) << entry.mount_point; } else { From e55e3dcd3f59008f1e3a770b5265be88b332f22c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 6 Jun 2023 16:45:05 -0700 Subject: [PATCH 0100/1487] vts_fs_test: Relax filesystem constraints for fixed partitions. Adjust this test to align with VSR. First, skip the test if kernel is < 5.10 or < Android 13. Second, allow non-dynamic partitions to be vfat. Bug: 286038059 Test: vts_fs_test on CF (cherry picked from https://android-review.googlesource.com/q/commit:084c94e43eb2916c84c72de524c6e8c3d5ec2d4f) Merged-In: I5bd874f68296f7155d8c4366ebc13fe3d59c3ee6 Change-Id: I5bd874f68296f7155d8c4366ebc13fe3d59c3ee6 --- fs_mgr/tests/vts_fs_test.cpp | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/fs_mgr/tests/vts_fs_test.cpp b/fs_mgr/tests/vts_fs_test.cpp index bb2ceb9b5681..4d771fa046d6 100644 --- a/fs_mgr/tests/vts_fs_test.cpp +++ b/fs_mgr/tests/vts_fs_test.cpp @@ -55,6 +55,21 @@ TEST(fs, ErofsSupported) { } TEST(fs, PartitionTypes) { + // Requirements only apply to Android 13+, 5.10+ devices. + int vsr_level = GetVsrLevel(); + if (vsr_level < __ANDROID_API_T__) { + GTEST_SKIP(); + } + + struct utsname uts; + ASSERT_EQ(uname(&uts), 0); + + unsigned int major, minor; + ASSERT_EQ(sscanf(uts.release, "%u.%u", &major, &minor), 2); + if (major < 5 || (major == 5 && minor < 10)) { + GTEST_SKIP(); + } + android::fs_mgr::Fstab fstab; ASSERT_TRUE(android::fs_mgr::ReadFstabFromFile("/proc/mounts", &fstab)); @@ -64,12 +79,7 @@ TEST(fs, PartitionTypes) { ASSERT_TRUE(android::base::Readlink("/dev/block/by-name/super", &super_bdev)); ASSERT_TRUE(android::base::Readlink("/dev/block/by-name/userdata", &userdata_bdev)); - int vsr_level = GetVsrLevel(); - - std::vector must_be_f2fs; - if (vsr_level >= __ANDROID_API_T__) { - must_be_f2fs.emplace_back("/data"); - } + std::vector must_be_f2fs = {"/data"}; if (vsr_level >= __ANDROID_API_U__) { must_be_f2fs.emplace_back("/metadata"); } @@ -98,17 +108,13 @@ TEST(fs, PartitionTypes) { continue; } - if (vsr_level < __ANDROID_API_T__) { - continue; - } - if (vsr_level == __ANDROID_API_T__ && parent_bdev != super_bdev) { - // Only check for dynamic partitions at this VSR level. - continue; - } - if (entry.flags & MS_RDONLY) { - std::vector allowed = {"erofs", "ext4", "f2fs"}; + if (parent_bdev != super_bdev) { + // Ignore non-AOSP partitions (eg anything outside of super). + continue; + } + std::vector allowed = {"erofs", "ext4", "f2fs"}; EXPECT_NE(std::find(allowed.begin(), allowed.end(), entry.fs_type), allowed.end()) << entry.mount_point; } else { From 4866d284f81dec3068c8f4f015d82c0db46c2b85 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 16 May 2023 15:53:57 -0700 Subject: [PATCH 0101/1487] ueventd: Fix a race condition in handling device-mapper events. We've had flake in libdm_test for a long time, with no clear cause. Lately however it has become particularly reproducible when running the UeventAfterLoadTable test in isolation, and thus we've identified the root cause. uevents for device-mapper are fired when the sysfs node is added, but at that time, the "dm" subnode has not yet been added. The root node and dm node are added very close together, so usually it works, but sometimes ueventd is too fast. Instead of relying on sysfs, query the uuid/name node directly from device-mapper. Bug: 286011429 Test: libdm_test (cherry picked from https://android-review.googlesource.com/q/commit:59abbfe64706a7ea0c4e932ae40bc8bde9746dce) Merged-In: I258de5de05d813c3cb7f129e82e56dbfe8bf3117 Change-Id: I85e240807e0ce5ade211ec65453ab06d4066992a --- fs_mgr/libdm/dm.cpp | 19 +++++++ fs_mgr/libdm/dm_test.cpp | 94 +++++++++++++++++++++++---------- fs_mgr/libdm/include/libdm/dm.h | 2 + init/devices.cpp | 18 +++---- 4 files changed, 94 insertions(+), 39 deletions(-) diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index deffae1ad6fe..1e8c14fe2c01 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -243,6 +243,25 @@ bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* pat return true; } +bool DeviceMapper::GetDeviceNameAndUuid(dev_t dev, std::string* name, std::string* uuid) { + struct dm_ioctl io; + InitIo(&io, {}); + io.dev = dev; + + if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) { + PLOG(ERROR) << "Failed to find device dev: " << major(dev) << ":" << minor(dev); + return false; + } + + if (name) { + *name = io.name; + } + if (uuid) { + *uuid = io.uuid; + } + return true; +} + std::optional DeviceMapper::GetDetailedInfo(const std::string& name) const { struct dm_ioctl io; InitIo(&io, name); diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp index 788cf5174853..c522eafae058 100644 --- a/fs_mgr/libdm/dm_test.cpp +++ b/fs_mgr/libdm/dm_test.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -42,16 +43,40 @@ using namespace std; using namespace std::chrono_literals; using namespace android::dm; -using unique_fd = android::base::unique_fd; +using android::base::make_scope_guard; +using android::base::unique_fd; + +class DmTest : public ::testing::Test { + protected: + void SetUp() override { + const testing::TestInfo* const test_info = + testing::UnitTest::GetInstance()->current_test_info(); + test_name_ = test_info->name(); + test_full_name_ = test_info->test_suite_name() + "/"s + test_name_; + + LOG(INFO) << "Starting test: " << test_full_name_; + } + void TearDown() override { + LOG(INFO) << "Tearing down test: " << test_full_name_; + + auto& dm = DeviceMapper::Instance(); + ASSERT_TRUE(dm.DeleteDeviceIfExists(test_name_)); + + LOG(INFO) << "Teardown complete for test: " << test_full_name_; + } + + std::string test_name_; + std::string test_full_name_; +}; -TEST(libdm, HasMinimumTargets) { +TEST_F(DmTest, HasMinimumTargets) { DmTargetTypeInfo info; DeviceMapper& dm = DeviceMapper::Instance(); ASSERT_TRUE(dm.GetTargetByName("linear", &info)); } -TEST(libdm, DmLinear) { +TEST_F(DmTest, DmLinear) { unique_fd tmp1(CreateTempFile("file_1", 4096)); ASSERT_GE(tmp1, 0); unique_fd tmp2(CreateTempFile("file_2", 4096)); @@ -127,7 +152,7 @@ TEST(libdm, DmLinear) { ASSERT_TRUE(dev.Destroy()); } -TEST(libdm, DmSuspendResume) { +TEST_F(DmTest, DmSuspendResume) { unique_fd tmp1(CreateTempFile("file_suspend_resume", 512)); ASSERT_GE(tmp1, 0); @@ -156,7 +181,7 @@ TEST(libdm, DmSuspendResume) { ASSERT_EQ(dm.GetState(dev.name()), DmDeviceState::ACTIVE); } -TEST(libdm, DmVerityArgsAvb2) { +TEST_F(DmTest, DmVerityArgsAvb2) { std::string device = "/dev/block/platform/soc/1da4000.ufshc/by-name/vendor_a"; std::string algorithm = "sha1"; std::string digest = "4be7e823b8c40f7bd5c8ccd5123f0722c5baca21"; @@ -178,7 +203,7 @@ TEST(libdm, DmVerityArgsAvb2) { EXPECT_EQ(target.GetParameterString(), expected); } -TEST(libdm, DmSnapshotArgs) { +TEST_F(DmTest, DmSnapshotArgs) { DmTargetSnapshot target1(0, 512, "base", "cow", SnapshotStorageMode::Persistent, 8); if (DmTargetSnapshot::ReportsOverflow("snapshot")) { EXPECT_EQ(target1.GetParameterString(), "base cow PO 8"); @@ -200,7 +225,7 @@ TEST(libdm, DmSnapshotArgs) { EXPECT_EQ(target3.name(), "snapshot-merge"); } -TEST(libdm, DmSnapshotOriginArgs) { +TEST_F(DmTest, DmSnapshotOriginArgs) { DmTargetSnapshotOrigin target(0, 512, "base"); EXPECT_EQ(target.GetParameterString(), "base"); EXPECT_EQ(target.name(), "snapshot-origin"); @@ -330,7 +355,7 @@ bool CheckSnapshotAvailability() { return true; } -TEST(libdm, DmSnapshot) { +TEST_F(DmTest, DmSnapshot) { if (!CheckSnapshotAvailability()) { return; } @@ -374,7 +399,7 @@ TEST(libdm, DmSnapshot) { ASSERT_EQ(read, data); } -TEST(libdm, DmSnapshotOverflow) { +TEST_F(DmTest, DmSnapshotOverflow) { if (!CheckSnapshotAvailability()) { return; } @@ -421,7 +446,7 @@ TEST(libdm, DmSnapshotOverflow) { } } -TEST(libdm, ParseStatusText) { +TEST_F(DmTest, ParseStatusText) { DmTargetSnapshot::Status status; // Bad inputs @@ -448,7 +473,7 @@ TEST(libdm, ParseStatusText) { EXPECT_TRUE(DmTargetSnapshot::ParseStatusText("Overflow", &status)); } -TEST(libdm, DmSnapshotMergePercent) { +TEST_F(DmTest, DmSnapshotMergePercent) { DmTargetSnapshot::Status status; // Correct input @@ -502,7 +527,7 @@ TEST(libdm, DmSnapshotMergePercent) { EXPECT_LE(DmTargetSnapshot::MergePercent(status, 0), 0.0); } -TEST(libdm, CryptArgs) { +TEST_F(DmTest, CryptArgs) { DmTargetCrypt target1(0, 512, "sha1", "abcdefgh", 50, "/dev/loop0", 100); ASSERT_EQ(target1.name(), "crypt"); ASSERT_TRUE(target1.Valid()); @@ -518,7 +543,7 @@ TEST(libdm, CryptArgs) { "iv_large_sectors sector_size:64"); } -TEST(libdm, DefaultKeyArgs) { +TEST_F(DmTest, DefaultKeyArgs) { DmTargetDefaultKey target(0, 4096, "aes-xts-plain64", "abcdef0123456789", "/dev/loop0", 0); target.SetSetDun(); ASSERT_EQ(target.name(), "default-key"); @@ -529,7 +554,7 @@ TEST(libdm, DefaultKeyArgs) { "iv_large_sectors"); } -TEST(libdm, DefaultKeyLegacyArgs) { +TEST_F(DmTest, DefaultKeyLegacyArgs) { DmTargetDefaultKey target(0, 4096, "AES-256-XTS", "abcdef0123456789", "/dev/loop0", 0); target.SetUseLegacyOptionsFormat(); ASSERT_EQ(target.name(), "default-key"); @@ -537,7 +562,7 @@ TEST(libdm, DefaultKeyLegacyArgs) { ASSERT_EQ(target.GetParameterString(), "AES-256-XTS abcdef0123456789 /dev/loop0 0"); } -TEST(libdm, DeleteDeviceWithTimeout) { +TEST_F(DmTest, DeleteDeviceWithTimeout) { unique_fd tmp(CreateTempFile("file_1", 4096)); ASSERT_GE(tmp, 0); LoopDevice loop(tmp, 10s); @@ -561,7 +586,7 @@ TEST(libdm, DeleteDeviceWithTimeout) { ASSERT_EQ(ENOENT, errno); } -TEST(libdm, IsDmBlockDevice) { +TEST_F(DmTest, IsDmBlockDevice) { unique_fd tmp(CreateTempFile("file_1", 4096)); ASSERT_GE(tmp, 0); LoopDevice loop(tmp, 10s); @@ -580,7 +605,7 @@ TEST(libdm, IsDmBlockDevice) { ASSERT_FALSE(dm.IsDmBlockDevice(loop.device())); } -TEST(libdm, GetDmDeviceNameByPath) { +TEST_F(DmTest, GetDmDeviceNameByPath) { unique_fd tmp(CreateTempFile("file_1", 4096)); ASSERT_GE(tmp, 0); LoopDevice loop(tmp, 10s); @@ -601,7 +626,7 @@ TEST(libdm, GetDmDeviceNameByPath) { ASSERT_EQ("libdm-test-dm-linear", *name); } -TEST(libdm, GetParentBlockDeviceByPath) { +TEST_F(DmTest, GetParentBlockDeviceByPath) { unique_fd tmp(CreateTempFile("file_1", 4096)); ASSERT_GE(tmp, 0); LoopDevice loop(tmp, 10s); @@ -621,7 +646,7 @@ TEST(libdm, GetParentBlockDeviceByPath) { ASSERT_EQ(loop.device(), *sub_block_device); } -TEST(libdm, DeleteDeviceDeferredNoReferences) { +TEST_F(DmTest, DeleteDeviceDeferredNoReferences) { unique_fd tmp(CreateTempFile("file_1", 4096)); ASSERT_GE(tmp, 0); LoopDevice loop(tmp, 10s); @@ -647,7 +672,7 @@ TEST(libdm, DeleteDeviceDeferredNoReferences) { ASSERT_EQ(ENOENT, errno); } -TEST(libdm, DeleteDeviceDeferredWaitsForLastReference) { +TEST_F(DmTest, DeleteDeviceDeferredWaitsForLastReference) { unique_fd tmp(CreateTempFile("file_1", 4096)); ASSERT_GE(tmp, 0); LoopDevice loop(tmp, 10s); @@ -682,7 +707,7 @@ TEST(libdm, DeleteDeviceDeferredWaitsForLastReference) { ASSERT_EQ(ENOENT, errno); } -TEST(libdm, CreateEmptyDevice) { +TEST_F(DmTest, CreateEmptyDevice) { DeviceMapper& dm = DeviceMapper::Instance(); ASSERT_TRUE(dm.CreateEmptyDevice("empty-device")); auto guard = @@ -692,9 +717,7 @@ TEST(libdm, CreateEmptyDevice) { ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device")); } -TEST(libdm, UeventAfterLoadTable) { - static const char* kDeviceName = "libdm-test-uevent-load-table"; - +TEST_F(DmTest, UeventAfterLoadTable) { struct utsname u; ASSERT_EQ(uname(&u), 0); @@ -706,18 +729,31 @@ TEST(libdm, UeventAfterLoadTable) { } DeviceMapper& dm = DeviceMapper::Instance(); - ASSERT_TRUE(dm.CreateEmptyDevice(kDeviceName)); + ASSERT_TRUE(dm.CreateEmptyDevice(test_name_)); DmTable table; table.Emplace(0, 1); - ASSERT_TRUE(dm.LoadTable(kDeviceName, table)); + ASSERT_TRUE(dm.LoadTable(test_name_, table)); std::string ignore_path; - ASSERT_TRUE(dm.WaitForDevice(kDeviceName, 5s, &ignore_path)); + ASSERT_TRUE(dm.WaitForDevice(test_name_, 5s, &ignore_path)); - auto info = dm.GetDetailedInfo(kDeviceName); + auto info = dm.GetDetailedInfo(test_name_); ASSERT_TRUE(info.has_value()); ASSERT_TRUE(info->IsSuspended()); - ASSERT_TRUE(dm.DeleteDevice(kDeviceName)); + ASSERT_TRUE(dm.DeleteDevice(test_name_)); +} + +TEST_F(DmTest, GetNameAndUuid) { + auto& dm = DeviceMapper::Instance(); + ASSERT_TRUE(dm.CreatePlaceholderDevice(test_name_)); + + dev_t dev; + ASSERT_TRUE(dm.GetDeviceNumber(test_name_, &dev)); + + std::string name, uuid; + ASSERT_TRUE(dm.GetDeviceNameAndUuid(dev, &name, &uuid)); + ASSERT_EQ(name, test_name_); + ASSERT_FALSE(uuid.empty()); } diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h index dbef8f902b29..3e7ecc645eec 100644 --- a/fs_mgr/libdm/include/libdm/dm.h +++ b/fs_mgr/libdm/include/libdm/dm.h @@ -298,6 +298,8 @@ class DeviceMapper final : public IDeviceMapper { // a placeholder table containing dm-error. bool CreatePlaceholderDevice(const std::string& name); + bool GetDeviceNameAndUuid(dev_t dev, std::string* name, std::string* uuid); + private: // Maximum possible device mapper targets registered in the kernel. // This is only used to read the list of targets from kernel so we allocate diff --git a/init/devices.cpp b/init/devices.cpp index 39442a0e8019..d29ffd604f4e 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -112,17 +113,14 @@ static bool FindVbdDevicePrefix(const std::string& path, std::string* result) { // the supplied buffer with the dm module's instantiated name. // If it doesn't start with a virtual block device, or there is some // error, return false. -static bool FindDmDevice(const std::string& path, std::string* name, std::string* uuid) { - if (!StartsWith(path, "/devices/virtual/block/dm-")) return false; +static bool FindDmDevice(const Uevent& uevent, std::string* name, std::string* uuid) { + if (!StartsWith(uevent.path, "/devices/virtual/block/dm-")) return false; + if (uevent.action == "remove") return false; // Avoid error spam from ioctl - if (!ReadFileToString("/sys" + path + "/dm/name", name)) { - return false; - } - ReadFileToString("/sys" + path + "/dm/uuid", uuid); + dev_t dev = makedev(uevent.major, uevent.minor); - *name = android::base::Trim(*name); - *uuid = android::base::Trim(*uuid); - return true; + auto& dm = android::dm::DeviceMapper::Instance(); + return dm.GetDeviceNameAndUuid(dev, name, uuid); } Permissions::Permissions(const std::string& name, mode_t perm, uid_t uid, gid_t gid, @@ -392,7 +390,7 @@ std::vector DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uev type = "pci"; } else if (FindVbdDevicePrefix(uevent.path, &device)) { type = "vbd"; - } else if (FindDmDevice(uevent.path, &partition, &uuid)) { + } else if (FindDmDevice(uevent, &partition, &uuid)) { std::vector symlinks = {"/dev/block/mapper/" + partition}; if (!uuid.empty()) { symlinks.emplace_back("/dev/block/mapper/by-uuid/" + uuid); From 874fdaed435009dfba8255bae4a2dbdc1900b2a4 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 8 May 2023 21:17:32 -0700 Subject: [PATCH 0102/1487] libsnapshot: Add CowWriterBase, clean up CowWriter. To support multiple implementations of CowWriter, we will need to move direct usage of CowWriter to ICowWriter. This CL does this while also adding some small cleanups: - Move ICowWriter implementation methods to a new CowWriterBase class. This keeps ICowWriter as a clean interface. - Make the "Add" methods pure virtual, move the "Emit" methods to CowWriterBase as an implementation detail. - Simplify Initialize/InitializeAppend so they can be shared. - Rename CowWriter to CowWriterV2. - Rename cow_writer.cpp to writer_v2.cpp. - Rename cow_api_test.cpp to test_v2.cpp. - Remove ICowWriter::options, replace with GetBlockSize. - Add a CreateCowWriter helper to avoid implementation details in update_engine. Bug: 280529365 Test: builds Change-Id: If50faf03b292c6c8b23a6170e3f37329fb759ff6 --- fs_mgr/libsnapshot/Android.bp | 9 +- .../include/libsnapshot/cow_format.h | 4 + .../include/libsnapshot/cow_writer.h | 150 ++---------- .../libsnapshot/mock_snapshot_writer.h | 25 +- .../include/libsnapshot/snapshot_writer.h | 50 ++-- .../libsnapshot_cow/cow_format.cpp | 25 ++ .../{cow_api_test.cpp => test_v2.cpp} | 154 ++++++------ .../libsnapshot_cow/writer_base.cpp | 163 ++++++++++++ .../libsnapshot/libsnapshot_cow/writer_base.h | 71 ++++++ .../{cow_writer.cpp => writer_v2.cpp} | 231 ++++-------------- .../libsnapshot/libsnapshot_cow/writer_v2.h | 94 +++++++ fs_mgr/libsnapshot/snapshot.cpp | 5 +- fs_mgr/libsnapshot/snapshot_test.cpp | 12 +- fs_mgr/libsnapshot/snapshot_writer.cpp | 68 ++++-- .../dm-snapshot-merge/cow_snapuserd_test.cpp | 209 +++++++--------- .../user-space-merge/snapuserd_test.cpp | 111 ++++----- 16 files changed, 748 insertions(+), 633 deletions(-) rename fs_mgr/libsnapshot/libsnapshot_cow/{cow_api_test.cpp => test_v2.cpp} (91%) create mode 100644 fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp create mode 100644 fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h rename fs_mgr/libsnapshot/libsnapshot_cow/{cow_writer.cpp => writer_v2.cpp} (75%) create mode 100644 fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index cba68446792a..e931bec39ff0 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -174,12 +174,13 @@ cc_library_static { "libsnapshot_cow_defaults", ], srcs: [ + "libsnapshot_cow/cow_compress.cpp", "libsnapshot_cow/cow_decompress.cpp", - "libsnapshot_cow/cow_reader.cpp", - "libsnapshot_cow/cow_writer.cpp", "libsnapshot_cow/cow_format.cpp", - "libsnapshot_cow/cow_compress.cpp", + "libsnapshot_cow/cow_reader.cpp", "libsnapshot_cow/parser_v2.cpp", + "libsnapshot_cow/writer_base.cpp", + "libsnapshot_cow/writer_v2.cpp", ], host_supported: true, recovery_available: true, @@ -371,7 +372,7 @@ cc_test { "libsnapshot_cow_defaults", ], srcs: [ - "libsnapshot_cow/cow_api_test.cpp", + "libsnapshot_cow/test_v2.cpp", ], cflags: [ "-D_FILE_OFFSET_BITS=64", diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h index b228dff8d72c..dd626bc4683a 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h @@ -31,6 +31,10 @@ static constexpr uint32_t kCowVersionManifest = 2; static constexpr uint32_t kMinCowVersion = 1; static constexpr uint32_t kMaxCowVersion = 2; +// Normally, this should be kMaxCowVersion. When a new version is under testing +// it may be the previous value of kMaxCowVersion. +static constexpr uint32_t kDefaultCowVersion = 2; + // This header appears as the first sequence of bytes in the COW. All fields // in the layout are little-endian encoded. The on-disk layout is: // diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h index 7881f35099dd..af2d3efc521a 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h @@ -1,16 +1,16 @@ -// Copyright (C) 2019 The Android Open Source Project +// copyright (c) 2019 the android open source project // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// 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 +// 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. +// 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. #pragma once @@ -61,30 +61,28 @@ struct CowOptions { // will occur in the sequence they were added to the COW. class ICowWriter { public: - explicit ICowWriter(const CowOptions& options) : options_(options) {} - virtual ~ICowWriter() {} // Encode an operation that copies the contents of |old_block| to the // location of |new_block|. 'num_blocks' is the number of contiguous // COPY operations from |old_block| to |new_block|. - bool AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1); + virtual bool AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) = 0; // Encode a sequence of raw blocks. |size| must be a multiple of the block size. - bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size); + virtual bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) = 0; // Add a sequence of xor'd blocks. |size| must be a multiple of the block size. - bool AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block, - uint16_t offset); + virtual bool AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, + uint32_t old_block, uint16_t offset) = 0; // Encode a sequence of zeroed blocks. |size| must be a multiple of the block size. - bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks); + virtual bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) = 0; // Add a label to the op sequence. - bool AddLabel(uint64_t label); + virtual bool AddLabel(uint64_t label) = 0; // Add sequence data for op merging. Data is a list of the destination block numbers. - bool AddSequenceData(size_t num_ops, const uint32_t* data); + virtual bool AddSequenceData(size_t num_ops, const uint32_t* data) = 0; // Flush all pending writes. This must be called before closing the writer // to ensure that the correct headers and footers are written. @@ -93,21 +91,8 @@ class ICowWriter { // Return number of bytes the cow image occupies on disk. virtual uint64_t GetCowSize() = 0; - const CowOptions& options() { return options_; } - - protected: - virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) = 0; - virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) = 0; - virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, - uint32_t old_block, uint16_t offset) = 0; - virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) = 0; - virtual bool EmitLabel(uint64_t label) = 0; - virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) = 0; - - bool ValidateNewBlock(uint64_t new_block); - - protected: - CowOptions options_; + virtual uint32_t GetBlockSize() const = 0; + virtual std::optional GetMaxBlocks() const = 0; }; class CompressWorker { @@ -146,96 +131,15 @@ class CompressWorker { std::vector>* compressed_data); }; -class CowWriter : public ICowWriter { - public: - explicit CowWriter(const CowOptions& options); - ~CowWriter(); - - // Set up the writer. - // The file starts from the beginning. - // - // If fd is < 0, the CowWriter will be opened against /dev/null. This is for - // computing COW sizes without using storage space. - bool Initialize(android::base::unique_fd&& fd); - bool Initialize(android::base::borrowed_fd fd); - // Set up a writer, assuming that the given label is the last valid label. - // This will result in dropping any labels that occur after the given on, and will fail - // if the given label does not appear. - bool InitializeAppend(android::base::unique_fd&&, uint64_t label); - bool InitializeAppend(android::base::borrowed_fd fd, uint64_t label); - - bool Finalize() override; - - uint64_t GetCowSize() override; - - protected: - virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override; - virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override; - virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, - uint32_t old_block, uint16_t offset) override; - virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override; - virtual bool EmitLabel(uint64_t label) override; - virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) override; +// Create an ICowWriter not backed by any file. This is useful for estimating +// the final size of a cow file. +std::unique_ptr CreateCowEstimator(uint32_t version, const CowOptions& options); - private: - bool EmitCluster(); - bool EmitClusterIfNeeded(); - bool EmitBlocks(uint64_t new_block_start, const void* data, size_t size, uint64_t old_block, - uint16_t offset, uint8_t type); - void SetupHeaders(); - void SetupWriteOptions(); - bool ParseOptions(); - bool OpenForWrite(); - bool OpenForAppend(uint64_t label); - bool GetDataPos(uint64_t* pos); - bool WriteRawData(const void* data, size_t size); - bool WriteOperation(const CowOperation& op, const void* data = nullptr, size_t size = 0); - void AddOperation(const CowOperation& op); - void InitPos(); - void InitBatchWrites(); - void InitWorkers(); - bool FlushCluster(); - - bool CompressBlocks(size_t num_blocks, const void* data); - bool SetFd(android::base::borrowed_fd fd); - bool Sync(); - bool Truncate(off_t length); - bool EnsureSpaceAvailable(const uint64_t bytes_needed) const; - - private: - android::base::unique_fd owned_fd_; - android::base::borrowed_fd fd_; - CowHeader header_{}; - CowFooter footer_{}; - CowCompressionAlgorithm compression_ = kCowCompressNone; - uint64_t current_op_pos_ = 0; - uint64_t next_op_pos_ = 0; - uint64_t next_data_pos_ = 0; - uint64_t current_data_pos_ = 0; - ssize_t total_data_written_ = 0; - uint32_t cluster_size_ = 0; - uint32_t current_cluster_size_ = 0; - uint64_t current_data_size_ = 0; - bool is_dev_null_ = false; - bool merge_in_progress_ = false; - bool is_block_device_ = false; - uint64_t cow_image_size_ = INT64_MAX; - - int num_compress_threads_ = 1; - std::vector> compress_threads_; - std::vector> threads_; - std::vector> compressed_buf_; - std::vector>::iterator buf_iter_; - - std::vector> opbuffer_vec_; - std::vector> databuffer_vec_; - std::unique_ptr cowop_vec_; - int op_vec_index_ = 0; - - std::unique_ptr data_vec_; - int data_vec_index_ = 0; - bool batch_write_ = false; -}; +// Create an ICowWriter of the given version and options. If a label is given, +// the writer is opened in append mode. +std::unique_ptr CreateCowWriter(uint32_t version, const CowOptions& options, + android::base::unique_fd&& fd, + std::optional label = {}); } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h index d798e25e3c4c..52e3a9c4eb34 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h @@ -23,30 +23,23 @@ class MockSnapshotWriter : public ISnapshotWriter { public: using FileDescriptor = ISnapshotWriter::FileDescriptor; - explicit MockSnapshotWriter(const CowOptions& options) : ISnapshotWriter(options) {} - MockSnapshotWriter() : ISnapshotWriter({}) {} - MOCK_METHOD(bool, Finalize, (), (override)); // Return number of bytes the cow image occupies on disk. MOCK_METHOD(uint64_t, GetCowSize, (), (override)); - MOCK_METHOD(bool, EmitCopy, (uint64_t, uint64_t, uint64_t), (override)); - MOCK_METHOD(bool, EmitRawBlocks, (uint64_t, const void*, size_t), (override)); - MOCK_METHOD(bool, EmitXorBlocks, (uint32_t, const void*, size_t, uint32_t, uint16_t), + MOCK_METHOD(bool, AddCopy, (uint64_t, uint64_t, uint64_t), (override)); + MOCK_METHOD(bool, AddRawBlocks, (uint64_t, const void*, size_t), (override)); + MOCK_METHOD(bool, AddXorBlocks, (uint32_t, const void*, size_t, uint32_t, uint16_t), (override)); - MOCK_METHOD(bool, EmitZeroBlocks, (uint64_t, uint64_t), (override)); - MOCK_METHOD(bool, EmitLabel, (uint64_t), (override)); - MOCK_METHOD(bool, EmitSequenceData, (size_t, const uint32_t*), (override)); - - // Open the writer in write mode (no append). + MOCK_METHOD(bool, AddZeroBlocks, (uint64_t, uint64_t), (override)); + MOCK_METHOD(bool, AddLabel, (uint64_t), (override)); + MOCK_METHOD(bool, AddSequenceData, (size_t, const uint32_t*), (override)); MOCK_METHOD(bool, Initialize, (), (override)); + MOCK_METHOD(bool, InitializeAppend, (uint64_t), (override)); MOCK_METHOD(bool, VerifyMergeOps, (), (override, const, noexcept)); - - // Open the writer in append mode, with the last label to resume - // from. See CowWriter::InitializeAppend. - MOCK_METHOD(bool, InitializeAppend, (uint64_t label), (override)); - MOCK_METHOD(std::unique_ptr, OpenReader, (), (override)); + MOCK_METHOD(uint32_t, GetBlockSize, (), (override, const)); + MOCK_METHOD(std::optional, GetMaxBlocks, (), (override, const)); }; } // namespace android::snapshot diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h index 8f6344c3b741..2653a6053026 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h @@ -31,13 +31,7 @@ class ISnapshotWriter : public ICowWriter { public: using FileDescriptor = chromeos_update_engine::FileDescriptor; - explicit ISnapshotWriter(const CowOptions& options); - - // Set the source device. This is used for AddCopy() operations, if the - // underlying writer needs the original bytes (for example if backed by - // dm-snapshot or if writing directly to an unsnapshotted region). The - // device is only opened on the first operation that requires it. - void SetSourceDevice(const std::string& source_device); + virtual ~ISnapshotWriter() {} // Open the writer in write mode (no append). virtual bool Initialize() = 0; @@ -47,15 +41,8 @@ class ISnapshotWriter : public ICowWriter { virtual bool InitializeAppend(uint64_t label) = 0; virtual std::unique_ptr OpenReader() = 0; - virtual bool VerifyMergeOps() const noexcept = 0; - protected: - android::base::borrowed_fd GetSourceFd(); - - std::optional source_device_; - - private: - android::base::unique_fd source_fd_; + virtual bool VerifyMergeOps() const noexcept = 0; }; // Send writes to a COW or a raw device directly, based on a threshold. @@ -63,6 +50,8 @@ class CompressedSnapshotWriter final : public ISnapshotWriter { public: CompressedSnapshotWriter(const CowOptions& options); + void SetSourceDevice(const std::string& source_device); + // Sets the COW device; this is required. bool SetCowDevice(android::base::unique_fd&& cow_device); @@ -70,23 +59,34 @@ class CompressedSnapshotWriter final : public ISnapshotWriter { bool InitializeAppend(uint64_t label) override; bool Finalize() override; uint64_t GetCowSize() override; + uint32_t GetBlockSize() const override; + std::optional GetMaxBlocks() const override; std::unique_ptr OpenReader() override; bool VerifyMergeOps() const noexcept; - protected: - bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override; - bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override; - bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block, - uint16_t offset) override; - bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override; - bool EmitLabel(uint64_t label) override; - bool EmitSequenceData(size_t num_ops, const uint32_t* data) override; + bool AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override; + bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) override; + bool AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block, + uint16_t offset) override; + bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override; + bool AddLabel(uint64_t label) override; + bool AddSequenceData(size_t num_ops, const uint32_t* data) override; private: std::unique_ptr OpenCowReader() const; - android::base::unique_fd cow_device_; + android::base::borrowed_fd GetSourceFd(); - std::unique_ptr cow_; + CowOptions options_; + + // Set the source device. This is used for AddCopy() operations, if the + // underlying writer needs the original bytes (for example if backed by + // dm-snapshot or if writing directly to an unsnapshotted region). The + // device is only opened on the first operation that requires it. + std::optional source_device_; + android::base::unique_fd source_fd_; + + android::base::unique_fd cow_device_; + std::unique_ptr cow_; }; } // namespace snapshot diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp index 2157d0fa94cb..ff3ccecb86aa 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp @@ -19,10 +19,13 @@ #include #include +#include "writer_v2.h" namespace android { namespace snapshot { +using android::base::unique_fd; + std::ostream& operator<<(std::ostream& os, CowOperation const& op) { os << "CowOperation(type:"; if (op.type == kCowCopyOp) @@ -103,5 +106,27 @@ bool IsOrderedOp(const CowOperation& op) { } } +std::unique_ptr CreateCowWriter(uint32_t version, const CowOptions& options, + unique_fd&& fd, std::optional label) { + std::unique_ptr base; + switch (version) { + case 1: + case 2: + base = std::make_unique(options, std::move(fd)); + break; + default: + LOG(ERROR) << "Cannot create unknown cow version: " << version; + return nullptr; + } + if (!base->Initialize(label)) { + return nullptr; + } + return base; +} + +std::unique_ptr CreateCowEstimator(uint32_t version, const CowOptions& options) { + return CreateCowWriter(version, options, unique_fd{-1}, std::nullopt); +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_api_test.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp similarity index 91% rename from fs_mgr/libsnapshot/libsnapshot_cow/cow_api_test.cpp rename to fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp index 8f80bb34533b..120b2c062c83 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_api_test.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp @@ -25,7 +25,9 @@ #include #include #include "cow_decompress.h" +#include "writer_v2.h" +using android::base::unique_fd; using testing::AssertionFailure; using testing::AssertionResult; using testing::AssertionSuccess; @@ -42,6 +44,8 @@ class CowTest : public ::testing::Test { virtual void TearDown() override { cow_ = nullptr; } + unique_fd GetCowFd() { return unique_fd{dup(cow_->fd)}; } + std::unique_ptr cow_; }; @@ -53,9 +57,9 @@ static inline bool ReadData(CowReader& reader, const CowOperation* op, void* buf TEST_F(CowTest, CopyContiguous) { CowOptions options; options.cluster_ops = 0; - CowWriter writer(options); + CowWriterV2 writer(options, GetCowFd()); - ASSERT_TRUE(writer.Initialize(cow_->fd)); + ASSERT_TRUE(writer.Initialize()); ASSERT_TRUE(writer.AddCopy(10, 1000, 100)); ASSERT_TRUE(writer.Finalize()); @@ -96,9 +100,9 @@ TEST_F(CowTest, CopyContiguous) { TEST_F(CowTest, ReadWrite) { CowOptions options; options.cluster_ops = 0; - CowWriter writer(options); + CowWriterV2 writer(options, GetCowFd()); - ASSERT_TRUE(writer.Initialize(cow_->fd)); + ASSERT_TRUE(writer.Initialize()); std::string data = "This is some data, believe it"; data.resize(options.block_size, '\0'); @@ -175,9 +179,9 @@ TEST_F(CowTest, ReadWrite) { TEST_F(CowTest, ReadWriteXor) { CowOptions options; options.cluster_ops = 0; - CowWriter writer(options); + CowWriterV2 writer(options, GetCowFd()); - ASSERT_TRUE(writer.Initialize(cow_->fd)); + ASSERT_TRUE(writer.Initialize()); std::string data = "This is some data, believe it"; data.resize(options.block_size, '\0'); @@ -256,9 +260,9 @@ TEST_F(CowTest, CompressGz) { CowOptions options; options.cluster_ops = 0; options.compression = "gz"; - CowWriter writer(options); + CowWriterV2 writer(options, GetCowFd()); - ASSERT_TRUE(writer.Initialize(cow_->fd)); + ASSERT_TRUE(writer.Initialize()); std::string data = "This is some data, believe it"; data.resize(options.block_size, '\0'); @@ -296,9 +300,9 @@ TEST_P(CompressionTest, ThreadedBatchWrites) { options.compression = GetParam(); options.num_compress_threads = 2; - CowWriter writer(options); + CowWriterV2 writer(options, GetCowFd()); - ASSERT_TRUE(writer.Initialize(cow_->fd)); + ASSERT_TRUE(writer.Initialize()); std::string xor_data = "This is test data-1. Testing xor"; xor_data.resize(options.block_size, '\0'); @@ -374,9 +378,9 @@ TEST_P(CompressionTest, NoBatchWrites) { options.num_compress_threads = 1; options.cluster_ops = 0; - CowWriter writer(options); + CowWriterV2 writer(options, GetCowFd()); - ASSERT_TRUE(writer.Initialize(cow_->fd)); + ASSERT_TRUE(writer.Initialize()); std::string data = "Testing replace ops without batch writes"; data.resize(options.block_size * 1024, '\0'); @@ -497,9 +501,9 @@ TEST_F(CowTest, ClusterCompressGz) { CowOptions options; options.compression = "gz"; options.cluster_ops = 2; - CowWriter writer(options); + CowWriterV2 writer(options, GetCowFd()); - ASSERT_TRUE(writer.Initialize(cow_->fd)); + ASSERT_TRUE(writer.Initialize()); std::string data = "This is some data, believe it"; data.resize(options.block_size, '\0'); @@ -562,9 +566,9 @@ TEST_F(CowTest, CompressTwoBlocks) { CowOptions options; options.compression = "gz"; options.cluster_ops = 0; - CowWriter writer(options); + CowWriterV2 writer(options, GetCowFd()); - ASSERT_TRUE(writer.Initialize(cow_->fd)); + ASSERT_TRUE(writer.Initialize()); std::string data = "This is some data, believe it"; data.resize(options.block_size * 2, '\0'); @@ -595,12 +599,12 @@ TEST_F(CowTest, CompressTwoBlocks) { TEST_F(CowTest, GetSize) { CowOptions options; options.cluster_ops = 0; - CowWriter writer(options); + CowWriterV2 writer(options, GetCowFd()); if (ftruncate(cow_->fd, 0) < 0) { perror("Fails to set temp file size"); FAIL(); } - ASSERT_TRUE(writer.Initialize(cow_->fd)); + ASSERT_TRUE(writer.Initialize()); std::string data = "This is some data, believe it"; data.resize(options.block_size, '\0'); @@ -621,8 +625,8 @@ TEST_F(CowTest, GetSize) { TEST_F(CowTest, AppendLabelSmall) { CowOptions options; options.cluster_ops = 0; - auto writer = std::make_unique(options); - ASSERT_TRUE(writer->Initialize(cow_->fd)); + auto writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize()); std::string data = "This is some data, believe it"; data.resize(options.block_size, '\0'); @@ -632,8 +636,8 @@ TEST_F(CowTest, AppendLabelSmall) { ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0); - writer = std::make_unique(options); - ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 3)); + writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize({3})); std::string data2 = "More data!"; data2.resize(options.block_size, '\0'); @@ -688,8 +692,8 @@ TEST_F(CowTest, AppendLabelSmall) { TEST_F(CowTest, AppendLabelMissing) { CowOptions options; options.cluster_ops = 0; - auto writer = std::make_unique(options); - ASSERT_TRUE(writer->Initialize(cow_->fd)); + auto writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize()); ASSERT_TRUE(writer->AddLabel(0)); std::string data = "This is some data, believe it"; @@ -701,9 +705,9 @@ TEST_F(CowTest, AppendLabelMissing) { ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0); - writer = std::make_unique(options); - ASSERT_FALSE(writer->InitializeAppend(cow_->fd, 1)); - ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 0)); + writer = std::make_unique(options, GetCowFd()); + ASSERT_FALSE(writer->Initialize({1})); + ASSERT_TRUE(writer->Initialize({0})); ASSERT_TRUE(writer->AddZeroBlocks(51, 1)); ASSERT_TRUE(writer->Finalize()); @@ -740,8 +744,8 @@ TEST_F(CowTest, AppendLabelMissing) { TEST_F(CowTest, AppendExtendedCorrupted) { CowOptions options; options.cluster_ops = 0; - auto writer = std::make_unique(options); - ASSERT_TRUE(writer->Initialize(cow_->fd)); + auto writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize()); ASSERT_TRUE(writer->AddLabel(5)); @@ -763,8 +767,8 @@ TEST_F(CowTest, AppendExtendedCorrupted) { ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0); - writer = std::make_unique(options); - ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 5)); + writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize({5})); ASSERT_TRUE(writer->Finalize()); @@ -791,8 +795,8 @@ TEST_F(CowTest, AppendExtendedCorrupted) { TEST_F(CowTest, AppendbyLabel) { CowOptions options; options.cluster_ops = 0; - auto writer = std::make_unique(options); - ASSERT_TRUE(writer->Initialize(cow_->fd)); + auto writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize()); std::string data = "This is some data, believe it"; data.resize(options.block_size * 2, '\0'); @@ -810,9 +814,9 @@ TEST_F(CowTest, AppendbyLabel) { ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0); - writer = std::make_unique(options); - ASSERT_FALSE(writer->InitializeAppend(cow_->fd, 12)); - ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 5)); + writer = std::make_unique(options, GetCowFd()); + ASSERT_FALSE(writer->Initialize({12})); + ASSERT_TRUE(writer->Initialize({5})); // This should drop label 6 ASSERT_TRUE(writer->Finalize()); @@ -879,8 +883,8 @@ TEST_F(CowTest, AppendbyLabel) { TEST_F(CowTest, ClusterTest) { CowOptions options; options.cluster_ops = 4; - auto writer = std::make_unique(options); - ASSERT_TRUE(writer->Initialize(cow_->fd)); + auto writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize()); std::string data = "This is some data, believe it"; data.resize(options.block_size, '\0'); @@ -976,16 +980,16 @@ TEST_F(CowTest, ClusterTest) { TEST_F(CowTest, ClusterAppendTest) { CowOptions options; options.cluster_ops = 3; - auto writer = std::make_unique(options); - ASSERT_TRUE(writer->Initialize(cow_->fd)); + auto writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize()); ASSERT_TRUE(writer->AddLabel(50)); ASSERT_TRUE(writer->Finalize()); // Adds a cluster op, should be dropped on append ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0); - writer = std::make_unique(options); - ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 50)); + writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize({50})); std::string data2 = "More data!"; data2.resize(options.block_size, '\0'); @@ -1037,8 +1041,8 @@ TEST_F(CowTest, ClusterAppendTest) { TEST_F(CowTest, AppendAfterFinalize) { CowOptions options; options.cluster_ops = 0; - auto writer = std::make_unique(options); - ASSERT_TRUE(writer->Initialize(cow_->fd)); + auto writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize()); std::string data = "This is some data, believe it"; data.resize(options.block_size, '\0'); @@ -1058,8 +1062,8 @@ TEST_F(CowTest, AppendAfterFinalize) { ASSERT_TRUE(reader.Parse(cow_->fd)); } -AssertionResult WriteDataBlock(CowWriter* writer, uint64_t new_block, std::string data) { - data.resize(writer->options().block_size, '\0'); +AssertionResult WriteDataBlock(ICowWriter* writer, uint64_t new_block, std::string data) { + data.resize(writer->GetBlockSize(), '\0'); if (!writer->AddRawBlocks(new_block, data.data(), data.size())) { return AssertionFailure() << "Failed to add raw block"; } @@ -1088,8 +1092,8 @@ AssertionResult CompareDataBlock(CowReader* reader, const CowOperation* op, TEST_F(CowTest, ResumeMidCluster) { CowOptions options; options.cluster_ops = 7; - auto writer = std::make_unique(options); - ASSERT_TRUE(writer->Initialize(cow_->fd)); + auto writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize()); ASSERT_TRUE(WriteDataBlock(writer.get(), 1, "Block 1")); ASSERT_TRUE(WriteDataBlock(writer.get(), 2, "Block 2")); @@ -1099,8 +1103,8 @@ TEST_F(CowTest, ResumeMidCluster) { ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4")); ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0); - writer = std::make_unique(options); - ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1)); + writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize({1})); ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4")); ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5")); ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6")); @@ -1145,8 +1149,8 @@ TEST_F(CowTest, ResumeEndCluster) { CowOptions options; int cluster_ops = 5; options.cluster_ops = cluster_ops; - auto writer = std::make_unique(options); - ASSERT_TRUE(writer->Initialize(cow_->fd)); + auto writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize()); ASSERT_TRUE(WriteDataBlock(writer.get(), 1, "Block 1")); ASSERT_TRUE(WriteDataBlock(writer.get(), 2, "Block 2")); @@ -1160,8 +1164,8 @@ TEST_F(CowTest, ResumeEndCluster) { ASSERT_TRUE(WriteDataBlock(writer.get(), 8, "Block 8")); ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0); - writer = std::make_unique(options); - ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1)); + writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize({1})); ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4")); ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5")); ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6")); @@ -1205,8 +1209,8 @@ TEST_F(CowTest, ResumeEndCluster) { TEST_F(CowTest, DeleteMidCluster) { CowOptions options; options.cluster_ops = 7; - auto writer = std::make_unique(options); - ASSERT_TRUE(writer->Initialize(cow_->fd)); + auto writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize()); ASSERT_TRUE(WriteDataBlock(writer.get(), 1, "Block 1")); ASSERT_TRUE(WriteDataBlock(writer.get(), 2, "Block 2")); @@ -1218,8 +1222,8 @@ TEST_F(CowTest, DeleteMidCluster) { ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6")); ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0); - writer = std::make_unique(options); - ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1)); + writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize({1})); ASSERT_TRUE(writer->Finalize()); ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0); @@ -1255,14 +1259,14 @@ TEST_F(CowTest, DeleteMidCluster) { TEST_F(CowTest, BigSeqOp) { CowOptions options; - CowWriter writer(options); + CowWriterV2 writer(options, GetCowFd()); const int seq_len = std::numeric_limits::max() / sizeof(uint32_t) + 1; uint32_t sequence[seq_len]; for (int i = 0; i < seq_len; i++) { sequence[i] = i + 1; } - ASSERT_TRUE(writer.Initialize(cow_->fd)); + ASSERT_TRUE(writer.Initialize()); ASSERT_TRUE(writer.AddSequenceData(seq_len, sequence)); ASSERT_TRUE(writer.AddZeroBlocks(1, seq_len)); @@ -1287,14 +1291,14 @@ TEST_F(CowTest, BigSeqOp) { TEST_F(CowTest, MissingSeqOp) { CowOptions options; - CowWriter writer(options); + CowWriterV2 writer(options, GetCowFd()); const int seq_len = 10; uint32_t sequence[seq_len]; for (int i = 0; i < seq_len; i++) { sequence[i] = i + 1; } - ASSERT_TRUE(writer.Initialize(cow_->fd)); + ASSERT_TRUE(writer.Initialize()); ASSERT_TRUE(writer.AddSequenceData(seq_len, sequence)); ASSERT_TRUE(writer.AddZeroBlocks(1, seq_len - 1)); @@ -1308,14 +1312,14 @@ TEST_F(CowTest, MissingSeqOp) { TEST_F(CowTest, ResumeSeqOp) { CowOptions options; - auto writer = std::make_unique(options); + auto writer = std::make_unique(options, GetCowFd()); const int seq_len = 10; uint32_t sequence[seq_len]; for (int i = 0; i < seq_len; i++) { sequence[i] = i + 1; } - ASSERT_TRUE(writer->Initialize(cow_->fd)); + ASSERT_TRUE(writer->Initialize()); ASSERT_TRUE(writer->AddSequenceData(seq_len, sequence)); ASSERT_TRUE(writer->AddZeroBlocks(1, seq_len / 2)); @@ -1328,8 +1332,8 @@ TEST_F(CowTest, ResumeSeqOp) { auto itr = reader->GetRevMergeOpIter(); ASSERT_TRUE(itr->AtEnd()); - writer = std::make_unique(options); - ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1)); + writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize({1})); ASSERT_TRUE(writer->AddZeroBlocks(1 + seq_len / 2, seq_len / 2)); ASSERT_TRUE(writer->Finalize()); @@ -1358,10 +1362,10 @@ TEST_F(CowTest, RevMergeOpItrTest) { CowOptions options; options.cluster_ops = 5; options.num_merge_ops = 1; - CowWriter writer(options); + CowWriterV2 writer(options, GetCowFd()); uint32_t sequence[] = {2, 10, 6, 7, 3, 5}; - ASSERT_TRUE(writer.Initialize(cow_->fd)); + ASSERT_TRUE(writer.Initialize()); ASSERT_TRUE(writer.AddSequenceData(6, sequence)); ASSERT_TRUE(writer.AddCopy(6, 13)); @@ -1408,9 +1412,9 @@ TEST_F(CowTest, LegacyRevMergeOpItrTest) { CowOptions options; options.cluster_ops = 5; options.num_merge_ops = 1; - CowWriter writer(options); + CowWriterV2 writer(options, GetCowFd()); - ASSERT_TRUE(writer.Initialize(cow_->fd)); + ASSERT_TRUE(writer.Initialize()); ASSERT_TRUE(writer.AddCopy(2, 11)); ASSERT_TRUE(writer.AddCopy(10, 12)); @@ -1459,10 +1463,10 @@ TEST_F(CowTest, InvalidMergeOrderTest) { 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(options); + auto writer = std::make_unique(options, GetCowFd()); CowReader reader; - ASSERT_TRUE(writer->Initialize(cow_->fd)); + ASSERT_TRUE(writer->Initialize()); ASSERT_TRUE(writer->AddCopy(3, 2)); ASSERT_TRUE(writer->AddCopy(2, 1)); @@ -1471,14 +1475,14 @@ TEST_F(CowTest, InvalidMergeOrderTest) { ASSERT_TRUE(reader.Parse(cow_->fd)); ASSERT_TRUE(reader.VerifyMergeOps()); - ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1)); + ASSERT_TRUE(writer->Initialize({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(options); - ASSERT_TRUE(writer->Initialize(cow_->fd)); + writer = std::make_unique(options, GetCowFd()); + ASSERT_TRUE(writer->Initialize()); ASSERT_TRUE(writer->AddCopy(2, 1)); ASSERT_TRUE(writer->AddXorBlocks(3, &data, data.size(), 1, 1)); ASSERT_TRUE(writer->Finalize()); diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp new file mode 100644 index 000000000000..22e63d0a323d --- /dev/null +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp @@ -0,0 +1,163 @@ +// Copyright (C) 2023 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 "writer_base.h" + +#include +#include +#include +#include +#include + +#include + +// The info messages here are spammy, but as useful for update_engine. Disable +// them when running on the host. +#ifdef __ANDROID__ +#define LOG_INFO LOG(INFO) +#else +#define LOG_INFO LOG(VERBOSE) +#endif + +namespace android { +namespace snapshot { + +using android::base::borrowed_fd; +using android::base::unique_fd; + +namespace { +std::string GetFdPath(borrowed_fd fd) { + const auto fd_path = "/proc/self/fd/" + std::to_string(fd.get()); + std::string file_path(512, '\0'); + const auto err = readlink(fd_path.c_str(), file_path.data(), file_path.size()); + if (err <= 0) { + PLOG(ERROR) << "Failed to determine path for fd " << fd.get(); + file_path.clear(); + } else { + file_path.resize(err); + } + return file_path; +} +} // namespace + +CowWriterBase::CowWriterBase(const CowOptions& options, unique_fd&& fd) + : options_(options), fd_(std::move(fd)) {} + +bool CowWriterBase::InitFd() { + if (fd_.get() < 0) { + fd_.reset(open("/dev/null", O_RDWR | O_CLOEXEC)); + if (fd_ < 0) { + PLOG(ERROR) << "open /dev/null failed"; + return false; + } + is_dev_null_ = true; + return true; + } + + struct stat stat {}; + if (fstat(fd_.get(), &stat) < 0) { + PLOG(ERROR) << "fstat failed"; + return false; + } + const auto file_path = GetFdPath(fd_); + is_block_device_ = S_ISBLK(stat.st_mode); + if (is_block_device_) { + uint64_t size_in_bytes = 0; + if (ioctl(fd_.get(), BLKGETSIZE64, &size_in_bytes)) { + PLOG(ERROR) << "Failed to get total size for: " << fd_.get(); + return false; + } + cow_image_size_ = size_in_bytes; + LOG_INFO << "COW image " << file_path << " has size " << size_in_bytes; + } else { + LOG_INFO << "COW image " << file_path + << " is not a block device, assuming unlimited space."; + } + return true; +} + +bool CowWriterBase::AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks) { + CHECK(num_blocks != 0); + + for (size_t i = 0; i < num_blocks; i++) { + if (!ValidateNewBlock(new_block + i)) { + return false; + } + } + + return EmitCopy(new_block, old_block, num_blocks); +} + +bool CowWriterBase::AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) { + if (size % options_.block_size != 0) { + LOG(ERROR) << "AddRawBlocks: size " << size << " is not a multiple of " + << options_.block_size; + return false; + } + + uint64_t num_blocks = size / options_.block_size; + uint64_t last_block = new_block_start + num_blocks - 1; + if (!ValidateNewBlock(last_block)) { + return false; + } + return EmitRawBlocks(new_block_start, data, size); +} + +bool CowWriterBase::AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, + uint32_t old_block, uint16_t offset) { + if (size % options_.block_size != 0) { + LOG(ERROR) << "AddRawBlocks: size " << size << " is not a multiple of " + << options_.block_size; + return false; + } + + uint64_t num_blocks = size / options_.block_size; + uint64_t last_block = new_block_start + num_blocks - 1; + if (!ValidateNewBlock(last_block)) { + return false; + } + if (offset >= options_.block_size) { + LOG(ERROR) << "AddXorBlocks: offset " << offset << " is not less than " + << options_.block_size; + } + return EmitXorBlocks(new_block_start, data, size, old_block, offset); +} + +bool CowWriterBase::AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { + uint64_t last_block = new_block_start + num_blocks - 1; + if (!ValidateNewBlock(last_block)) { + return false; + } + return EmitZeroBlocks(new_block_start, num_blocks); +} + +bool CowWriterBase::AddLabel(uint64_t label) { + return EmitLabel(label); +} + +bool CowWriterBase::AddSequenceData(size_t num_ops, const uint32_t* data) { + return EmitSequenceData(num_ops, data); +} + +bool CowWriterBase::ValidateNewBlock(uint64_t new_block) { + if (options_.max_blocks && new_block >= options_.max_blocks.value()) { + LOG(ERROR) << "New block " << new_block << " exceeds maximum block count " + << options_.max_blocks.value(); + return false; + } + return true; +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h new file mode 100644 index 000000000000..8fa90656fe6b --- /dev/null +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h @@ -0,0 +1,71 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include + +namespace android { +namespace snapshot { + +class CowWriterBase : public ICowWriter { + public: + CowWriterBase(const CowOptions& options, android::base::unique_fd&& fd); + virtual ~CowWriterBase() {} + + // Set up the writer. + // The file starts from the beginning. + // + // If fd is < 0, the CowWriter will be opened against /dev/null. This is for + // computing COW sizes without using storage space. + // + // If a label is given, any operations after the given label will be dropped. + // If the given label is not found, Initialize will fail. + virtual bool Initialize(std::optional label = {}) = 0; + + bool AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override; + bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) override; + bool AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block, + uint16_t offset) override; + bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override; + bool AddLabel(uint64_t label) override; + bool AddSequenceData(size_t num_ops, const uint32_t* data) override; + uint32_t GetBlockSize() const override { return options_.block_size; } + std::optional GetMaxBlocks() const override { return options_.max_blocks; } + + const CowOptions& options() const { return options_; } + + protected: + virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) = 0; + virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) = 0; + virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, + uint32_t old_block, uint16_t offset) = 0; + virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) = 0; + virtual bool EmitLabel(uint64_t label) = 0; + virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) = 0; + + bool InitFd(); + bool ValidateNewBlock(uint64_t new_block); + + CowOptions options_; + CowHeader header_{}; + + android::base::unique_fd fd_; + bool is_dev_null_ = false; + bool is_block_device_ = false; + uint64_t cow_image_size_ = INT64_MAX; +}; + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp similarity index 75% rename from fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp rename to fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp index 1eaa0385ee26..b6603da52edf 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp @@ -37,6 +37,8 @@ #include #include +#include "writer_v2.h" + // The info messages here are spammy, but as useful for update_engine. Disable // them when running on the host. #ifdef __ANDROID__ @@ -48,104 +50,17 @@ namespace android { namespace snapshot { -namespace { -std::string GetFdPath(int fd) { - const auto fd_path = "/proc/self/fd/" + std::to_string(fd); - std::string file_path(512, '\0'); - const auto err = readlink(fd_path.c_str(), file_path.data(), file_path.size()); - if (err <= 0) { - PLOG(ERROR) << "Failed to determine path for fd " << fd; - file_path.clear(); - } else { - file_path.resize(err); - } - return file_path; -} -} // namespace - static_assert(sizeof(off_t) == sizeof(uint64_t)); -using android::base::borrowed_fd; using android::base::unique_fd; -bool ICowWriter::AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks) { - CHECK(num_blocks != 0); - - for (size_t i = 0; i < num_blocks; i++) { - if (!ValidateNewBlock(new_block + i)) { - return false; - } - } - - return EmitCopy(new_block, old_block, num_blocks); -} - -bool ICowWriter::AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) { - if (size % options_.block_size != 0) { - LOG(ERROR) << "AddRawBlocks: size " << size << " is not a multiple of " - << options_.block_size; - return false; - } - - uint64_t num_blocks = size / options_.block_size; - uint64_t last_block = new_block_start + num_blocks - 1; - if (!ValidateNewBlock(last_block)) { - return false; - } - return EmitRawBlocks(new_block_start, data, size); -} - -bool ICowWriter::AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, - uint32_t old_block, uint16_t offset) { - if (size % options_.block_size != 0) { - LOG(ERROR) << "AddRawBlocks: size " << size << " is not a multiple of " - << options_.block_size; - return false; - } - - uint64_t num_blocks = size / options_.block_size; - uint64_t last_block = new_block_start + num_blocks - 1; - if (!ValidateNewBlock(last_block)) { - return false; - } - if (offset >= options_.block_size) { - LOG(ERROR) << "AddXorBlocks: offset " << offset << " is not less than " - << options_.block_size; - } - return EmitXorBlocks(new_block_start, data, size, old_block, offset); -} - -bool ICowWriter::AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { - uint64_t last_block = new_block_start + num_blocks - 1; - if (!ValidateNewBlock(last_block)) { - return false; - } - return EmitZeroBlocks(new_block_start, num_blocks); -} - -bool ICowWriter::AddLabel(uint64_t label) { - return EmitLabel(label); -} - -bool ICowWriter::AddSequenceData(size_t num_ops, const uint32_t* data) { - return EmitSequenceData(num_ops, data); -} - -bool ICowWriter::ValidateNewBlock(uint64_t new_block) { - if (options_.max_blocks && new_block >= options_.max_blocks.value()) { - LOG(ERROR) << "New block " << new_block << " exceeds maximum block count " - << options_.max_blocks.value(); - return false; - } - return true; -} - -CowWriter::CowWriter(const CowOptions& options) : ICowWriter(options), fd_(-1) { +CowWriterV2::CowWriterV2(const CowOptions& options, unique_fd&& fd) + : CowWriterBase(options, std::move(fd)) { SetupHeaders(); SetupWriteOptions(); } -CowWriter::~CowWriter() { +CowWriterV2::~CowWriterV2() { for (size_t i = 0; i < compress_threads_.size(); i++) { CompressWorker* worker = compress_threads_[i].get(); if (worker) { @@ -164,7 +79,7 @@ CowWriter::~CowWriter() { compress_threads_.clear(); } -void CowWriter::SetupWriteOptions() { +void CowWriterV2::SetupWriteOptions() { num_compress_threads_ = options_.num_compress_threads; if (!num_compress_threads_) { @@ -184,7 +99,7 @@ void CowWriter::SetupWriteOptions() { } } -void CowWriter::SetupHeaders() { +void CowWriterV2::SetupHeaders() { header_ = {}; header_.prefix.magic = kCowMagicNumber; header_.prefix.major_version = kCowVersionMajor; @@ -201,7 +116,7 @@ void CowWriter::SetupHeaders() { footer_.op.type = kCowFooterOp; } -bool CowWriter::ParseOptions() { +bool CowWriterV2::ParseOptions() { auto algorithm = CompressionAlgorithmFromString(options_.compression); if (!algorithm) { LOG(ERROR) << "unrecognized compression: " << options_.compression; @@ -216,42 +131,7 @@ bool CowWriter::ParseOptions() { return true; } -bool CowWriter::SetFd(android::base::borrowed_fd fd) { - if (fd.get() < 0) { - owned_fd_.reset(open("/dev/null", O_RDWR | O_CLOEXEC)); - if (owned_fd_ < 0) { - PLOG(ERROR) << "open /dev/null failed"; - return false; - } - fd_ = owned_fd_; - is_dev_null_ = true; - } else { - fd_ = fd; - - struct stat stat {}; - if (fstat(fd.get(), &stat) < 0) { - PLOG(ERROR) << "fstat failed"; - return false; - } - const auto file_path = GetFdPath(fd.get()); - is_block_device_ = S_ISBLK(stat.st_mode); - if (is_block_device_) { - uint64_t size_in_bytes = 0; - if (ioctl(fd.get(), BLKGETSIZE64, &size_in_bytes)) { - PLOG(ERROR) << "Failed to get total size for: " << fd.get(); - return false; - } - cow_image_size_ = size_in_bytes; - LOG_INFO << "COW image " << file_path << " has size " << size_in_bytes; - } else { - LOG_INFO << "COW image " << file_path - << " is not a block device, assuming unlimited space."; - } - } - return true; -} - -void CowWriter::InitBatchWrites() { +void CowWriterV2::InitBatchWrites() { if (batch_write_) { cowop_vec_ = std::make_unique(header_.cluster_ops); data_vec_ = std::make_unique(header_.cluster_ops); @@ -277,7 +157,7 @@ void CowWriter::InitBatchWrites() { LOG_INFO << "Batch writes: " << batch_write; } -void CowWriter::InitWorkers() { +void CowWriterV2::InitWorkers() { if (num_compress_threads_ <= 1) { LOG_INFO << "Not creating new threads for compression."; return; @@ -291,44 +171,27 @@ void CowWriter::InitWorkers() { LOG_INFO << num_compress_threads_ << " thread used for compression"; } -bool CowWriter::Initialize(unique_fd&& fd) { - owned_fd_ = std::move(fd); - return Initialize(borrowed_fd{owned_fd_}); -} - -bool CowWriter::Initialize(borrowed_fd fd) { - if (!SetFd(fd) || !ParseOptions()) { +bool CowWriterV2::Initialize(std::optional label) { + if (!InitFd() || !ParseOptions()) { return false; } - - if (!OpenForWrite()) { - return false; - } - - InitWorkers(); - return true; -} - -bool CowWriter::InitializeAppend(android::base::unique_fd&& fd, uint64_t label) { - owned_fd_ = std::move(fd); - return InitializeAppend(android::base::borrowed_fd{owned_fd_}, label); -} - -bool CowWriter::InitializeAppend(android::base::borrowed_fd fd, uint64_t label) { - if (!SetFd(fd) || !ParseOptions()) { - return false; + if (!label) { + if (!OpenForWrite()) { + return false; + } + } else { + if (!OpenForAppend(*label)) { + return false; + } } - bool ret = OpenForAppend(label); - - if (ret && !compress_threads_.size()) { + if (!compress_threads_.size()) { InitWorkers(); } - - return ret; + return true; } -void CowWriter::InitPos() { +void CowWriterV2::InitPos() { next_op_pos_ = sizeof(header_) + header_.buffer_size; cluster_size_ = header_.cluster_ops * sizeof(CowOperation); if (header_.cluster_ops) { @@ -340,7 +203,7 @@ void CowWriter::InitPos() { current_data_size_ = 0; } -bool CowWriter::OpenForWrite() { +bool CowWriterV2::OpenForWrite() { // This limitation is tied to the data field size in CowOperation. if (header_.block_size > std::numeric_limits::max()) { LOG(ERROR) << "Block size is too large"; @@ -388,7 +251,7 @@ bool CowWriter::OpenForWrite() { return true; } -bool CowWriter::OpenForAppend(uint64_t label) { +bool CowWriterV2::OpenForAppend(uint64_t label) { auto reader = std::make_unique(); std::queue toAdd; @@ -424,7 +287,7 @@ bool CowWriter::OpenForAppend(uint64_t label) { return EmitClusterIfNeeded(); } -bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks) { +bool CowWriterV2::EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks) { CHECK(!merge_in_progress_); for (size_t i = 0; i < num_blocks; i++) { @@ -440,16 +303,16 @@ bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_bl return true; } -bool CowWriter::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) { +bool CowWriterV2::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) { return EmitBlocks(new_block_start, data, size, 0, 0, kCowReplaceOp); } -bool CowWriter::EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, - uint32_t old_block, uint16_t offset) { +bool CowWriterV2::EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, + uint32_t old_block, uint16_t offset) { return EmitBlocks(new_block_start, data, size, old_block, offset, kCowXorOp); } -bool CowWriter::CompressBlocks(size_t num_blocks, const void* data) { +bool CowWriterV2::CompressBlocks(size_t num_blocks, const void* data) { size_t num_threads = (num_blocks == 1) ? 1 : num_compress_threads_; size_t num_blocks_per_thread = num_blocks / num_threads; const uint8_t* iter = reinterpret_cast(data); @@ -483,8 +346,8 @@ bool CowWriter::CompressBlocks(size_t num_blocks, const void* data) { return true; } -bool CowWriter::EmitBlocks(uint64_t new_block_start, const void* data, size_t size, - uint64_t old_block, uint16_t offset, uint8_t type) { +bool CowWriterV2::EmitBlocks(uint64_t new_block_start, const void* data, size_t size, + uint64_t old_block, uint16_t offset, uint8_t type) { CHECK(!merge_in_progress_); const uint8_t* iter = reinterpret_cast(data); @@ -558,7 +421,7 @@ bool CowWriter::EmitBlocks(uint64_t new_block_start, const void* data, size_t si return true; } -bool CowWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { +bool CowWriterV2::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { CHECK(!merge_in_progress_); for (uint64_t i = 0; i < num_blocks; i++) { CowOperation op = {}; @@ -570,7 +433,7 @@ bool CowWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { return true; } -bool CowWriter::EmitLabel(uint64_t label) { +bool CowWriterV2::EmitLabel(uint64_t label) { CHECK(!merge_in_progress_); CowOperation op = {}; op.type = kCowLabelOp; @@ -578,7 +441,7 @@ bool CowWriter::EmitLabel(uint64_t label) { return WriteOperation(op) && Sync(); } -bool CowWriter::EmitSequenceData(size_t num_ops, const uint32_t* data) { +bool CowWriterV2::EmitSequenceData(size_t num_ops, const uint32_t* data) { CHECK(!merge_in_progress_); size_t to_add = 0; size_t max_ops = (header_.block_size * 2) / sizeof(uint32_t); @@ -598,7 +461,7 @@ bool CowWriter::EmitSequenceData(size_t num_ops, const uint32_t* data) { return true; } -bool CowWriter::EmitCluster() { +bool CowWriterV2::EmitCluster() { CowOperation op = {}; op.type = kCowClusterOp; // Next cluster starts after remainder of current cluster and the next data block. @@ -606,7 +469,7 @@ bool CowWriter::EmitCluster() { return WriteOperation(op); } -bool CowWriter::EmitClusterIfNeeded() { +bool CowWriterV2::EmitClusterIfNeeded() { // If there isn't room for another op and the cluster end op, end the current cluster if (cluster_size_ && cluster_size_ < current_cluster_size_ + 2 * sizeof(CowOperation)) { if (!EmitCluster()) return false; @@ -614,7 +477,7 @@ bool CowWriter::EmitClusterIfNeeded() { return true; } -bool CowWriter::Finalize() { +bool CowWriterV2::Finalize() { if (!FlushCluster()) { LOG(ERROR) << "Finalize: FlushCluster() failed"; return false; @@ -688,7 +551,7 @@ bool CowWriter::Finalize() { return Sync(); } -uint64_t CowWriter::GetCowSize() { +uint64_t CowWriterV2::GetCowSize() { if (current_data_size_ > 0) { return next_data_pos_ + sizeof(footer_); } else { @@ -696,7 +559,7 @@ uint64_t CowWriter::GetCowSize() { } } -bool CowWriter::GetDataPos(uint64_t* pos) { +bool CowWriterV2::GetDataPos(uint64_t* pos) { off_t offs = lseek(fd_.get(), 0, SEEK_CUR); if (offs < 0) { PLOG(ERROR) << "lseek failed"; @@ -706,7 +569,7 @@ bool CowWriter::GetDataPos(uint64_t* pos) { return true; } -bool CowWriter::EnsureSpaceAvailable(const uint64_t bytes_needed) const { +bool CowWriterV2::EnsureSpaceAvailable(const uint64_t bytes_needed) const { if (bytes_needed > cow_image_size_) { LOG(ERROR) << "No space left on COW device. Required: " << bytes_needed << ", available: " << cow_image_size_; @@ -716,7 +579,7 @@ bool CowWriter::EnsureSpaceAvailable(const uint64_t bytes_needed) const { return true; } -bool CowWriter::FlushCluster() { +bool CowWriterV2::FlushCluster() { ssize_t ret; if (op_vec_index_) { @@ -745,7 +608,7 @@ bool CowWriter::FlushCluster() { return true; } -bool CowWriter::WriteOperation(const CowOperation& op, const void* data, size_t size) { +bool CowWriterV2::WriteOperation(const CowOperation& op, const void* data, size_t size) { if (!EnsureSpaceAvailable(next_op_pos_ + sizeof(op))) { return false; } @@ -793,7 +656,7 @@ bool CowWriter::WriteOperation(const CowOperation& op, const void* data, size_t return EmitClusterIfNeeded(); } -void CowWriter::AddOperation(const CowOperation& op) { +void CowWriterV2::AddOperation(const CowOperation& op) { footer_.op.num_ops++; if (op.type == kCowClusterOp) { @@ -808,14 +671,14 @@ void CowWriter::AddOperation(const CowOperation& op) { next_op_pos_ += sizeof(CowOperation) + GetNextOpOffset(op, header_.cluster_ops); } -bool CowWriter::WriteRawData(const void* data, const size_t size) { +bool CowWriterV2::WriteRawData(const void* data, const size_t size) { if (!android::base::WriteFullyAtOffset(fd_, data, size, next_data_pos_)) { return false; } return true; } -bool CowWriter::Sync() { +bool CowWriterV2::Sync() { if (is_dev_null_) { return true; } @@ -826,7 +689,7 @@ bool CowWriter::Sync() { return true; } -bool CowWriter::Truncate(off_t length) { +bool CowWriterV2::Truncate(off_t length) { if (is_dev_null_ || is_block_device_) { return true; } diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h new file mode 100644 index 000000000000..809ae5747935 --- /dev/null +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h @@ -0,0 +1,94 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include "writer_base.h" + +namespace android { +namespace snapshot { + +class CowWriterV2 : public CowWriterBase { + public: + explicit CowWriterV2(const CowOptions& options, android::base::unique_fd&& fd); + ~CowWriterV2() override; + + bool Initialize(std::optional label = {}) override; + bool Finalize() override; + uint64_t GetCowSize() override; + + protected: + virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override; + virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override; + virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, + uint32_t old_block, uint16_t offset) override; + virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override; + virtual bool EmitLabel(uint64_t label) override; + virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) override; + + private: + bool EmitCluster(); + bool EmitClusterIfNeeded(); + bool EmitBlocks(uint64_t new_block_start, const void* data, size_t size, uint64_t old_block, + uint16_t offset, uint8_t type); + void SetupHeaders(); + void SetupWriteOptions(); + bool ParseOptions(); + bool OpenForWrite(); + bool OpenForAppend(uint64_t label); + bool GetDataPos(uint64_t* pos); + bool WriteRawData(const void* data, size_t size); + bool WriteOperation(const CowOperation& op, const void* data = nullptr, size_t size = 0); + void AddOperation(const CowOperation& op); + void InitPos(); + void InitBatchWrites(); + void InitWorkers(); + bool FlushCluster(); + + bool CompressBlocks(size_t num_blocks, const void* data); + bool Sync(); + bool Truncate(off_t length); + bool EnsureSpaceAvailable(const uint64_t bytes_needed) const; + + private: + CowFooter footer_{}; + CowCompressionAlgorithm compression_ = kCowCompressNone; + uint64_t current_op_pos_ = 0; + uint64_t next_op_pos_ = 0; + uint64_t next_data_pos_ = 0; + uint64_t current_data_pos_ = 0; + ssize_t total_data_written_ = 0; + uint32_t cluster_size_ = 0; + uint32_t current_cluster_size_ = 0; + uint64_t current_data_size_ = 0; + bool merge_in_progress_ = false; + + int num_compress_threads_ = 1; + std::vector> compress_threads_; + std::vector> threads_; + std::vector> compressed_buf_; + std::vector>::iterator buf_iter_; + + std::vector> opbuffer_vec_; + std::vector> databuffer_vec_; + std::unique_ptr cowop_vec_; + int op_vec_index_ = 0; + + std::unique_ptr data_vec_; + int data_vec_index_ = 0; + bool batch_write_ = false; +}; + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index e114d255654e..5920bc22fa8c 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -45,6 +45,7 @@ #include #include #include "device_info.h" +#include "libsnapshot_cow/writer_v2.h" #include "partition_cow_creator.h" #include "snapshot_metadata_updater.h" #include "snapshot_reader.h" @@ -3557,8 +3558,8 @@ Return SnapshotManager::InitializeUpdateSnapshots( } options.compression = it->second.compression_algorithm(); - CowWriter writer(options); - if (!writer.Initialize(fd) || !writer.Finalize()) { + CowWriterV2 writer(options, std::move(fd)); + if (!writer.Initialize(std::nullopt) || !writer.Finalize()) { LOG(ERROR) << "Could not initialize COW device for " << target_partition->name(); return Return::Error(); } diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index 757f6f181590..dac1b771b83d 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -1220,13 +1220,13 @@ class SnapshotUpdateTest : public SnapshotTest { SHA256_CTX ctx; SHA256_Init(&ctx); - if (!writer->options().max_blocks) { + if (!writer->GetMaxBlocks()) { LOG(ERROR) << "CowWriter must specify maximum number of blocks"; return false; } - const auto num_blocks = writer->options().max_blocks.value(); + const auto num_blocks = writer->GetMaxBlocks().value(); - const auto block_size = writer->options().block_size; + const auto block_size = writer->GetBlockSize(); std::string block(block_size, '\0'); for (uint64_t i = 0; i < num_blocks; i++) { if (!ReadFully(rand, block.data(), block.size())) { @@ -1254,13 +1254,13 @@ class SnapshotUpdateTest : public SnapshotTest { if (auto res = MapUpdateSnapshot(name, &writer); !res) { return res; } - if (!writer->options().max_blocks || !*writer->options().max_blocks) { + if (!writer->GetMaxBlocks() || !*writer->GetMaxBlocks()) { return AssertionFailure() << "No max blocks set for " << name << " writer"; } - uint64_t src_block = (old_size / writer->options().block_size) - 1; + uint64_t src_block = (old_size / writer->GetBlockSize()) - 1; uint64_t dst_block = 0; - uint64_t max_blocks = *writer->options().max_blocks; + uint64_t max_blocks = *writer->GetMaxBlocks(); while (dst_block < max_blocks && dst_block < src_block) { if (!writer->AddCopy(dst_block, src_block)) { return AssertionFailure() << "Unable to add copy for " << name << " for blocks " diff --git a/fs_mgr/libsnapshot/snapshot_writer.cpp b/fs_mgr/libsnapshot/snapshot_writer.cpp index 6a3906ead22c..0ea424c7e9d9 100644 --- a/fs_mgr/libsnapshot/snapshot_writer.cpp +++ b/fs_mgr/libsnapshot/snapshot_writer.cpp @@ -19,6 +19,7 @@ #include #include #include +#include "libsnapshot_cow/writer_v2.h" #include "snapshot_reader.h" namespace android { @@ -28,13 +29,11 @@ using android::base::borrowed_fd; using android::base::unique_fd; using chromeos_update_engine::FileDescriptor; -ISnapshotWriter::ISnapshotWriter(const CowOptions& options) : ICowWriter(options) {} - -void ISnapshotWriter::SetSourceDevice(const std::string& source_device) { +void CompressedSnapshotWriter::SetSourceDevice(const std::string& source_device) { source_device_ = {source_device}; } -borrowed_fd ISnapshotWriter::GetSourceFd() { +borrowed_fd CompressedSnapshotWriter::GetSourceFd() { if (!source_device_) { LOG(ERROR) << "Attempted to read from source device but none was set"; return borrowed_fd{-1}; @@ -50,12 +49,10 @@ borrowed_fd ISnapshotWriter::GetSourceFd() { return source_fd_; } -CompressedSnapshotWriter::CompressedSnapshotWriter(const CowOptions& options) - : ISnapshotWriter(options) {} +CompressedSnapshotWriter::CompressedSnapshotWriter(const CowOptions& options) : options_(options) {} bool CompressedSnapshotWriter::SetCowDevice(android::base::unique_fd&& cow_device) { cow_device_ = std::move(cow_device); - cow_ = std::make_unique(options_); return true; } @@ -106,47 +103,76 @@ std::unique_ptr CompressedSnapshotWriter::OpenReader() { reader->SetSourceDevice(*source_device_); } - const auto& cow_options = options(); - if (cow_options.max_blocks) { - reader->SetBlockDeviceSize(*cow_options.max_blocks * cow_options.block_size); + if (options_.max_blocks) { + reader->SetBlockDeviceSize(*options_.max_blocks * options_.block_size); } return reader; } -bool CompressedSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block, - uint64_t num_blocks) { +bool CompressedSnapshotWriter::AddCopy(uint64_t new_block, uint64_t old_block, + uint64_t num_blocks) { return cow_->AddCopy(new_block, old_block, num_blocks); } -bool CompressedSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const void* data, - size_t size) { +bool CompressedSnapshotWriter::AddRawBlocks(uint64_t new_block_start, const void* data, + size_t size) { return cow_->AddRawBlocks(new_block_start, data, size); } -bool CompressedSnapshotWriter::EmitXorBlocks(uint32_t new_block_start, const void* data, - size_t size, uint32_t old_block, uint16_t offset) { +bool CompressedSnapshotWriter::AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, + uint32_t old_block, uint16_t offset) { return cow_->AddXorBlocks(new_block_start, data, size, old_block, offset); } -bool CompressedSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { +bool CompressedSnapshotWriter::AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { return cow_->AddZeroBlocks(new_block_start, num_blocks); } -bool CompressedSnapshotWriter::EmitLabel(uint64_t label) { +bool CompressedSnapshotWriter::AddLabel(uint64_t label) { return cow_->AddLabel(label); } -bool CompressedSnapshotWriter::EmitSequenceData(size_t num_ops, const uint32_t* data) { +bool CompressedSnapshotWriter::AddSequenceData(size_t num_ops, const uint32_t* data) { return cow_->AddSequenceData(num_ops, data); } bool CompressedSnapshotWriter::Initialize() { - return cow_->Initialize(cow_device_); + unique_fd cow_fd(dup(cow_device_.get())); + if (cow_fd < 0) { + PLOG(ERROR) << "dup COW device"; + return false; + } + + auto cow = std::make_unique(options_, std::move(cow_fd)); + if (!cow->Initialize(std::nullopt)) { + return false; + } + cow_ = std::move(cow); + return true; } bool CompressedSnapshotWriter::InitializeAppend(uint64_t label) { - return cow_->InitializeAppend(cow_device_, label); + unique_fd cow_fd(dup(cow_device_.get())); + if (cow_fd < 0) { + PLOG(ERROR) << "dup COW device"; + return false; + } + + auto cow = std::make_unique(options_, std::move(cow_fd)); + if (!cow->Initialize(label)) { + return false; + } + cow_ = std::move(cow); + return true; +} + +uint32_t CompressedSnapshotWriter::GetBlockSize() const { + return cow_->GetBlockSize(); +} + +std::optional CompressedSnapshotWriter::GetMaxBlocks() const { + return cow_->GetMaxBlocks(); } } // namespace snapshot 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 3c4ab2ef7cf0..737c480a8b48 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 @@ -122,6 +122,7 @@ class CowSnapuserdTest final { void SimulateDaemonRestart(); void StartMerge(); + std::unique_ptr CreateCowDeviceInternal(); void CreateCowDevice(); void CreateCowDeviceOrderedOps(); void CreateCowDeviceOrderedOpsInverted(); @@ -164,6 +165,7 @@ class CowSnapuserdMetadataTest final { private: void InitMetadata(); + std::unique_ptr CreateCowDeviceInternal(); void CreateCowDevice(); void CreateCowPartialFilledArea(); @@ -258,6 +260,19 @@ void CowSnapuserdTest::StartSnapuserdDaemon() { } } +std::unique_ptr CowSnapuserdTest::CreateCowDeviceInternal() { + std::string path = android::base::GetExecutableDirectory(); + cow_system_ = std::make_unique(path); + + CowOptions options; + options.compression = "gz"; + + unique_fd fd(cow_system_->fd); + cow_system_->fd = -1; + + return CreateCowWriter(kDefaultCowVersion, options, std::move(fd)); +} + void CowSnapuserdTest::ReadLastBlock() { unique_fd rnd_fd; total_base_size_ = BLOCK_SZ * 2; @@ -280,9 +295,6 @@ void CowSnapuserdTest::ReadLastBlock() { base_loop_ = std::make_unique(base_fd_, 10s); ASSERT_TRUE(base_loop_->valid()); - std::string path = android::base::GetExecutableDirectory(); - cow_system_ = std::make_unique(path); - std::unique_ptr random_buffer_1_ = std::make_unique(total_base_size_); loff_t offset = 0; @@ -294,16 +306,13 @@ void CowSnapuserdTest::ReadLastBlock() { offset += BLOCK_SZ; } - CowOptions options; - options.compression = "gz"; - CowWriter writer(options); - - ASSERT_TRUE(writer.Initialize(cow_system_->fd)); + auto writer = CreateCowDeviceInternal(); + ASSERT_NE(writer, nullptr); - ASSERT_TRUE(writer.AddRawBlocks(0, random_buffer_1_.get(), BLOCK_SZ)); - ASSERT_TRUE(writer.AddRawBlocks(1, (char*)random_buffer_1_.get() + BLOCK_SZ, BLOCK_SZ)); + ASSERT_TRUE(writer->AddRawBlocks(0, random_buffer_1_.get(), BLOCK_SZ)); + ASSERT_TRUE(writer->AddRawBlocks(1, (char*)random_buffer_1_.get() + BLOCK_SZ, BLOCK_SZ)); - ASSERT_TRUE(writer.Finalize()); + ASSERT_TRUE(writer->Finalize()); SetDeviceControlName(); @@ -381,22 +390,16 @@ void CowSnapuserdTest::ReadSnapshotDeviceAndValidate() { } void CowSnapuserdTest::CreateCowDeviceWithCopyOverlap_2() { - std::string path = android::base::GetExecutableDirectory(); - cow_system_ = std::make_unique(path); - - CowOptions options; - options.compression = "gz"; - CowWriter writer(options); - - ASSERT_TRUE(writer.Initialize(cow_system_->fd)); + auto writer = CreateCowDeviceInternal(); + ASSERT_NE(writer, nullptr); - size_t num_blocks = size_ / options.block_size; + size_t num_blocks = size_ / writer->GetBlockSize(); size_t x = num_blocks; size_t blk_src_copy = 0; // Create overlapping copy operations while (1) { - ASSERT_TRUE(writer.AddCopy(blk_src_copy, blk_src_copy + 1)); + ASSERT_TRUE(writer->AddCopy(blk_src_copy, blk_src_copy + 1)); x -= 1; if (x == 1) { break; @@ -405,7 +408,7 @@ void CowSnapuserdTest::CreateCowDeviceWithCopyOverlap_2() { } // Flush operations - ASSERT_TRUE(writer.Finalize()); + ASSERT_TRUE(writer->Finalize()); // Construct the buffer required for validation orig_buffer_ = std::make_unique(total_base_size_); @@ -433,22 +436,16 @@ void CowSnapuserdTest::CreateCowDeviceWithCopyOverlap_2() { } void CowSnapuserdTest::CreateCowDeviceWithCopyOverlap_1() { - std::string path = android::base::GetExecutableDirectory(); - cow_system_ = std::make_unique(path); + auto writer = CreateCowDeviceInternal(); + ASSERT_NE(writer, nullptr); - CowOptions options; - options.compression = "gz"; - CowWriter writer(options); - - ASSERT_TRUE(writer.Initialize(cow_system_->fd)); - - size_t num_blocks = size_ / options.block_size; + size_t num_blocks = size_ / writer->GetBlockSize(); size_t x = num_blocks; size_t blk_src_copy = num_blocks - 1; // Create overlapping copy operations while (1) { - ASSERT_TRUE(writer.AddCopy(blk_src_copy + 1, blk_src_copy)); + ASSERT_TRUE(writer->AddCopy(blk_src_copy + 1, blk_src_copy)); x -= 1; if (x == 0) { ASSERT_EQ(blk_src_copy, 0); @@ -458,7 +455,7 @@ void CowSnapuserdTest::CreateCowDeviceWithCopyOverlap_1() { } // Flush operations - ASSERT_TRUE(writer.Finalize()); + ASSERT_TRUE(writer->Finalize()); // Construct the buffer required for validation orig_buffer_ = std::make_unique(total_base_size_); @@ -468,10 +465,11 @@ void CowSnapuserdTest::CreateCowDeviceWithCopyOverlap_1() { true); // Merged operations - ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), options.block_size, 0), + ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), writer->GetBlockSize(), + 0), true); ASSERT_EQ(android::base::ReadFullyAtOffset( - base_fd_, (char*)orig_buffer_.get() + options.block_size, size_, 0), + base_fd_, (char*)orig_buffer_.get() + writer->GetBlockSize(), size_, 0), true); } @@ -479,8 +477,8 @@ void CowSnapuserdTest::CreateCowDeviceOrderedOpsInverted() { unique_fd rnd_fd; loff_t offset = 0; - std::string path = android::base::GetExecutableDirectory(); - cow_system_ = std::make_unique(path); + auto writer = CreateCowDeviceInternal(); + ASSERT_NE(writer, nullptr); rnd_fd.reset(open("/dev/random", O_RDONLY)); ASSERT_TRUE(rnd_fd > 0); @@ -495,13 +493,7 @@ void CowSnapuserdTest::CreateCowDeviceOrderedOpsInverted() { offset += 1_MiB; } - CowOptions options; - options.compression = "gz"; - CowWriter writer(options); - - ASSERT_TRUE(writer.Initialize(cow_system_->fd)); - - size_t num_blocks = size_ / options.block_size; + size_t num_blocks = size_ / writer->GetBlockSize(); size_t blk_end_copy = num_blocks * 3; size_t source_blk = num_blocks - 1; size_t blk_src_copy = blk_end_copy - 1; @@ -509,7 +501,7 @@ void CowSnapuserdTest::CreateCowDeviceOrderedOpsInverted() { size_t x = num_blocks; while (1) { - ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy)); + ASSERT_TRUE(writer->AddCopy(source_blk, blk_src_copy)); x -= 1; if (x == 0) { break; @@ -519,12 +511,12 @@ void CowSnapuserdTest::CreateCowDeviceOrderedOpsInverted() { } for (size_t i = num_blocks; i > 0; i--) { - ASSERT_TRUE(writer.AddXorBlocks(num_blocks + i - 1, - &random_buffer_1_.get()[options.block_size * (i - 1)], - options.block_size, 2 * num_blocks + i - 1, xor_offset)); + ASSERT_TRUE(writer->AddXorBlocks( + num_blocks + i - 1, &random_buffer_1_.get()[writer->GetBlockSize() * (i - 1)], + writer->GetBlockSize(), 2 * num_blocks + i - 1, xor_offset)); } // Flush operations - ASSERT_TRUE(writer.Finalize()); + ASSERT_TRUE(writer->Finalize()); // Construct the buffer required for validation orig_buffer_ = std::make_unique(total_base_size_); // Read the entire base device @@ -542,8 +534,8 @@ void CowSnapuserdTest::CreateCowDeviceOrderedOps() { unique_fd rnd_fd; loff_t offset = 0; - std::string path = android::base::GetExecutableDirectory(); - cow_system_ = std::make_unique(path); + auto writer = CreateCowDeviceInternal(); + ASSERT_NE(writer, nullptr); rnd_fd.reset(open("/dev/random", O_RDONLY)); ASSERT_TRUE(rnd_fd > 0); @@ -559,20 +551,14 @@ void CowSnapuserdTest::CreateCowDeviceOrderedOps() { } memset(random_buffer_1_.get(), 0, size_); - CowOptions options; - options.compression = "gz"; - CowWriter writer(options); - - ASSERT_TRUE(writer.Initialize(cow_system_->fd)); - - size_t num_blocks = size_ / options.block_size; + size_t num_blocks = size_ / writer->GetBlockSize(); size_t x = num_blocks; size_t source_blk = 0; size_t blk_src_copy = 2 * num_blocks; uint16_t xor_offset = 5; while (1) { - ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy)); + ASSERT_TRUE(writer->AddCopy(source_blk, blk_src_copy)); x -= 1; if (x == 0) { @@ -582,10 +568,10 @@ void CowSnapuserdTest::CreateCowDeviceOrderedOps() { blk_src_copy += 1; } - ASSERT_TRUE(writer.AddXorBlocks(num_blocks, random_buffer_1_.get(), size_, 2 * num_blocks, - xor_offset)); + ASSERT_TRUE(writer->AddXorBlocks(num_blocks, random_buffer_1_.get(), size_, 2 * num_blocks, + xor_offset)); // Flush operations - ASSERT_TRUE(writer.Finalize()); + ASSERT_TRUE(writer->Finalize()); // Construct the buffer required for validation orig_buffer_ = std::make_unique(total_base_size_); // Read the entire base device @@ -603,8 +589,8 @@ void CowSnapuserdTest::CreateCowDevice() { unique_fd rnd_fd; loff_t offset = 0; - std::string path = android::base::GetExecutableDirectory(); - cow_system_ = std::make_unique(path); + auto writer = CreateCowDeviceInternal(); + ASSERT_NE(writer, nullptr); rnd_fd.reset(open("/dev/random", O_RDONLY)); ASSERT_TRUE(rnd_fd > 0); @@ -619,13 +605,7 @@ void CowSnapuserdTest::CreateCowDevice() { offset += 1_MiB; } - CowOptions options; - options.compression = "gz"; - CowWriter writer(options); - - ASSERT_TRUE(writer.Initialize(cow_system_->fd)); - - size_t num_blocks = size_ / options.block_size; + size_t num_blocks = size_ / writer->GetBlockSize(); size_t blk_end_copy = num_blocks * 2; size_t source_blk = num_blocks - 1; size_t blk_src_copy = blk_end_copy - 1; @@ -639,11 +619,11 @@ void CowSnapuserdTest::CreateCowDevice() { for (int i = 0; i < num_blocks; i++) { sequence[num_blocks + i] = 5 * num_blocks - 1 - i; } - ASSERT_TRUE(writer.AddSequenceData(2 * num_blocks, sequence)); + ASSERT_TRUE(writer->AddSequenceData(2 * num_blocks, sequence)); size_t x = num_blocks; while (1) { - ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy)); + ASSERT_TRUE(writer->AddCopy(source_blk, blk_src_copy)); x -= 1; if (x == 0) { break; @@ -655,24 +635,24 @@ void CowSnapuserdTest::CreateCowDevice() { source_blk = num_blocks; blk_src_copy = blk_end_copy; - ASSERT_TRUE(writer.AddRawBlocks(source_blk, random_buffer_1_.get(), size_)); + ASSERT_TRUE(writer->AddRawBlocks(source_blk, random_buffer_1_.get(), size_)); size_t blk_zero_copy_start = source_blk + num_blocks; size_t blk_zero_copy_end = blk_zero_copy_start + num_blocks; - ASSERT_TRUE(writer.AddZeroBlocks(blk_zero_copy_start, num_blocks)); + ASSERT_TRUE(writer->AddZeroBlocks(blk_zero_copy_start, num_blocks)); size_t blk_random2_replace_start = blk_zero_copy_end; - ASSERT_TRUE(writer.AddRawBlocks(blk_random2_replace_start, random_buffer_1_.get(), size_)); + ASSERT_TRUE(writer->AddRawBlocks(blk_random2_replace_start, random_buffer_1_.get(), size_)); size_t blk_xor_start = blk_random2_replace_start + num_blocks; size_t xor_offset = BLOCK_SZ / 2; - ASSERT_TRUE(writer.AddXorBlocks(blk_xor_start, random_buffer_1_.get(), size_, num_blocks, - xor_offset)); + ASSERT_TRUE(writer->AddXorBlocks(blk_xor_start, random_buffer_1_.get(), size_, num_blocks, + xor_offset)); // Flush operations - ASSERT_TRUE(writer.Finalize()); + ASSERT_TRUE(writer->Finalize()); // Construct the buffer required for validation orig_buffer_ = std::make_unique(total_base_size_); std::string zero_buffer(size_, 0); @@ -902,29 +882,36 @@ void CowSnapuserdTest::MergeInterrupt() { ASSERT_TRUE(Merge()); } -void CowSnapuserdMetadataTest::CreateCowPartialFilledArea() { +std::unique_ptr CowSnapuserdMetadataTest::CreateCowDeviceInternal() { std::string path = android::base::GetExecutableDirectory(); cow_system_ = std::make_unique(path); CowOptions options; options.compression = "gz"; - CowWriter writer(options); - ASSERT_TRUE(writer.Initialize(cow_system_->fd)); + unique_fd fd(cow_system_->fd); + cow_system_->fd = -1; + + return CreateCowWriter(kDefaultCowVersion, options, std::move(fd)); +} + +void CowSnapuserdMetadataTest::CreateCowPartialFilledArea() { + auto writer = CreateCowDeviceInternal(); + ASSERT_NE(writer, nullptr); // Area 0 is completely filled with 256 exceptions for (int i = 0; i < 256; i++) { - ASSERT_TRUE(writer.AddCopy(i, 256 + i)); + ASSERT_TRUE(writer->AddCopy(i, 256 + i)); } // Area 1 is partially filled with 2 copy ops and 10 zero ops - ASSERT_TRUE(writer.AddCopy(500, 1000)); - ASSERT_TRUE(writer.AddCopy(501, 1001)); + ASSERT_TRUE(writer->AddCopy(500, 1000)); + ASSERT_TRUE(writer->AddCopy(501, 1001)); - ASSERT_TRUE(writer.AddZeroBlocks(300, 10)); + ASSERT_TRUE(writer->AddZeroBlocks(300, 10)); // Flush operations - ASSERT_TRUE(writer.Finalize()); + ASSERT_TRUE(writer->Finalize()); } void CowSnapuserdMetadataTest::ValidatePartialFilledArea() { @@ -956,8 +943,8 @@ void CowSnapuserdMetadataTest::CreateCowDevice() { unique_fd rnd_fd; loff_t offset = 0; - std::string path = android::base::GetExecutableDirectory(); - cow_system_ = std::make_unique(path); + auto writer = CreateCowDeviceInternal(); + ASSERT_NE(writer, nullptr); rnd_fd.reset(open("/dev/random", O_RDONLY)); ASSERT_TRUE(rnd_fd > 0); @@ -972,50 +959,44 @@ void CowSnapuserdMetadataTest::CreateCowDevice() { offset += 1_MiB; } - CowOptions options; - options.compression = "gz"; - CowWriter writer(options); - - ASSERT_TRUE(writer.Initialize(cow_system_->fd)); - - size_t num_blocks = size_ / options.block_size; + size_t num_blocks = size_ / writer->GetBlockSize(); // Overlapping region. This has to be split // into two batch operations - ASSERT_TRUE(writer.AddCopy(23, 20)); - ASSERT_TRUE(writer.AddCopy(22, 19)); - ASSERT_TRUE(writer.AddCopy(21, 18)); - ASSERT_TRUE(writer.AddCopy(20, 17)); - ASSERT_TRUE(writer.AddCopy(19, 16)); - ASSERT_TRUE(writer.AddCopy(18, 15)); + ASSERT_TRUE(writer->AddCopy(23, 20)); + ASSERT_TRUE(writer->AddCopy(22, 19)); + ASSERT_TRUE(writer->AddCopy(21, 18)); + ASSERT_TRUE(writer->AddCopy(20, 17)); + ASSERT_TRUE(writer->AddCopy(19, 16)); + ASSERT_TRUE(writer->AddCopy(18, 15)); // Contiguous region but blocks in ascending order // Daemon has to ensure that these blocks are merged // in a batch - ASSERT_TRUE(writer.AddCopy(50, 75)); - ASSERT_TRUE(writer.AddCopy(51, 76)); - ASSERT_TRUE(writer.AddCopy(52, 77)); - ASSERT_TRUE(writer.AddCopy(53, 78)); + ASSERT_TRUE(writer->AddCopy(50, 75)); + ASSERT_TRUE(writer->AddCopy(51, 76)); + ASSERT_TRUE(writer->AddCopy(52, 77)); + ASSERT_TRUE(writer->AddCopy(53, 78)); // Dis-contiguous region - ASSERT_TRUE(writer.AddCopy(110, 130)); - ASSERT_TRUE(writer.AddCopy(105, 125)); - ASSERT_TRUE(writer.AddCopy(100, 120)); + ASSERT_TRUE(writer->AddCopy(110, 130)); + ASSERT_TRUE(writer->AddCopy(105, 125)); + ASSERT_TRUE(writer->AddCopy(100, 120)); // Overlap - ASSERT_TRUE(writer.AddCopy(25, 30)); - ASSERT_TRUE(writer.AddCopy(30, 31)); + ASSERT_TRUE(writer->AddCopy(25, 30)); + ASSERT_TRUE(writer->AddCopy(30, 31)); size_t source_blk = num_blocks; - ASSERT_TRUE(writer.AddRawBlocks(source_blk, random_buffer_1_.get(), size_)); + ASSERT_TRUE(writer->AddRawBlocks(source_blk, random_buffer_1_.get(), size_)); size_t blk_zero_copy_start = source_blk + num_blocks; - ASSERT_TRUE(writer.AddZeroBlocks(blk_zero_copy_start, num_blocks)); + ASSERT_TRUE(writer->AddZeroBlocks(blk_zero_copy_start, num_blocks)); // Flush operations - ASSERT_TRUE(writer.Finalize()); + ASSERT_TRUE(writer->Finalize()); } void CowSnapuserdMetadataTest::InitMetadata() { 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 57f9e7ac1a03..efe0c1443215 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -125,6 +125,7 @@ class SnapuserdTest : public ::testing::Test { void SimulateDaemonRestart(); + std::unique_ptr CreateCowDeviceInternal(); void CreateCowDevice(); void CreateCowDeviceOrderedOps(); void CreateCowDeviceOrderedOpsInverted(); @@ -277,23 +278,30 @@ void SnapuserdTest::ReadSnapshotDeviceAndValidate() { ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 4), size_), 0); } -void SnapuserdTest::CreateCowDeviceWithCopyOverlap_2() { +std::unique_ptr SnapuserdTest::CreateCowDeviceInternal() { std::string path = android::base::GetExecutableDirectory(); cow_system_ = std::make_unique(path); CowOptions options; options.compression = "gz"; - CowWriter writer(options); - ASSERT_TRUE(writer.Initialize(cow_system_->fd)); + unique_fd fd(cow_system_->fd); + cow_system_->fd = -1; + + return CreateCowWriter(kDefaultCowVersion, options, std::move(fd)); +} + +void SnapuserdTest::CreateCowDeviceWithCopyOverlap_2() { + auto writer = CreateCowDeviceInternal(); + ASSERT_NE(writer, nullptr); - size_t num_blocks = size_ / options.block_size; + size_t num_blocks = size_ / writer->GetBlockSize(); size_t x = num_blocks; size_t blk_src_copy = 0; // Create overlapping copy operations while (1) { - ASSERT_TRUE(writer.AddCopy(blk_src_copy, blk_src_copy + 1)); + ASSERT_TRUE(writer->AddCopy(blk_src_copy, blk_src_copy + 1)); x -= 1; if (x == 1) { break; @@ -302,7 +310,7 @@ void SnapuserdTest::CreateCowDeviceWithCopyOverlap_2() { } // Flush operations - ASSERT_TRUE(writer.Finalize()); + ASSERT_TRUE(writer->Finalize()); // Construct the buffer required for validation orig_buffer_ = std::make_unique(total_base_size_); @@ -330,22 +338,16 @@ void SnapuserdTest::CreateCowDeviceWithCopyOverlap_2() { } void SnapuserdTest::CreateCowDeviceWithCopyOverlap_1() { - std::string path = android::base::GetExecutableDirectory(); - cow_system_ = std::make_unique(path); + auto writer = CreateCowDeviceInternal(); + ASSERT_NE(writer, nullptr); - CowOptions options; - options.compression = "gz"; - CowWriter writer(options); - - ASSERT_TRUE(writer.Initialize(cow_system_->fd)); - - size_t num_blocks = size_ / options.block_size; + size_t num_blocks = size_ / writer->GetBlockSize(); size_t x = num_blocks; size_t blk_src_copy = num_blocks - 1; // Create overlapping copy operations while (1) { - ASSERT_TRUE(writer.AddCopy(blk_src_copy + 1, blk_src_copy)); + ASSERT_TRUE(writer->AddCopy(blk_src_copy + 1, blk_src_copy)); x -= 1; if (x == 0) { ASSERT_EQ(blk_src_copy, 0); @@ -355,7 +357,7 @@ void SnapuserdTest::CreateCowDeviceWithCopyOverlap_1() { } // Flush operations - ASSERT_TRUE(writer.Finalize()); + ASSERT_TRUE(writer->Finalize()); // Construct the buffer required for validation orig_buffer_ = std::make_unique(total_base_size_); @@ -365,10 +367,11 @@ void SnapuserdTest::CreateCowDeviceWithCopyOverlap_1() { true); // Merged operations - ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), options.block_size, 0), + ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), writer->GetBlockSize(), + 0), true); ASSERT_EQ(android::base::ReadFullyAtOffset( - base_fd_, (char*)orig_buffer_.get() + options.block_size, size_, 0), + base_fd_, (char*)orig_buffer_.get() + writer->GetBlockSize(), size_, 0), true); } @@ -376,8 +379,8 @@ void SnapuserdTest::CreateCowDeviceOrderedOpsInverted() { unique_fd rnd_fd; loff_t offset = 0; - std::string path = android::base::GetExecutableDirectory(); - cow_system_ = std::make_unique(path); + auto writer = CreateCowDeviceInternal(); + ASSERT_NE(writer, nullptr); rnd_fd.reset(open("/dev/random", O_RDONLY)); ASSERT_TRUE(rnd_fd > 0); @@ -392,13 +395,7 @@ void SnapuserdTest::CreateCowDeviceOrderedOpsInverted() { offset += 1_MiB; } - CowOptions options; - options.compression = "gz"; - CowWriter writer(options); - - ASSERT_TRUE(writer.Initialize(cow_system_->fd)); - - size_t num_blocks = size_ / options.block_size; + size_t num_blocks = size_ / writer->GetBlockSize(); size_t blk_end_copy = num_blocks * 3; size_t source_blk = num_blocks - 1; size_t blk_src_copy = blk_end_copy - 1; @@ -406,7 +403,7 @@ void SnapuserdTest::CreateCowDeviceOrderedOpsInverted() { size_t x = num_blocks; while (1) { - ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy)); + ASSERT_TRUE(writer->AddCopy(source_blk, blk_src_copy)); x -= 1; if (x == 0) { break; @@ -416,12 +413,12 @@ void SnapuserdTest::CreateCowDeviceOrderedOpsInverted() { } for (size_t i = num_blocks; i > 0; i--) { - ASSERT_TRUE(writer.AddXorBlocks(num_blocks + i - 1, - &random_buffer_1_.get()[options.block_size * (i - 1)], - options.block_size, 2 * num_blocks + i - 1, xor_offset)); + ASSERT_TRUE(writer->AddXorBlocks( + num_blocks + i - 1, &random_buffer_1_.get()[writer->GetBlockSize() * (i - 1)], + writer->GetBlockSize(), 2 * num_blocks + i - 1, xor_offset)); } // Flush operations - ASSERT_TRUE(writer.Finalize()); + ASSERT_TRUE(writer->Finalize()); // Construct the buffer required for validation orig_buffer_ = std::make_unique(total_base_size_); // Read the entire base device @@ -439,8 +436,8 @@ void SnapuserdTest::CreateCowDeviceOrderedOps() { unique_fd rnd_fd; loff_t offset = 0; - std::string path = android::base::GetExecutableDirectory(); - cow_system_ = std::make_unique(path); + auto writer = CreateCowDeviceInternal(); + ASSERT_NE(writer, nullptr); rnd_fd.reset(open("/dev/random", O_RDONLY)); ASSERT_TRUE(rnd_fd > 0); @@ -456,20 +453,14 @@ void SnapuserdTest::CreateCowDeviceOrderedOps() { } memset(random_buffer_1_.get(), 0, size_); - CowOptions options; - options.compression = "gz"; - CowWriter writer(options); - - ASSERT_TRUE(writer.Initialize(cow_system_->fd)); - - size_t num_blocks = size_ / options.block_size; + size_t num_blocks = size_ / writer->GetBlockSize(); size_t x = num_blocks; size_t source_blk = 0; size_t blk_src_copy = 2 * num_blocks; uint16_t xor_offset = 5; while (1) { - ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy)); + ASSERT_TRUE(writer->AddCopy(source_blk, blk_src_copy)); x -= 1; if (x == 0) { @@ -479,10 +470,10 @@ void SnapuserdTest::CreateCowDeviceOrderedOps() { blk_src_copy += 1; } - ASSERT_TRUE(writer.AddXorBlocks(num_blocks, random_buffer_1_.get(), size_, 2 * num_blocks, - xor_offset)); + ASSERT_TRUE(writer->AddXorBlocks(num_blocks, random_buffer_1_.get(), size_, 2 * num_blocks, + xor_offset)); // Flush operations - ASSERT_TRUE(writer.Finalize()); + ASSERT_TRUE(writer->Finalize()); // Construct the buffer required for validation orig_buffer_ = std::make_unique(total_base_size_); // Read the entire base device @@ -500,8 +491,8 @@ void SnapuserdTest::CreateCowDevice() { unique_fd rnd_fd; loff_t offset = 0; - std::string path = android::base::GetExecutableDirectory(); - cow_system_ = std::make_unique(path); + auto writer = CreateCowDeviceInternal(); + ASSERT_NE(writer, nullptr); rnd_fd.reset(open("/dev/random", O_RDONLY)); ASSERT_TRUE(rnd_fd > 0); @@ -516,13 +507,7 @@ void SnapuserdTest::CreateCowDevice() { offset += 1_MiB; } - CowOptions options; - options.compression = "gz"; - CowWriter writer(options); - - ASSERT_TRUE(writer.Initialize(cow_system_->fd)); - - size_t num_blocks = size_ / options.block_size; + size_t num_blocks = size_ / writer->GetBlockSize(); size_t blk_end_copy = num_blocks * 2; size_t source_blk = num_blocks - 1; size_t blk_src_copy = blk_end_copy - 1; @@ -536,11 +521,11 @@ void SnapuserdTest::CreateCowDevice() { for (int i = 0; i < num_blocks; i++) { sequence[num_blocks + i] = 5 * num_blocks - 1 - i; } - ASSERT_TRUE(writer.AddSequenceData(2 * num_blocks, sequence)); + ASSERT_TRUE(writer->AddSequenceData(2 * num_blocks, sequence)); size_t x = num_blocks; while (1) { - ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy)); + ASSERT_TRUE(writer->AddCopy(source_blk, blk_src_copy)); x -= 1; if (x == 0) { break; @@ -552,24 +537,24 @@ void SnapuserdTest::CreateCowDevice() { source_blk = num_blocks; blk_src_copy = blk_end_copy; - ASSERT_TRUE(writer.AddRawBlocks(source_blk, random_buffer_1_.get(), size_)); + ASSERT_TRUE(writer->AddRawBlocks(source_blk, random_buffer_1_.get(), size_)); size_t blk_zero_copy_start = source_blk + num_blocks; size_t blk_zero_copy_end = blk_zero_copy_start + num_blocks; - ASSERT_TRUE(writer.AddZeroBlocks(blk_zero_copy_start, num_blocks)); + ASSERT_TRUE(writer->AddZeroBlocks(blk_zero_copy_start, num_blocks)); size_t blk_random2_replace_start = blk_zero_copy_end; - ASSERT_TRUE(writer.AddRawBlocks(blk_random2_replace_start, random_buffer_1_.get(), size_)); + ASSERT_TRUE(writer->AddRawBlocks(blk_random2_replace_start, random_buffer_1_.get(), size_)); size_t blk_xor_start = blk_random2_replace_start + num_blocks; size_t xor_offset = BLOCK_SZ / 2; - ASSERT_TRUE(writer.AddXorBlocks(blk_xor_start, random_buffer_1_.get(), size_, num_blocks, - xor_offset)); + ASSERT_TRUE(writer->AddXorBlocks(blk_xor_start, random_buffer_1_.get(), size_, num_blocks, + xor_offset)); // Flush operations - ASSERT_TRUE(writer.Finalize()); + ASSERT_TRUE(writer->Finalize()); // Construct the buffer required for validation orig_buffer_ = std::make_unique(total_base_size_); std::string zero_buffer(size_, 0); From 7a0611b00611512b43a9739b7ca4a2c1e74c6db0 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 8 Jun 2023 20:54:49 +0000 Subject: [PATCH 0103/1487] Remove write permission from file mode of top-level user dirs Due to the work done for b/156305599 ("Ensure no process except vold can create directories like /data/system_ce/0"), the SELinux policy now enforces that vold is the only process that can write to directories that contain per-user encrypted subdirectories. This is essential to prevent bugs where directories that are supposed to be encrypted get created too early so are not actually encrypted as intended. However, this only works when SELinux is in enforcing mode. When SELinux is in permissive mode, only DAC is enforced, and the file modes allow other processes to write to many of these directories. That allows system_server to break things once again. Therefore, remove the write bit from the file modes so that write access is always denied to processes that don't have CAP_DAC_OVERRIDE. This is not as strong a restriction as the SELinux policy, which still applies independently, but it does keep out system_server by itself. Also remove the sticky bit from /data/misc_ce and /data/misc_de, since there is no reason for it. (It probably was originally copied from /data/misc, which might need it. But misc_{ce,de} don't need it.) Bug: 285239971 Test: Booted Cuttlefish Change-Id: I1213a4d18c5f851acf213d786400d79d73777ed0 --- rootdir/init.rc | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 0ee85c7412b9..53443685263a 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -919,15 +919,22 @@ on post-fs-data # encryption policies apply recursively. These directories should never # contain any subdirectories other than the per-user ones. /data/media/obb # is an exception that exists for legacy reasons. - mkdir /data/media 0770 media_rw media_rw encryption=None - mkdir /data/misc_ce 01771 system misc encryption=None - mkdir /data/misc_de 01771 system misc encryption=None - mkdir /data/system_ce 0770 system system encryption=None - mkdir /data/system_de 0770 system system encryption=None - mkdir /data/user 0711 system system encryption=None - mkdir /data/user_de 0711 system system encryption=None - mkdir /data/vendor_ce 0771 root root encryption=None - mkdir /data/vendor_de 0771 root root encryption=None + # + # Don't use any write mode bits (0222) for any of these directories, since + # the only process that should write to them directly is vold (since it + # needs to set up file-based encryption on the subdirectories), which runs + # as root with CAP_DAC_OVERRIDE. This is also fully enforced via the + # SELinux policy. But we also set the DAC file modes accordingly, to try to + # minimize differences in behavior if SELinux is set to permissive mode. + mkdir /data/media 0550 media_rw media_rw encryption=None + mkdir /data/misc_ce 0551 system misc encryption=None + mkdir /data/misc_de 0551 system misc encryption=None + mkdir /data/system_ce 0550 system system encryption=None + mkdir /data/system_de 0550 system system encryption=None + mkdir /data/user 0511 system system encryption=None + mkdir /data/user_de 0511 system system encryption=None + mkdir /data/vendor_ce 0551 root root encryption=None + mkdir /data/vendor_de 0551 root root encryption=None # Set the casefold flag on /data/media. For upgrades, a restorecon can be # needed first to relabel the directory from media_rw_data_file. From 0d277d777f290729fd9708b88f7ed57f0e0e49eb Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Fri, 9 Jun 2023 09:52:49 +0900 Subject: [PATCH 0104/1487] init: non-crashing service can restart immediately This CL allows restart_period to be set to a value shorter than 5s. Previously this was prohibited to rate limit crashing services. That behavior is considered to be a bit too conservative because some services don't crash, but exit deliverately. adbd is the motivating example. When adb root or adb unroot is requested, it changes its mode of operation (via sysprop), exits itself, and restarts (by init) to enter into the mode. However, due to the 5s delay, the mode change can complete no earlier than 5 seconds after adbd was started last time. This can slow the mode change when it is requested right after the boot. With this CL, restart_period can be set to a value smaller than 5. And services like adbd can make use of it. However, in ordef to rate limit crashing service, the default is enforced if the service was crashed last time. In addition, such intended restart is not counted as crashes when monitoring successive crashes during booting. Bug: 286061817 Test: /packages/modules/Virtualization/vm/vm_shell.sh start-microdroid \ --auto-connect -- --protected * with this change: within 2s * without this change: over 6s Change-Id: I1b3f0c92d349e8c8760821cf50fb69997b67b242 --- init/README.md | 13 ++++++++----- init/service.cpp | 4 +++- init/service.h | 17 +++++++++++++++-- init/service_parser.cpp | 4 ++-- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/init/README.md b/init/README.md index 6bdff4afead7..5fced19b076f 100644 --- a/init/README.md +++ b/init/README.md @@ -344,11 +344,14 @@ runs the service. intended to be used with the `exec_start` builtin for any must-have checks during boot. `restart_period ` -> If a non-oneshot service exits, it will be restarted at its start time plus - this period. It defaults to 5s to rate limit crashing services. - This can be increased for services that are meant to run periodically. For - example, it may be set to 3600 to indicate that the service should run every hour - or 86400 to indicate that the service should run every day. +> If a non-oneshot service exits, it will be restarted at its previous start time plus this period. + The default value is 5s. This can be used to implement periodic services together with the + `timeout_period` command below. For example, it may be set to 3600 to indicate that the service + should run every hour or 86400 to indicate that the service should run every day. This can be set + to a value shorter than 5s for example 0, but the minimum 5s delay is enforced if the restart was + due to a crash. This is to rate limit persistentally crashing services. In other words, + `` smaller than 5 is respected only when the service exits deliverately and successfully + (i.e. by calling exit(0)). `rlimit ` > This applies the given rlimit to the service. rlimits are inherited by child diff --git a/init/service.cpp b/init/service.cpp index c1520818a807..29457084b05f 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -308,6 +308,7 @@ void Service::Reap(const siginfo_t& siginfo) { pid_ = 0; flags_ &= (~SVC_RUNNING); start_order_ = 0; + was_last_exit_ok_ = siginfo.si_code == CLD_EXITED && siginfo.si_status == 0; // Oneshot processes go into the disabled state on exit, // except when manually restarted. @@ -361,7 +362,8 @@ void Service::Reap(const siginfo_t& siginfo) { // If we crash > 4 times in 'fatal_crash_window_' minutes or before boot_completed, // reboot into bootloader or set crashing property boot_clock::time_point now = boot_clock::now(); - if (((flags_ & SVC_CRITICAL) || is_process_updatable) && !(flags_ & SVC_RESTART)) { + if (((flags_ & SVC_CRITICAL) || is_process_updatable) && !(flags_ & SVC_RESTART) && + !was_last_exit_ok_) { bool boot_completed = GetBoolProperty("sys.boot_completed", false); if (now < time_crashed_ + fatal_crash_window_ || !boot_completed) { if (++crash_count_ > 4) { diff --git a/init/service.h b/init/service.h index ce7c0daf2a98..b858eeff03d6 100644 --- a/init/service.h +++ b/init/service.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -115,6 +116,7 @@ class Service { pid_t pid() const { return pid_; } android::base::boot_clock::time_point time_started() const { return time_started_; } int crash_count() const { return crash_count_; } + int was_last_exit_ok() const { return was_last_exit_ok_; } uid_t uid() const { return proc_attr_.uid(); } gid_t gid() const { return proc_attr_.gid; } int namespace_flags() const { return namespaces_.flags; } @@ -130,7 +132,15 @@ class Service { bool process_cgroup_empty() const { return process_cgroup_empty_; } unsigned long start_order() const { return start_order_; } void set_sigstop(bool value) { sigstop_ = value; } - std::chrono::seconds restart_period() const { return restart_period_; } + std::chrono::seconds restart_period() const { + // If the service exited abnormally or due to timeout, late limit the restart even if + // restart_period is set to a very short value. + // If not, i.e. restart after a deliberate and successful exit, respect the period. + if (!was_last_exit_ok_) { + return std::max(restart_period_, default_restart_period_); + } + return restart_period_; + } std::optional timeout_period() const { return timeout_period_; } const std::vector& args() const { return args_; } bool is_updatable() const { return updatable_; } @@ -172,6 +182,8 @@ class Service { bool upgraded_mte_ = false; // whether we upgraded async MTE -> sync MTE before std::chrono::minutes fatal_crash_window_ = 4min; // fatal() when more than 4 crashes in it std::optional fatal_reboot_target_; // reboot target of fatal handler + bool was_last_exit_ok_ = + true; // true if the service never exited, or exited with status code 0 std::optional capabilities_; ProcessAttributes proc_attr_; @@ -214,7 +226,8 @@ class Service { bool sigstop_ = false; - std::chrono::seconds restart_period_ = 5s; + const std::chrono::seconds default_restart_period_ = 5s; + std::chrono::seconds restart_period_ = default_restart_period_; std::optional timeout_period_; bool updatable_ = false; diff --git a/init/service_parser.cpp b/init/service_parser.cpp index d46e1f7544bd..a1b2cc55f472 100644 --- a/init/service_parser.cpp +++ b/init/service_parser.cpp @@ -370,8 +370,8 @@ Result ServiceParser::ParseRebootOnFailure(std::vector&& args Result ServiceParser::ParseRestartPeriod(std::vector&& args) { int period; - if (!ParseInt(args[1], &period, 5)) { - return Error() << "restart_period value must be an integer >= 5"; + if (!ParseInt(args[1], &period, 0)) { + return Error() << "restart_period value must be an integer >= 0"; } service_->restart_period_ = std::chrono::seconds(period); return {}; From 9d2fb9ca3cf50de931666dbd4783652f45cf2a5b Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 9 Jun 2023 18:52:22 +0000 Subject: [PATCH 0105/1487] fastboot: Introduce FASTBOOT_DEVICE alias for ANDROID_SERIAL environment variable The ANDROID_SERIAL env is useful for managing multiple directly connected devices at one time. Unfortunately for network connected devices, its harder to use. This is because both adb and fastboot use the same ANDROID_SERIAL environment value to identify the device to use, and while that one value works for directly connected devices, when using network connected devices, the fastboot and adb port numbers may differ for the same device. So if I set: `ANDROID_SERIAL="tcp:127.0.0.1:44403"` fastboot will work, but when I type `adb shell`, I'll get: adb: device 'tcp:127.0.0.1:44403' not found As `adb devices` outputs: List of devices attached localhost:36697 device To resolve this, we need separate environment variables, so introduce a FASTBOOT_DEVICE variable for fastboot. If FASTBOOT_DEVICE is set, it will use that, and if not it will fall back to the ANDROID_SERIAL if it is set. Using an explicit -s argument will still override both. Change-Id: Icd7db6f29e51ed2decd219e35537f6ed98d698b8 Signed-off-by: John Stultz --- fastboot/fastboot.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 799406581143..a1664a4b816b 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -2231,7 +2231,9 @@ int FastBootTool::Main(int argc, char* argv[]) { {"version", no_argument, 0, 0}, {0, 0, 0, 0}}; - serial = getenv("ANDROID_SERIAL"); + serial = getenv("FASTBOOT_DEVICE"); + if (!serial) + serial = getenv("ANDROID_SERIAL"); int c; while ((c = getopt_long(argc, argv, "a::hls:S:vw", longopts, &longindex)) != -1) { From 214f37c2493f005231ff32e9982c2b831de11d38 Mon Sep 17 00:00:00 2001 From: Biswapriyo Nath Date: Sat, 10 Jun 2023 20:03:31 +0530 Subject: [PATCH 0106/1487] fastboot: Add header that declares std::function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the following compiler error with gcc fastboot_driver.h:51:10: error: ‘function’ in namespace ‘std’ does not name a template type Change-Id: I3a4d9b48bfdc2c76e443e2efe1761ec9503c6dc5 --- fastboot/fastboot_driver.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h index 3d6c7b017c3c..6ac26ce31f13 100644 --- a/fastboot/fastboot_driver.h +++ b/fastboot/fastboot_driver.h @@ -28,6 +28,7 @@ #pragma once #include #include +#include #include #include #include From 816480b56ec0b96c76fa9145a0c092db0ba3b37e Mon Sep 17 00:00:00 2001 From: Biswapriyo Nath Date: Tue, 13 Jun 2023 00:28:14 +0530 Subject: [PATCH 0107/1487] fastboot: Include header for ostream_iterator and istream_iterator This fixes the following compiler errors with gcc storage.cpp:45:20: error: 'ostream_iterator' is not a member of 'std' storage.cpp:50:10: error: 'istream_iterator' is not a member of 'std' Change-Id: I570e332d100bb18e445644a9d57dc14d80f104b5 --- fastboot/storage.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fastboot/storage.cpp b/fastboot/storage.cpp index dc733b99464e..629ebc88eff7 100644 --- a/fastboot/storage.cpp +++ b/fastboot/storage.cpp @@ -18,6 +18,7 @@ #include #include +#include #include "storage.h" #include "util.h" @@ -62,4 +63,4 @@ FileLock ConnectedDevicesStorage::Lock() const { LOG(FATAL) << "Cannot create directory: " << home_fastboot_path_; } return FileLock(devices_lock_path_); -} \ No newline at end of file +} From 3dc7fcc0b69b20eb6fb34fdf36908313f2cf811e Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 13 Jun 2023 14:53:32 -0700 Subject: [PATCH 0108/1487] Removing duplicate CollectImages() images are being flashed twice, because of an additional collectImages. This is resulting in a ~50% increase in flashing time Test: fastboot flashall -w Change-Id: I6c271e1e1456cd789f37ebd67cefd221cabc6e7a --- fastboot/fastboot.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 799406581143..fb0e18b6f36f 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1780,7 +1780,6 @@ void FlashAllTool::Flash() { } DetermineSlot(); - CollectImages(); CancelSnapshotIfNeeded(); From 32e1c70f275991ec7fe4d4a2d6e3eeba2a172540 Mon Sep 17 00:00:00 2001 From: Subrahmanya Manikanta Venkateswarlu Bhamidipati Kameswara Sri Date: Tue, 13 Jun 2023 17:37:29 +0000 Subject: [PATCH 0109/1487] Check AServiceManager_isDeclared before AServiceManager_getService Call AServiceManager_isDeclared before calling AServiceManager_getService to avoid the waiting time when aidl service is not available. Bug: 286969060 Test: run VtsHalGatekeeperTarget Change-Id: I7d652a546cb810a601338a68950f01d065aea7a5 --- gatekeeperd/gatekeeperd.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp index 7987167662dc..bdfb7f6f7f1f 100644 --- a/gatekeeperd/gatekeeperd.cpp +++ b/gatekeeperd/gatekeeperd.cpp @@ -63,9 +63,13 @@ constexpr const char gatekeeperServiceName[] = "android.hardware.gatekeeper.IGat GateKeeperProxy::GateKeeperProxy() { clear_state_if_needed_done = false; - hw_device = IGatekeeper::getService(); - ::ndk::SpAIBinder ks2Binder(AServiceManager_getService(gatekeeperServiceName)); - aidl_hw_device = AidlIGatekeeper::fromBinder(ks2Binder); + if (AServiceManager_isDeclared(gatekeeperServiceName)) { + ::ndk::SpAIBinder ks2Binder(AServiceManager_waitForService(gatekeeperServiceName)); + aidl_hw_device = AidlIGatekeeper::fromBinder(ks2Binder); + } + if (!aidl_hw_device) { + hw_device = IGatekeeper::getService(); + } is_running_gsi = android::base::GetBoolProperty(android::gsi::kGsiBootedProp, false); if (!aidl_hw_device && !hw_device) { From 94ef7122d663067bbdd841d0ce13054d264ec0cc Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Wed, 7 Jun 2023 23:58:19 +0100 Subject: [PATCH 0110/1487] Treat Microdroid as OS with monolithic sepolicy Bug: 285855150 Test: atest MicrodroidTestApp Change-Id: Idfda3044716a021888017adef801ef67775a3eda --- init/selinux.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/init/selinux.cpp b/init/selinux.cpp index 907eb80e31c0..a9365323362f 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -300,6 +300,8 @@ bool GetVendorMappingVersion(std::string* plat_vers) { } constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil"; +constexpr const char kMicrodroidPrecompiledSepolicy[] = + "/system/etc/selinux/microdroid_precompiled_sepolicy"; bool IsSplitPolicyDevice() { return access(plat_policy_cil_file, R_OK) != -1; @@ -497,14 +499,19 @@ bool OpenSplitPolicy(PolicyFile* policy_file) { bool OpenMonolithicPolicy(PolicyFile* policy_file) { static constexpr char kSepolicyFile[] = "/sepolicy"; - - LOG(VERBOSE) << "Opening SELinux policy from monolithic file"; - policy_file->fd.reset(open(kSepolicyFile, O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); + // In Microdroid the precompiled sepolicy is located on /system, since there is no vendor code. + // TODO(b/287206497): refactor once we start conditionally compiling init for Microdroid. + std::string monolithic_policy_file = access(kMicrodroidPrecompiledSepolicy, R_OK) == 0 + ? kMicrodroidPrecompiledSepolicy + : kSepolicyFile; + + LOG(INFO) << "Opening SELinux policy from monolithic file " << monolithic_policy_file; + policy_file->fd.reset(open(monolithic_policy_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); if (policy_file->fd < 0) { PLOG(ERROR) << "Failed to open monolithic SELinux policy"; return false; } - policy_file->path = kSepolicyFile; + policy_file->path = monolithic_policy_file; return true; } From 1779dcca32e6c84a0b81454f5fe647cfb5295ccb Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 13 Jun 2023 10:28:40 -0700 Subject: [PATCH 0111/1487] snapuserd: Create snapuserd_readahead.h. This moves ReadAhead out of snapuserd_core.h so it's easier to find. Bug: N/A Test: builds Change-Id: I888b87921950f2f7582b94c078e9e136f8fdd09e --- .../user-space-merge/snapuserd_core.h | 77 +----------- .../user-space-merge/snapuserd_readahead.cpp | 2 + .../user-space-merge/snapuserd_readahead.h | 112 ++++++++++++++++++ 3 files changed, 115 insertions(+), 76 deletions(-) create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.h diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index 777aa0705b2d..79a5bc952abf 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -46,6 +46,7 @@ #include #include #include +#include "snapuserd_readahead.h" namespace android { namespace snapshot { @@ -96,82 +97,6 @@ struct MergeGroupState { : merge_state_(state), num_ios_in_progress(n_ios) {} }; -class ReadAhead { - public: - ReadAhead(const std::string& cow_device, const std::string& backing_device, - const std::string& misc_name, std::shared_ptr snapuserd); - bool RunThread(); - - private: - void InitializeRAIter(); - bool RAIterDone(); - void RAIterNext(); - void RAResetIter(uint64_t num_blocks); - const CowOperation* GetRAOpIter(); - - void InitializeBuffer(); - bool InitReader(); - bool InitializeFds(); - - void CloseFds() { backing_store_fd_ = {}; } - - bool ReadAheadIOStart(); - int PrepareNextReadAhead(uint64_t* source_offset, int* pending_ops, - std::vector& blocks, - std::vector& xor_op_vec); - bool ReconstructDataFromCow(); - void CheckOverlap(const CowOperation* cow_op); - - bool ReadAheadAsyncIO(); - bool ReapIoCompletions(int pending_ios_to_complete); - bool ReadXorData(size_t block_index, size_t xor_op_index, - std::vector& xor_op_vec); - void ProcessXorData(size_t& block_xor_index, size_t& xor_index, - std::vector& xor_op_vec, void* buffer, - loff_t& buffer_offset); - void UpdateScratchMetadata(); - - bool ReadAheadSyncIO(); - bool InitializeIouring(); - void FinalizeIouring(); - - void* read_ahead_buffer_; - void* metadata_buffer_; - - std::unique_ptr cowop_iter_; - - std::string cow_device_; - std::string backing_store_device_; - std::string misc_name_; - - unique_fd cow_fd_; - unique_fd backing_store_fd_; - - std::shared_ptr snapuserd_; - std::unique_ptr reader_; - - std::unordered_set dest_blocks_; - std::unordered_set source_blocks_; - bool overlap_; - std::vector blocks_; - int total_blocks_merged_ = 0; - std::unique_ptr ra_temp_buffer_; - std::unique_ptr ra_temp_meta_buffer_; - BufferSink bufsink_; - - uint64_t total_ra_blocks_completed_ = 0; - bool read_ahead_async_ = false; - // Queue depth of 8 seems optimal. We don't want - // to have a huge depth as it may put more memory pressure - // on the kernel worker threads given that we use - // IOSQE_ASYNC flag - ASYNC flags can potentially - // result in EINTR; Since we don't restart - // syscalls and fallback to synchronous I/O, we - // don't want huge queue depth - int queue_depth_ = 8; - std::unique_ptr ring_; -}; - class UpdateVerify { public: UpdateVerify(const std::string& misc_name); diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp index 17f1f0e27375..af2428602962 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "snapuserd_readahead.h" + #include "snapuserd_core.h" namespace android { diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.h new file mode 100644 index 000000000000..5e94de005511 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.h @@ -0,0 +1,112 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace android { +namespace snapshot { + +class SnapshotHandler; + +class ReadAhead { + public: + ReadAhead(const std::string& cow_device, const std::string& backing_device, + const std::string& misc_name, std::shared_ptr snapuserd); + bool RunThread(); + + private: + void InitializeRAIter(); + bool RAIterDone(); + void RAIterNext(); + void RAResetIter(uint64_t num_blocks); + const CowOperation* GetRAOpIter(); + + void InitializeBuffer(); + bool InitReader(); + bool InitializeFds(); + + void CloseFds() { backing_store_fd_ = {}; } + + bool ReadAheadIOStart(); + int PrepareNextReadAhead(uint64_t* source_offset, int* pending_ops, + std::vector& blocks, + std::vector& xor_op_vec); + bool ReconstructDataFromCow(); + void CheckOverlap(const CowOperation* cow_op); + + bool ReadAheadAsyncIO(); + bool ReapIoCompletions(int pending_ios_to_complete); + bool ReadXorData(size_t block_index, size_t xor_op_index, + std::vector& xor_op_vec); + void ProcessXorData(size_t& block_xor_index, size_t& xor_index, + std::vector& xor_op_vec, void* buffer, + loff_t& buffer_offset); + void UpdateScratchMetadata(); + + bool ReadAheadSyncIO(); + bool InitializeIouring(); + void FinalizeIouring(); + + void* read_ahead_buffer_; + void* metadata_buffer_; + + std::unique_ptr cowop_iter_; + + std::string cow_device_; + std::string backing_store_device_; + std::string misc_name_; + + android::base::unique_fd cow_fd_; + android::base::unique_fd backing_store_fd_; + + std::shared_ptr snapuserd_; + std::unique_ptr reader_; + + std::unordered_set dest_blocks_; + std::unordered_set source_blocks_; + bool overlap_; + std::vector blocks_; + int total_blocks_merged_ = 0; + std::unique_ptr ra_temp_buffer_; + std::unique_ptr ra_temp_meta_buffer_; + BufferSink bufsink_; + + uint64_t total_ra_blocks_completed_ = 0; + bool read_ahead_async_ = false; + // Queue depth of 8 seems optimal. We don't want + // to have a huge depth as it may put more memory pressure + // on the kernel worker threads given that we use + // IOSQE_ASYNC flag - ASYNC flags can potentially + // result in EINTR; Since we don't restart + // syscalls and fallback to synchronous I/O, we + // don't want huge queue depth + int queue_depth_ = 8; + std::unique_ptr ring_; +}; + +} // namespace snapshot +} // namespace android From 4ac7d0e82ebd7c0f2381ada7fa1a10dc5548c3bf Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 13 Jun 2023 10:40:17 -0700 Subject: [PATCH 0112/1487] snapuserd: Create snapuserd_verify.h. Bug: N/A Test: builds Change-Id: I380bf705520858dbec8053432c0a7c3fa8bed26d --- .../user-space-merge/snapuserd_core.cpp | 4 ++ .../user-space-merge/snapuserd_core.h | 33 +--------- .../user-space-merge/snapuserd_verify.cpp | 4 +- .../user-space-merge/snapuserd_verify.h | 64 +++++++++++++++++++ 4 files changed, 73 insertions(+), 32 deletions(-) create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h 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 c3343b8c642a..8e1212b7b3ce 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -448,5 +448,9 @@ bool SnapshotHandler::IsIouringSupported() { return android::base::GetBoolProperty("ro.virtual_ab.io_uring.enabled", false); } +bool SnapshotHandler::CheckPartitionVerification() { + return update_verify_->CheckPartitionVerification(); +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index 79a5bc952abf..c16ad24a5c69 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -47,6 +47,7 @@ #include #include #include "snapuserd_readahead.h" +#include "snapuserd_verify.h" namespace android { namespace snapshot { @@ -97,36 +98,6 @@ struct MergeGroupState { : merge_state_(state), num_ios_in_progress(n_ios) {} }; -class UpdateVerify { - public: - UpdateVerify(const std::string& misc_name); - void VerifyUpdatePartition(); - bool CheckPartitionVerification(); - - private: - enum class UpdateVerifyState { - VERIFY_UNKNOWN, - VERIFY_FAILED, - VERIFY_SUCCESS, - }; - - std::string misc_name_; - UpdateVerifyState state_; - std::mutex m_lock_; - std::condition_variable m_cv_; - - int kMinThreadsToVerify = 1; - int kMaxThreadsToVerify = 4; - uint64_t kThresholdSize = 512_MiB; - uint64_t kBlockSizeVerify = 1_MiB; - - bool IsBlockAligned(uint64_t read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } - void UpdatePartitionVerificationState(UpdateVerifyState state); - bool VerifyPartition(const std::string& partition_name, const std::string& dm_block_device); - bool VerifyBlocks(const std::string& partition_name, const std::string& dm_block_device, - off_t offset, int skip_blocks, uint64_t dev_sz); -}; - class Worker { public: Worker(const std::string& cow_device, const std::string& backing_device, @@ -308,7 +279,7 @@ class SnapshotHandler : public std::enable_shared_from_this { MERGE_GROUP_STATE ProcessMergingBlock(uint64_t new_block, void* buffer); bool IsIouringSupported(); - bool CheckPartitionVerification() { return update_verify_->CheckPartitionVerification(); } + bool CheckPartitionVerification(); private: bool ReadMetadata(); diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp index 18c1dfcd9288..68173408045b 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp @@ -14,12 +14,14 @@ * limitations under the License. */ -#include "snapuserd_core.h" +#include "snapuserd_verify.h" #include #include #include +#include "snapuserd_core.h" + namespace android { namespace snapshot { diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h new file mode 100644 index 000000000000..d07d2f836838 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h @@ -0,0 +1,64 @@ +// Copyright (C) 2023 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. +// + +#pragma once + +#include +#include + +#include +#include +#include + +#include +#include + +namespace android { +namespace snapshot { + +using namespace android::storage_literals; + +class UpdateVerify { + public: + UpdateVerify(const std::string& misc_name); + void VerifyUpdatePartition(); + bool CheckPartitionVerification(); + + private: + enum class UpdateVerifyState { + VERIFY_UNKNOWN, + VERIFY_FAILED, + VERIFY_SUCCESS, + }; + + std::string misc_name_; + UpdateVerifyState state_; + std::mutex m_lock_; + std::condition_variable m_cv_; + + int kMinThreadsToVerify = 1; + int kMaxThreadsToVerify = 4; + uint64_t kThresholdSize = 512_MiB; + uint64_t kBlockSizeVerify = 1_MiB; + + bool IsBlockAligned(uint64_t read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } + void UpdatePartitionVerificationState(UpdateVerifyState state); + bool VerifyPartition(const std::string& partition_name, const std::string& dm_block_device); + bool VerifyBlocks(const std::string& partition_name, const std::string& dm_block_device, + off_t offset, int skip_blocks, uint64_t dev_sz); +}; + +} // namespace snapshot +} // namespace android From 85f52dd1ac84567dbc817d8015896f9c00c2b671 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Wed, 14 Jun 2023 18:28:17 +0000 Subject: [PATCH 0113/1487] Revert "Treat Microdroid as OS with monolithic sepolicy" Revert submission 2625691 Reason for revert: b/287283650 Reverted changes: /q/submissionid:2625691 Change-Id: Ie62bbb4d4f1af528f42aafde79407b151bab46f9 --- init/selinux.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/init/selinux.cpp b/init/selinux.cpp index a9365323362f..907eb80e31c0 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -300,8 +300,6 @@ bool GetVendorMappingVersion(std::string* plat_vers) { } constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil"; -constexpr const char kMicrodroidPrecompiledSepolicy[] = - "/system/etc/selinux/microdroid_precompiled_sepolicy"; bool IsSplitPolicyDevice() { return access(plat_policy_cil_file, R_OK) != -1; @@ -499,19 +497,14 @@ bool OpenSplitPolicy(PolicyFile* policy_file) { bool OpenMonolithicPolicy(PolicyFile* policy_file) { static constexpr char kSepolicyFile[] = "/sepolicy"; - // In Microdroid the precompiled sepolicy is located on /system, since there is no vendor code. - // TODO(b/287206497): refactor once we start conditionally compiling init for Microdroid. - std::string monolithic_policy_file = access(kMicrodroidPrecompiledSepolicy, R_OK) == 0 - ? kMicrodroidPrecompiledSepolicy - : kSepolicyFile; - - LOG(INFO) << "Opening SELinux policy from monolithic file " << monolithic_policy_file; - policy_file->fd.reset(open(monolithic_policy_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); + + LOG(VERBOSE) << "Opening SELinux policy from monolithic file"; + policy_file->fd.reset(open(kSepolicyFile, O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); if (policy_file->fd < 0) { PLOG(ERROR) << "Failed to open monolithic SELinux policy"; return false; } - policy_file->path = monolithic_policy_file; + policy_file->path = kSepolicyFile; return true; } From 5eae2cb4508282b1ae8f7f376a07645c650557d0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 9 May 2023 13:27:22 -0700 Subject: [PATCH 0114/1487] libsnapshot: Remove ISnapshotWriter. This only added one real method to ICowWriter, so let's just fold it into ICowWriter. CompressedSnapshotWriter goes away as well. CompressedSnapshotReader is now part of libsnapshot_cow. Bug: 280529365 Test: m otapackage apply ota Change-Id: I55358c3c9be111d5aee1a0c22c29cb1539d05494 --- fs_mgr/libsnapshot/Android.bp | 9 +- .../include/libsnapshot/cow_reader.h | 9 +- .../include/libsnapshot/cow_writer.h | 13 ++ ...ck_snapshot_writer.h => mock_cow_writer.h} | 16 +- .../include/libsnapshot/mock_snapshot.h | 4 +- .../include/libsnapshot/snapshot.h | 28 ++- .../include/libsnapshot/snapshot_stub.h | 4 +- .../include/libsnapshot/snapshot_writer.h | 93 --------- .../include_test/libsnapshot/test_helpers.h | 2 +- .../{ => libsnapshot_cow}/snapshot_reader.cpp | 86 +++------ .../{ => libsnapshot_cow}/snapshot_reader.h | 32 +--- .../snapshot_reader_test.cpp | 19 +- .../libsnapshot_cow/writer_base.cpp | 32 ++++ .../libsnapshot/libsnapshot_cow/writer_base.h | 3 + fs_mgr/libsnapshot/snapshot.cpp | 40 ++-- fs_mgr/libsnapshot/snapshot_stub.cpp | 4 +- fs_mgr/libsnapshot/snapshot_test.cpp | 28 +-- fs_mgr/libsnapshot/snapshot_writer.cpp | 179 ------------------ fs_mgr/libsnapshot/snapshot_writer_test.cpp | 62 ------ fs_mgr/libsnapshot/snapshotctl.cpp | 7 +- fs_mgr/libsnapshot/test_helpers.cpp | 7 +- 21 files changed, 158 insertions(+), 519 deletions(-) rename fs_mgr/libsnapshot/include/libsnapshot/{mock_snapshot_writer.h => mock_cow_writer.h} (75%) delete mode 100644 fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h rename fs_mgr/libsnapshot/{ => libsnapshot_cow}/snapshot_reader.cpp (83%) rename fs_mgr/libsnapshot/{ => libsnapshot_cow}/snapshot_reader.h (69%) rename fs_mgr/libsnapshot/{ => libsnapshot_cow}/snapshot_reader_test.cpp (92%) delete mode 100644 fs_mgr/libsnapshot/snapshot_writer.cpp delete mode 100644 fs_mgr/libsnapshot/snapshot_writer_test.cpp diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index e931bec39ff0..046d30cc9a16 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -85,11 +85,9 @@ filegroup { "android/snapshot/snapshot.proto", "device_info.cpp", "snapshot.cpp", - "snapshot_reader.cpp", "snapshot_stats.cpp", "snapshot_stub.cpp", "snapshot_metadata_updater.cpp", - "snapshot_writer.cpp", "partition_cow_creator.cpp", "return.cpp", "utility.cpp", @@ -165,6 +163,9 @@ cc_defaults { "liblz4", "libzstd", ], + header_libs: [ + "libupdate_engine_headers", + ], export_include_dirs: ["include"], } @@ -179,6 +180,7 @@ cc_library_static { "libsnapshot_cow/cow_format.cpp", "libsnapshot_cow/cow_reader.cpp", "libsnapshot_cow/parser_v2.cpp", + "libsnapshot_cow/snapshot_reader.cpp", "libsnapshot_cow/writer_base.cpp", "libsnapshot_cow/writer_v2.cpp", ], @@ -224,9 +226,7 @@ cc_defaults { srcs: [ "partition_cow_creator_test.cpp", "snapshot_metadata_updater_test.cpp", - "snapshot_reader_test.cpp", "snapshot_test.cpp", - "snapshot_writer_test.cpp", ], shared_libs: [ "libbinder", @@ -372,6 +372,7 @@ cc_test { "libsnapshot_cow_defaults", ], srcs: [ + "libsnapshot_cow/snapshot_reader_test.cpp", "libsnapshot_cow/test_v2.cpp", ], cflags: [ diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h index 95a1270f996a..3890b175434a 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h @@ -24,6 +24,10 @@ #include #include +namespace chromeos_update_engine { +class FileDescriptor; +} // namespace chromeos_update_engine + namespace android { namespace snapshot { @@ -32,6 +36,8 @@ class ICowOpIter; // Interface for reading from a snapuserd COW. class ICowReader { public: + using FileDescriptor = chromeos_update_engine::FileDescriptor; + virtual ~ICowReader() {} // Return the file header. @@ -109,10 +115,9 @@ class CowReader final : public ICowReader { bool Parse(android::base::borrowed_fd fd, std::optional label = {}); bool InitForMerge(android::base::unique_fd&& fd); - bool VerifyMergeOps() override; + bool VerifyMergeOps() override; bool GetFooter(CowFooter* footer) override; - bool GetLastLabel(uint64_t* label) override; // Create a CowOpIter object which contains footer_.num_ops diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h index af2d3efc521a..d6194eb9396f 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h @@ -61,6 +61,8 @@ struct CowOptions { // will occur in the sequence they were added to the COW. class ICowWriter { public: + using FileDescriptor = chromeos_update_engine::FileDescriptor; + virtual ~ICowWriter() {} // Encode an operation that copies the contents of |old_block| to the @@ -93,6 +95,17 @@ class ICowWriter { virtual uint32_t GetBlockSize() const = 0; virtual std::optional GetMaxBlocks() const = 0; + + // Open an ICowReader for this writer. The reader will be a snapshot of the + // current operations in the writer; new writes after OpenReader() will not + // be reflected. + virtual std::unique_ptr OpenReader() = 0; + + // Open a file descriptor. This allows reading and seeing through the cow + // as if it were a normal file. The optional source_device must be a valid + // path if the CowReader contains any copy or xor operations. + virtual std::unique_ptr OpenFileDescriptor( + const std::optional& source_device) = 0; }; class CompressWorker { diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h similarity index 75% rename from fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h rename to fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h index 52e3a9c4eb34..c58c6542aa21 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h @@ -15,17 +15,16 @@ // #include -#include +#include namespace android::snapshot { -class MockSnapshotWriter : public ISnapshotWriter { +class MockCowWriter : public ICowWriter { public: - using FileDescriptor = ISnapshotWriter::FileDescriptor; + using FileDescriptor = chromeos_update_engine::FileDescriptor; MOCK_METHOD(bool, Finalize, (), (override)); - // Return number of bytes the cow image occupies on disk. MOCK_METHOD(uint64_t, GetCowSize, (), (override)); MOCK_METHOD(bool, AddCopy, (uint64_t, uint64_t, uint64_t), (override)); @@ -35,11 +34,12 @@ class MockSnapshotWriter : public ISnapshotWriter { MOCK_METHOD(bool, AddZeroBlocks, (uint64_t, uint64_t), (override)); MOCK_METHOD(bool, AddLabel, (uint64_t), (override)); MOCK_METHOD(bool, AddSequenceData, (size_t, const uint32_t*), (override)); - MOCK_METHOD(bool, Initialize, (), (override)); - MOCK_METHOD(bool, InitializeAppend, (uint64_t), (override)); - MOCK_METHOD(bool, VerifyMergeOps, (), (override, const, noexcept)); - MOCK_METHOD(std::unique_ptr, OpenReader, (), (override)); MOCK_METHOD(uint32_t, GetBlockSize, (), (override, const)); MOCK_METHOD(std::optional, GetMaxBlocks, (), (override, const)); + + MOCK_METHOD(std::unique_ptr, OpenReader, (), (override)); + MOCK_METHOD(std::unique_ptr, OpenFileDescriptor, + (const std::optional&), (override)); }; + } // namespace android::snapshot diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h index d458b8718b8d..ca45d2fad88f 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h @@ -42,9 +42,9 @@ class MockSnapshotManager : public ISnapshotManager { (const android::fs_mgr::CreateLogicalPartitionParams& params, std::string* snapshot_path), (override)); - MOCK_METHOD(std::unique_ptr, OpenSnapshotWriter, + MOCK_METHOD(std::unique_ptr, OpenSnapshotWriter, (const android::fs_mgr::CreateLogicalPartitionParams& params, - const std::optional&), + std::optional), (override)); MOCK_METHOD(bool, UnmapUpdateSnapshot, (const std::string& target_partition_name), (override)); MOCK_METHOD(bool, NeedSnapshotsInFirstStageMount, (), (override)); diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h index ecf1d1531710..df532ee2152a 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h @@ -33,12 +33,11 @@ #include #include #include -#include - #include +#include #include -#include #include +#include #ifndef FRIEND_TEST #define FRIEND_TEST(test_set_name, individual_test) \ @@ -211,16 +210,13 @@ class ISnapshotManager { virtual bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params, std::string* snapshot_path) = 0; - // Create an ISnapshotWriter to build a snapshot against a target partition. The partition name + // Create an ICowWriter to build a snapshot against a target partition. The partition name // must be suffixed. If a source partition exists, it must be specified as well. The source // partition will only be used if raw bytes are needed. The source partition should be an // absolute path to the device, not a partition name. - // - // After calling OpenSnapshotWriter, the caller must invoke Initialize or InitializeForAppend - // before invoking write operations. - virtual std::unique_ptr OpenSnapshotWriter( + virtual std::unique_ptr OpenSnapshotWriter( const android::fs_mgr::CreateLogicalPartitionParams& params, - const std::optional& source_device) = 0; + std::optional label = {}) = 0; // Unmap a snapshot device or CowWriter that was previously opened with MapUpdateSnapshot, // OpenSnapshotWriter. All outstanding open descriptors, writers, or @@ -362,9 +358,9 @@ class SnapshotManager final : public ISnapshotManager { Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) override; bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params, std::string* snapshot_path) override; - std::unique_ptr OpenSnapshotWriter( + std::unique_ptr OpenSnapshotWriter( const android::fs_mgr::CreateLogicalPartitionParams& params, - const std::optional& source_device) override; + std::optional label) override; bool UnmapUpdateSnapshot(const std::string& target_partition_name) override; bool NeedSnapshotsInFirstStageMount() override; bool CreateLogicalAndSnapshotPartitions( @@ -693,10 +689,10 @@ class SnapshotManager final : public ISnapshotManager { }; // Helpers for OpenSnapshotWriter. - std::unique_ptr OpenCompressedSnapshotWriter( - LockedFile* lock, const std::optional& source_device, - const std::string& partition_name, const SnapshotStatus& status, - const SnapshotPaths& paths); + std::unique_ptr OpenCompressedSnapshotWriter(LockedFile* lock, + const SnapshotStatus& status, + const SnapshotPaths& paths, + std::optional label); // Map the base device, COW devices, and snapshot device. bool MapPartitionWithSnapshot(LockedFile* lock, CreateLogicalPartitionParams params, @@ -743,7 +739,7 @@ class SnapshotManager final : public ISnapshotManager { // Initialize snapshots so that they can be mapped later. // Map the COW partition and zero-initialize the header. Return InitializeUpdateSnapshots( - LockedFile* lock, MetadataBuilder* target_metadata, + LockedFile* lock, uint32_t cow_version, MetadataBuilder* target_metadata, const LpMetadata* exported_target_metadata, const std::string& target_suffix, const std::map& all_snapshot_status); diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h index 171c7c6f96c9..1c9b40368eb0 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h @@ -40,9 +40,9 @@ class SnapshotManagerStub : public ISnapshotManager { const chromeos_update_engine::DeltaArchiveManifest& manifest) override; bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params, std::string* snapshot_path) override; - std::unique_ptr OpenSnapshotWriter( + std::unique_ptr OpenSnapshotWriter( const android::fs_mgr::CreateLogicalPartitionParams& params, - const std::optional& source_device) override; + std::optional label) override; bool UnmapUpdateSnapshot(const std::string& target_partition_name) override; bool NeedSnapshotsInFirstStageMount() override; bool CreateLogicalAndSnapshotPartitions( diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h deleted file mode 100644 index 2653a6053026..000000000000 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h +++ /dev/null @@ -1,93 +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. - -#pragma once - -#include - -#include - -#include - -namespace chromeos_update_engine { -class FileDescriptor; -} // namespace chromeos_update_engine - -namespace android { -namespace snapshot { - -class ISnapshotWriter : public ICowWriter { - public: - using FileDescriptor = chromeos_update_engine::FileDescriptor; - - virtual ~ISnapshotWriter() {} - - // Open the writer in write mode (no append). - virtual bool Initialize() = 0; - - // Open the writer in append mode, with the last label to resume - // from. See CowWriter::InitializeAppend. - virtual bool InitializeAppend(uint64_t label) = 0; - - virtual std::unique_ptr OpenReader() = 0; - - virtual bool VerifyMergeOps() const noexcept = 0; -}; - -// Send writes to a COW or a raw device directly, based on a threshold. -class CompressedSnapshotWriter final : public ISnapshotWriter { - public: - CompressedSnapshotWriter(const CowOptions& options); - - void SetSourceDevice(const std::string& source_device); - - // Sets the COW device; this is required. - bool SetCowDevice(android::base::unique_fd&& cow_device); - - bool Initialize() override; - bool InitializeAppend(uint64_t label) override; - bool Finalize() override; - uint64_t GetCowSize() override; - uint32_t GetBlockSize() const override; - std::optional GetMaxBlocks() const override; - std::unique_ptr OpenReader() override; - bool VerifyMergeOps() const noexcept; - - bool AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override; - bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) override; - bool AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block, - uint16_t offset) override; - bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override; - bool AddLabel(uint64_t label) override; - bool AddSequenceData(size_t num_ops, const uint32_t* data) override; - - private: - std::unique_ptr OpenCowReader() const; - android::base::borrowed_fd GetSourceFd(); - - CowOptions options_; - - // Set the source device. This is used for AddCopy() operations, if the - // underlying writer needs the original bytes (for example if backed by - // dm-snapshot or if writing directly to an unsnapshotted region). The - // device is only opened on the first operation that requires it. - std::optional source_device_; - android::base::unique_fd source_fd_; - - android::base::unique_fd cow_device_; - std::unique_ptr cow_; -}; - -} // namespace snapshot -} // namespace android diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h index f45d4ed2abde..5e9f049d178a 100644 --- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h +++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h @@ -198,7 +198,7 @@ void DeleteBackingImage(android::fiemap::IImageManager* manager, const std::stri // Expect space of |path| is multiple of 4K. bool WriteRandomData(const std::string& path, std::optional expect_size = std::nullopt, std::string* hash = nullptr); -std::string HashSnapshot(ISnapshotWriter* writer); +std::string HashSnapshot(ICowWriter::FileDescriptor* writer); std::string ToHexString(const uint8_t* buf, size_t len); diff --git a/fs_mgr/libsnapshot/snapshot_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp similarity index 83% rename from fs_mgr/libsnapshot/snapshot_reader.cpp rename to fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp index 4e75ba75449f..f9cdbc0febf9 100644 --- a/fs_mgr/libsnapshot/snapshot_reader.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp @@ -18,73 +18,24 @@ #include #include -#include namespace android { namespace snapshot { using android::base::borrowed_fd; -// Not supported. -bool ReadOnlyFileDescriptor::Open(const char*, int, mode_t) { - errno = EINVAL; - return false; -} - -bool ReadOnlyFileDescriptor::Open(const char*, int) { - errno = EINVAL; - return false; -} - -ssize_t ReadOnlyFileDescriptor::Write(const void*, size_t) { - errno = EINVAL; - return false; -} - -bool ReadOnlyFileDescriptor::BlkIoctl(int, uint64_t, uint64_t, int*) { - errno = EINVAL; - return false; -} - -ReadFdFileDescriptor::ReadFdFileDescriptor(android::base::unique_fd&& fd) : fd_(std::move(fd)) {} - -ssize_t ReadFdFileDescriptor::Read(void* buf, size_t count) { - return read(fd_.get(), buf, count); -} - -off64_t ReadFdFileDescriptor::Seek(off64_t offset, int whence) { - return lseek(fd_.get(), offset, whence); -} - -uint64_t ReadFdFileDescriptor::BlockDevSize() { - return get_block_device_size(fd_.get()); -} - -bool ReadFdFileDescriptor::Close() { - fd_ = {}; - return true; -} - -bool ReadFdFileDescriptor::IsSettingErrno() { - return true; -} - -bool ReadFdFileDescriptor::IsOpen() { - return fd_ >= 0; -} - -bool ReadFdFileDescriptor::Flush() { - return true; -} - -bool CompressedSnapshotReader::SetCow(std::unique_ptr&& cow) { - cow_ = std::move(cow); - +CompressedSnapshotReader::CompressedSnapshotReader(std::unique_ptr&& cow, + const std::optional& source_device, + std::optional block_dev_size) + : cow_(std::move(cow)), + block_size_(cow_->GetHeader().block_size), + source_device_(source_device), + block_device_size_(block_dev_size.value_or(0)) { const auto& header = cow_->GetHeader(); block_size_ = header.block_size; // Populate the operation map. - op_iter_ = cow_->GetOpIter(); + op_iter_ = cow_->GetOpIter(false); while (!op_iter_->AtEnd()) { const CowOperation* op = op_iter_->Get(); if (IsMetadataOp(*op)) { @@ -97,16 +48,27 @@ bool CompressedSnapshotReader::SetCow(std::unique_ptr&& cow) { ops_[op->new_block] = op; op_iter_->Next(); } +} - return true; +// Not supported. +bool CompressedSnapshotReader::Open(const char*, int, mode_t) { + errno = EINVAL; + return false; +} + +bool CompressedSnapshotReader::Open(const char*, int) { + errno = EINVAL; + return false; } -void CompressedSnapshotReader::SetSourceDevice(const std::string& source_device) { - source_device_ = {source_device}; +ssize_t CompressedSnapshotReader::Write(const void*, size_t) { + errno = EINVAL; + return false; } -void CompressedSnapshotReader::SetBlockDeviceSize(uint64_t block_device_size) { - block_device_size_ = block_device_size; +bool CompressedSnapshotReader::BlkIoctl(int, uint64_t, uint64_t, int*) { + errno = EINVAL; + return false; } borrowed_fd CompressedSnapshotReader::GetSourceFd() { diff --git a/fs_mgr/libsnapshot/snapshot_reader.h b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.h similarity index 69% rename from fs_mgr/libsnapshot/snapshot_reader.h rename to fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.h index 5e19c62ce385..3de63ed197d1 100644 --- a/fs_mgr/libsnapshot/snapshot_reader.h +++ b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.h @@ -26,36 +26,16 @@ namespace android { namespace snapshot { -class ReadOnlyFileDescriptor : public chromeos_update_engine::FileDescriptor { +class CompressedSnapshotReader : public chromeos_update_engine::FileDescriptor { public: + CompressedSnapshotReader(std::unique_ptr&& cow, + const std::optional& source_device, + std::optional block_dev_size); + bool Open(const char* path, int flags, mode_t mode) override; bool Open(const char* path, int flags) override; ssize_t Write(const void* buf, size_t count) override; bool BlkIoctl(int request, uint64_t start, uint64_t length, int* result) override; -}; - -class ReadFdFileDescriptor : public ReadOnlyFileDescriptor { - public: - explicit ReadFdFileDescriptor(android::base::unique_fd&& fd); - - ssize_t Read(void* buf, size_t count) override; - off64_t Seek(off64_t offset, int whence) override; - uint64_t BlockDevSize() override; - bool Close() override; - bool IsSettingErrno() override; - bool IsOpen() override; - bool Flush() override; - - private: - android::base::unique_fd fd_; -}; - -class CompressedSnapshotReader : public ReadOnlyFileDescriptor { - public: - bool SetCow(std::unique_ptr&& cow); - void SetSourceDevice(const std::string& source_device); - void SetBlockDeviceSize(uint64_t block_device_size); - ssize_t Read(void* buf, size_t count) override; off64_t Seek(off64_t offset, int whence) override; uint64_t BlockDevSize() override; @@ -68,7 +48,7 @@ class CompressedSnapshotReader : public ReadOnlyFileDescriptor { ssize_t ReadBlock(uint64_t chunk, size_t start_offset, void* buffer, size_t size); android::base::borrowed_fd GetSourceFd(); - std::unique_ptr cow_; + std::unique_ptr cow_; std::unique_ptr op_iter_; uint32_t block_size_ = 0; diff --git a/fs_mgr/libsnapshot/snapshot_reader_test.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp similarity index 92% rename from fs_mgr/libsnapshot/snapshot_reader_test.cpp rename to fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp index f25023d817a6..10cb06d7eeea 100644 --- a/fs_mgr/libsnapshot/snapshot_reader_test.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include - #include #include @@ -61,7 +59,7 @@ class OfflineSnapshotTest : public ::testing::Test { ASSERT_EQ(fsync(base_->fd), 0); } - void WriteCow(ISnapshotWriter* writer) { + void WriteCow(ICowWriter* writer) { std::string new_block = MakeNewBlockString(); std::string xor_block = MakeXorBlockString(); @@ -72,8 +70,8 @@ class OfflineSnapshotTest : public ::testing::Test { ASSERT_TRUE(writer->Finalize()); } - void TestBlockReads(ISnapshotWriter* writer) { - auto reader = writer->OpenReader(); + void TestBlockReads(ICowWriter* writer) { + auto reader = writer->OpenFileDescriptor(base_->path); ASSERT_NE(reader, nullptr); // Test that unchanged blocks are not modified. @@ -117,8 +115,8 @@ class OfflineSnapshotTest : public ::testing::Test { ASSERT_EQ(two_blocks, zeroes); } - void TestByteReads(ISnapshotWriter* writer) { - auto reader = writer->OpenReader(); + void TestByteReads(ICowWriter* writer) { + auto reader = writer->OpenFileDescriptor(base_->path); ASSERT_NE(reader, nullptr); std::string blob(kBlockSize * 3, 'x'); @@ -154,7 +152,7 @@ class OfflineSnapshotTest : public ::testing::Test { ASSERT_EQ(got, expected); } - void TestReads(ISnapshotWriter* writer) { + void TestReads(ICowWriter* writer) { ASSERT_NO_FATAL_FAILURE(TestBlockReads(writer)); ASSERT_NO_FATAL_FAILURE(TestByteReads(writer)); } @@ -186,10 +184,7 @@ TEST_F(OfflineSnapshotTest, CompressedSnapshot) { unique_fd cow_fd(dup(cow_->fd)); ASSERT_GE(cow_fd, 0); - auto writer = std::make_unique(options); - writer->SetSourceDevice(base_->path); - ASSERT_TRUE(writer->SetCowDevice(std::move(cow_fd))); - ASSERT_TRUE(writer->Initialize()); + auto writer = CreateCowWriter(kDefaultCowVersion, options, std::move(cow_fd)); ASSERT_NO_FATAL_FAILURE(WriteCow(writer.get())); ASSERT_NO_FATAL_FAILURE(TestReads(writer.get())); } diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp index 22e63d0a323d..ff34c597b34b 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp @@ -21,6 +21,7 @@ #include #include +#include "snapshot_reader.h" // The info messages here are spammy, but as useful for update_engine. Disable // them when running on the host. @@ -159,5 +160,36 @@ bool CowWriterBase::ValidateNewBlock(uint64_t new_block) { return true; } +std::unique_ptr CowWriterBase::OpenReader() { + unique_fd cow_fd(fcntl(fd_.get(), F_DUPFD | F_DUPFD_CLOEXEC, 0)); + if (cow_fd < 0) { + PLOG(ERROR) << "CowWriterV2::OpenReander: dup COW device"; + return nullptr; + } + + auto cow = std::make_unique(); + if (!cow->Parse(std::move(cow_fd))) { + LOG(ERROR) << "CowWriterV2::OpenReader: unable to read COW"; + return nullptr; + } + return cow; +} + +std::unique_ptr CowWriterBase::OpenFileDescriptor( + const std::optional& source_device) { + auto reader = OpenReader(); + if (!reader) { + return nullptr; + } + + std::optional block_dev_size; + if (options_.max_blocks) { + block_dev_size = {*options_.max_blocks * options_.block_size}; + } + + return std::make_unique(std::move(reader), source_device, + block_dev_size); +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h index 8fa90656fe6b..c8b477275822 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h @@ -43,6 +43,9 @@ class CowWriterBase : public ICowWriter { bool AddSequenceData(size_t num_ops, const uint32_t* data) override; uint32_t GetBlockSize() const override { return options_.block_size; } std::optional GetMaxBlocks() const override { return options_.max_blocks; } + std::unique_ptr OpenReader() override; + std::unique_ptr OpenFileDescriptor( + const std::optional& source_device) override; const CowOptions& options() const { return options_; } diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index 5920bc22fa8c..fbea79b4ad9b 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -45,10 +45,9 @@ #include #include #include "device_info.h" -#include "libsnapshot_cow/writer_v2.h" +#include "libsnapshot_cow/parser_v2.h" #include "partition_cow_creator.h" #include "snapshot_metadata_updater.h" -#include "snapshot_reader.h" #include "utility.h" namespace android { @@ -3288,7 +3287,7 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife return Return::Error(); } - ret = InitializeUpdateSnapshots(lock.get(), target_metadata.get(), + ret = InitializeUpdateSnapshots(lock.get(), dap_metadata.cow_version(), target_metadata.get(), exported_target_metadata.get(), target_suffix, all_snapshot_status); if (!ret.is_ok()) return ret; @@ -3510,7 +3509,7 @@ Return SnapshotManager::CreateUpdateSnapshotsInternal( } Return SnapshotManager::InitializeUpdateSnapshots( - LockedFile* lock, MetadataBuilder* target_metadata, + LockedFile* lock, uint32_t cow_version, MetadataBuilder* target_metadata, const LpMetadata* exported_target_metadata, const std::string& target_suffix, const std::map& all_snapshot_status) { CHECK(lock); @@ -3558,8 +3557,8 @@ Return SnapshotManager::InitializeUpdateSnapshots( } options.compression = it->second.compression_algorithm(); - CowWriterV2 writer(options, std::move(fd)); - if (!writer.Initialize(std::nullopt) || !writer.Finalize()) { + auto writer = CreateCowWriter(cow_version, options, std::move(fd)); + if (!writer->Finalize()) { LOG(ERROR) << "Could not initialize COW device for " << target_partition->name(); return Return::Error(); } @@ -3609,12 +3608,12 @@ bool SnapshotManager::MapUpdateSnapshot(const CreateLogicalPartitionParams& para return true; } -std::unique_ptr SnapshotManager::OpenSnapshotWriter( +std::unique_ptr SnapshotManager::OpenSnapshotWriter( const android::fs_mgr::CreateLogicalPartitionParams& params, - const std::optional& source_device) { + std::optional label) { #if defined(LIBSNAPSHOT_NO_COW_WRITE) (void)params; - (void)source_device; + (void)label; LOG(ERROR) << "Snapshots cannot be written in first-stage init or recovery"; return nullptr; @@ -3653,16 +3652,14 @@ std::unique_ptr SnapshotManager::OpenSnapshotWriter( return nullptr; } - return OpenCompressedSnapshotWriter(lock.get(), source_device, params.GetPartitionName(), - status, paths); + return OpenCompressedSnapshotWriter(lock.get(), status, paths, label); #endif } #if !defined(LIBSNAPSHOT_NO_COW_WRITE) -std::unique_ptr SnapshotManager::OpenCompressedSnapshotWriter( - LockedFile* lock, const std::optional& source_device, - [[maybe_unused]] const std::string& partition_name, const SnapshotStatus& status, - const SnapshotPaths& paths) { +std::unique_ptr SnapshotManager::OpenCompressedSnapshotWriter( + LockedFile* lock, const SnapshotStatus& status, const SnapshotPaths& paths, + std::optional label) { CHECK(lock); CowOptions cow_options; @@ -3679,11 +3676,6 @@ std::unique_ptr SnapshotManager::OpenCompressedSnapshotWriter( // never creates this scenario. CHECK(status.snapshot_size() == status.device_size()); - auto writer = std::make_unique(cow_options); - if (source_device) { - writer->SetSourceDevice(*source_device); - } - std::string cow_path; if (!GetMappedImageDevicePath(paths.cow_device_name, &cow_path)) { LOG(ERROR) << "Could not determine path for " << paths.cow_device_name; @@ -3695,12 +3687,14 @@ std::unique_ptr SnapshotManager::OpenCompressedSnapshotWriter( PLOG(ERROR) << "OpenCompressedSnapshotWriter: open " << cow_path; return nullptr; } - if (!writer->SetCowDevice(std::move(cow_fd))) { - LOG(ERROR) << "Could not create COW writer from " << cow_path; + + CowHeader header; + if (!ReadCowHeader(cow_fd, &header)) { + LOG(ERROR) << "OpenCompressedSnapshotWriter: read header failed"; return nullptr; } - return writer; + return CreateCowWriter(header.prefix.major_version, cow_options, std::move(cow_fd), label); } #endif // !defined(LIBSNAPSHOT_NO_COW_WRITE) diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp index 84e2226fa888..93541020e51a 100644 --- a/fs_mgr/libsnapshot/snapshot_stub.cpp +++ b/fs_mgr/libsnapshot/snapshot_stub.cpp @@ -154,8 +154,8 @@ ISnapshotMergeStats* SnapshotManagerStub::GetSnapshotMergeStatsInstance() { return &snapshot_merge_stats; } -std::unique_ptr SnapshotManagerStub::OpenSnapshotWriter( - const CreateLogicalPartitionParams&, const std::optional&) { +std::unique_ptr SnapshotManagerStub::OpenSnapshotWriter( + const CreateLogicalPartitionParams&, std::optional) { LOG(ERROR) << __FUNCTION__ << " should never be called."; return nullptr; } diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index dac1b771b83d..0a85489bd7eb 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -345,7 +345,7 @@ class SnapshotTest : public ::testing::Test { } AssertionResult MapUpdateSnapshot(const std::string& name, - std::unique_ptr* writer) { + std::unique_ptr* writer) { TestPartitionOpener opener(fake_super); CreateLogicalPartitionParams params{ .block_device = fake_super, @@ -355,14 +355,10 @@ class SnapshotTest : public ::testing::Test { .partition_opener = &opener, }; - auto old_partition = "/dev/block/mapper/" + GetOtherPartitionName(name); - auto result = sm->OpenSnapshotWriter(params, {old_partition}); + auto result = sm->OpenSnapshotWriter(params, {}); if (!result) { return AssertionFailure() << "Cannot open snapshot for writing: " << name; } - if (!result->Initialize()) { - return AssertionFailure() << "Cannot initialize snapshot for writing: " << name; - } if (writer) { *writer = std::move(result); @@ -440,7 +436,7 @@ class SnapshotTest : public ::testing::Test { // Prepare A/B slot for a partition named "test_partition". AssertionResult PrepareOneSnapshot(uint64_t device_size, - std::unique_ptr* writer = nullptr) { + std::unique_ptr* writer = nullptr) { lock_ = nullptr; DeltaArchiveManifest manifest; @@ -651,7 +647,7 @@ TEST_F(SnapshotTest, Merge) { bool userspace_snapshots = false; if (snapuserd_required_) { - std::unique_ptr writer; + std::unique_ptr writer; ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize, &writer)); userspace_snapshots = sm->UpdateUsesUserSnapshots(lock_.get()); @@ -1160,7 +1156,7 @@ class SnapshotUpdateTest : public SnapshotTest { AssertionResult MapOneUpdateSnapshot(const std::string& name) { if (snapuserd_required_) { - std::unique_ptr writer; + std::unique_ptr writer; return MapUpdateSnapshot(name, &writer); } else { std::string path; @@ -1181,7 +1177,7 @@ class SnapshotUpdateTest : public SnapshotTest { AssertionResult WriteSnapshotAndHash(PartitionUpdate* partition) { std::string name = partition->partition_name() + "_b"; if (snapuserd_required_) { - std::unique_ptr writer; + std::unique_ptr writer; auto res = MapUpdateSnapshot(name, &writer); if (!res) { return res; @@ -1250,7 +1246,7 @@ class SnapshotUpdateTest : public SnapshotTest { // It doesn't really matter the order, we just want copies that reference // blocks that won't exist if the partition shrinks. AssertionResult ShiftAllSnapshotBlocks(const std::string& name, uint64_t old_size) { - std::unique_ptr writer; + std::unique_ptr writer; if (auto res = MapUpdateSnapshot(name, &writer); !res) { return res; } @@ -1273,7 +1269,13 @@ class SnapshotUpdateTest : public SnapshotTest { return AssertionFailure() << "Unable to finalize writer for " << name; } - auto hash = HashSnapshot(writer.get()); + auto old_partition = "/dev/block/mapper/" + GetOtherPartitionName(name); + auto reader = writer->OpenFileDescriptor(old_partition); + if (!reader) { + return AssertionFailure() << "Could not open file descriptor for " << name; + } + + auto hash = HashSnapshot(reader.get()); if (hash.empty()) { return AssertionFailure() << "Unable to hash snapshot writer for " << name; } @@ -1428,7 +1430,7 @@ TEST_F(SnapshotUpdateTest, DuplicateOps) { for (auto* partition : partitions) { AddOperation(partition); - std::unique_ptr writer; + std::unique_ptr writer; auto res = MapUpdateSnapshot(partition->partition_name() + "_b", &writer); ASSERT_TRUE(res); ASSERT_TRUE(writer->AddZeroBlocks(0, 1)); diff --git a/fs_mgr/libsnapshot/snapshot_writer.cpp b/fs_mgr/libsnapshot/snapshot_writer.cpp deleted file mode 100644 index 0ea424c7e9d9..000000000000 --- a/fs_mgr/libsnapshot/snapshot_writer.cpp +++ /dev/null @@ -1,179 +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 - -#include -#include -#include -#include "libsnapshot_cow/writer_v2.h" -#include "snapshot_reader.h" - -namespace android { -namespace snapshot { - -using android::base::borrowed_fd; -using android::base::unique_fd; -using chromeos_update_engine::FileDescriptor; - -void CompressedSnapshotWriter::SetSourceDevice(const std::string& source_device) { - source_device_ = {source_device}; -} - -borrowed_fd CompressedSnapshotWriter::GetSourceFd() { - if (!source_device_) { - LOG(ERROR) << "Attempted to read from source device but none was set"; - return borrowed_fd{-1}; - } - - if (source_fd_ < 0) { - source_fd_.reset(open(source_device_->c_str(), O_RDONLY | O_CLOEXEC)); - if (source_fd_ < 0) { - PLOG(ERROR) << "open " << *source_device_; - return borrowed_fd{-1}; - } - } - return source_fd_; -} - -CompressedSnapshotWriter::CompressedSnapshotWriter(const CowOptions& options) : options_(options) {} - -bool CompressedSnapshotWriter::SetCowDevice(android::base::unique_fd&& cow_device) { - cow_device_ = std::move(cow_device); - return true; -} - -bool CompressedSnapshotWriter::Finalize() { - return cow_->Finalize(); -} - -uint64_t CompressedSnapshotWriter::GetCowSize() { - return cow_->GetCowSize(); -} - -std::unique_ptr CompressedSnapshotWriter::OpenCowReader() const { - unique_fd cow_fd(dup(cow_device_.get())); - if (cow_fd < 0) { - PLOG(ERROR) << "dup COW device"; - return nullptr; - } - - auto cow = std::make_unique(); - if (!cow->Parse(std::move(cow_fd))) { - 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 CompressedSnapshotWriter::OpenReader() { - auto cow = OpenCowReader(); - if (cow == nullptr) { - return nullptr; - } - - auto reader = std::make_unique(); - if (!reader->SetCow(std::move(cow))) { - LOG(ERROR) << "Unable to initialize COW reader"; - return nullptr; - } - if (source_device_) { - reader->SetSourceDevice(*source_device_); - } - - if (options_.max_blocks) { - reader->SetBlockDeviceSize(*options_.max_blocks * options_.block_size); - } - - return reader; -} - -bool CompressedSnapshotWriter::AddCopy(uint64_t new_block, uint64_t old_block, - uint64_t num_blocks) { - return cow_->AddCopy(new_block, old_block, num_blocks); -} - -bool CompressedSnapshotWriter::AddRawBlocks(uint64_t new_block_start, const void* data, - size_t size) { - return cow_->AddRawBlocks(new_block_start, data, size); -} - -bool CompressedSnapshotWriter::AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, - uint32_t old_block, uint16_t offset) { - return cow_->AddXorBlocks(new_block_start, data, size, old_block, offset); -} - -bool CompressedSnapshotWriter::AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { - return cow_->AddZeroBlocks(new_block_start, num_blocks); -} - -bool CompressedSnapshotWriter::AddLabel(uint64_t label) { - return cow_->AddLabel(label); -} - -bool CompressedSnapshotWriter::AddSequenceData(size_t num_ops, const uint32_t* data) { - return cow_->AddSequenceData(num_ops, data); -} - -bool CompressedSnapshotWriter::Initialize() { - unique_fd cow_fd(dup(cow_device_.get())); - if (cow_fd < 0) { - PLOG(ERROR) << "dup COW device"; - return false; - } - - auto cow = std::make_unique(options_, std::move(cow_fd)); - if (!cow->Initialize(std::nullopt)) { - return false; - } - cow_ = std::move(cow); - return true; -} - -bool CompressedSnapshotWriter::InitializeAppend(uint64_t label) { - unique_fd cow_fd(dup(cow_device_.get())); - if (cow_fd < 0) { - PLOG(ERROR) << "dup COW device"; - return false; - } - - auto cow = std::make_unique(options_, std::move(cow_fd)); - if (!cow->Initialize(label)) { - return false; - } - cow_ = std::move(cow); - return true; -} - -uint32_t CompressedSnapshotWriter::GetBlockSize() const { - return cow_->GetBlockSize(); -} - -std::optional CompressedSnapshotWriter::GetMaxBlocks() const { - return cow_->GetMaxBlocks(); -} - -} // namespace snapshot -} // namespace android diff --git a/fs_mgr/libsnapshot/snapshot_writer_test.cpp b/fs_mgr/libsnapshot/snapshot_writer_test.cpp deleted file mode 100644 index a03632b46c99..000000000000 --- a/fs_mgr/libsnapshot/snapshot_writer_test.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// -// Copyright (C) 2021 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 - -#include - -#include -#include -#include -#include - -namespace android::snapshot { -class CompressedSnapshotWriterTest : public ::testing::Test { - public: - static constexpr size_t BLOCK_SIZE = 4096; -}; - -TEST_F(CompressedSnapshotWriterTest, ReadAfterWrite) { - TemporaryFile cow_device_file{}; - android::snapshot::CowOptions options{.block_size = BLOCK_SIZE}; - android::snapshot::CompressedSnapshotWriter snapshot_writer{options}; - ASSERT_TRUE(snapshot_writer.SetCowDevice(android::base::unique_fd{cow_device_file.fd})); - ASSERT_TRUE(snapshot_writer.Initialize()); - std::vector buffer; - buffer.resize(BLOCK_SIZE); - std::fill(buffer.begin(), buffer.end(), 123); - - ASSERT_TRUE(snapshot_writer.AddRawBlocks(0, buffer.data(), buffer.size())); - ASSERT_TRUE(snapshot_writer.Finalize()); - auto cow_reader = snapshot_writer.OpenReader(); - ASSERT_NE(cow_reader, nullptr); - ASSERT_TRUE(snapshot_writer.AddRawBlocks(1, buffer.data(), buffer.size())); - ASSERT_TRUE(snapshot_writer.AddRawBlocks(2, buffer.data(), buffer.size())); - ASSERT_TRUE(snapshot_writer.Finalize()); - // After wrigin some data, if we call OpenReader() again, writes should - // be visible to the newly opened reader. update_engine relies on this - // behavior for verity writes. - cow_reader = snapshot_writer.OpenReader(); - ASSERT_NE(cow_reader, nullptr); - std::vector read_back; - read_back.resize(buffer.size()); - cow_reader->Seek(BLOCK_SIZE, SEEK_SET); - const auto bytes_read = cow_reader->Read(read_back.data(), read_back.size()); - ASSERT_EQ((size_t)(bytes_read), BLOCK_SIZE); - ASSERT_EQ(read_back, buffer); -} - -} // namespace android::snapshot diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp index ad3f83cba89b..38eb719fd277 100644 --- a/fs_mgr/libsnapshot/snapshotctl.cpp +++ b/fs_mgr/libsnapshot/snapshotctl.cpp @@ -133,7 +133,6 @@ bool CreateTestUpdate(SnapshotManager* sm) { // Write the "new" system partition. auto system_target_name = "system" + target_slot; - auto source_device = "/dev/block/mapper/" + system_source_name; CreateLogicalPartitionParams clpp = { .block_device = fs_mgr_get_super_partition_name(target_slot_number), .metadata_slot = {target_slot_number}, @@ -141,15 +140,11 @@ bool CreateTestUpdate(SnapshotManager* sm) { .partition_opener = &opener, .timeout_ms = 10s, }; - auto writer = sm->OpenSnapshotWriter(clpp, {source_device}); + auto writer = sm->OpenSnapshotWriter(clpp, std::nullopt); if (!writer) { std::cerr << "Could not open snapshot writer.\n"; return false; } - if (!writer->Initialize()) { - std::cerr << "Could not initialize snapshot for writing.\n"; - return false; - } for (uint64_t block = 0; block < system_source_size / 4096; block++) { if (!writer->AddCopy(block, block)) { diff --git a/fs_mgr/libsnapshot/test_helpers.cpp b/fs_mgr/libsnapshot/test_helpers.cpp index a224f6b58284..2eac34749909 100644 --- a/fs_mgr/libsnapshot/test_helpers.cpp +++ b/fs_mgr/libsnapshot/test_helpers.cpp @@ -130,12 +130,7 @@ bool WriteRandomData(const std::string& path, std::optional expect_size, return true; } -std::string HashSnapshot(ISnapshotWriter* writer) { - auto reader = writer->OpenReader(); - if (!reader) { - return {}; - } - +std::string HashSnapshot(ICowWriter::FileDescriptor* reader) { SHA256_CTX ctx; SHA256_Init(&ctx); From 76622d444d94b620089707528dd98337bf2671fd Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 13 Jun 2023 16:51:22 -0700 Subject: [PATCH 0115/1487] libsnapshot: Remove dependence between CowWriterV2 and CowReader. The plan of record for the new CowOperation layout is to automatically translate from CowOperationV2. However, CowWriterV2 currently imports directly from CowReader, which means we'd need two translation steps. Luckily we now have CowParserV2, which means we can directly import into CowWriterV2. Bug: 280529365 Test: vts_libsnapshot_test Test: cow_api_test Change-Id: I11863dcb483f0448686d6c492d8eb128840ce18c --- .../libsnapshot/libsnapshot_cow/writer_v2.cpp | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp index b6603da52edf..c5499697286d 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp @@ -14,6 +14,8 @@ // limitations under the License. // +#include "writer_v2.h" + #include #include #include @@ -37,7 +39,7 @@ #include #include -#include "writer_v2.h" +#include "parser_v2.h" // The info messages here are spammy, but as useful for update_engine. Disable // them when running on the host. @@ -252,14 +254,20 @@ bool CowWriterV2::OpenForWrite() { } bool CowWriterV2::OpenForAppend(uint64_t label) { - auto reader = std::make_unique(); - std::queue toAdd; + if (!ReadCowHeader(fd_, &header_)) { + return false; + } - if (!reader->Parse(fd_, {label})) { + CowParserV2 parser; + if (!parser.Parse(fd_, header_, {label})) { + return false; + } + if (header_.prefix.major_version > 2) { + LOG(ERROR) << "CowWriterV2 tried to open incompatible version " + << header_.prefix.major_version; return false; } - header_ = reader->GetHeader(); options_.block_size = header_.block_size; options_.cluster_ops = header_.cluster_ops; @@ -267,16 +275,10 @@ bool CowWriterV2::OpenForAppend(uint64_t label) { footer_.op.num_ops = 0; InitPos(); - auto iter = reader->GetOpIter(); - - while (!iter->AtEnd()) { - AddOperation(*iter->Get()); - iter->Next(); + for (const auto& op : *parser.ops()) { + AddOperation(op); } - // Free reader so we own the descriptor position again. - reader = nullptr; - if (lseek(fd_.get(), next_op_pos_, SEEK_SET) < 0) { PLOG(ERROR) << "lseek failed"; return false; From fa33f85f522352be0b8766d88d1ff0abb76fd378 Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Wed, 14 Jun 2023 20:29:37 +0000 Subject: [PATCH 0116/1487] Reland "Treat Microdroid as OS with monolithic sepolicy" Bug: 285855150 Test: presubmit Change-Id: I477e1ef7268ac8e7d0fdae7ffcc611a69bb9d4fe --- init/selinux.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/init/selinux.cpp b/init/selinux.cpp index 907eb80e31c0..a9365323362f 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -300,6 +300,8 @@ bool GetVendorMappingVersion(std::string* plat_vers) { } constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil"; +constexpr const char kMicrodroidPrecompiledSepolicy[] = + "/system/etc/selinux/microdroid_precompiled_sepolicy"; bool IsSplitPolicyDevice() { return access(plat_policy_cil_file, R_OK) != -1; @@ -497,14 +499,19 @@ bool OpenSplitPolicy(PolicyFile* policy_file) { bool OpenMonolithicPolicy(PolicyFile* policy_file) { static constexpr char kSepolicyFile[] = "/sepolicy"; - - LOG(VERBOSE) << "Opening SELinux policy from monolithic file"; - policy_file->fd.reset(open(kSepolicyFile, O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); + // In Microdroid the precompiled sepolicy is located on /system, since there is no vendor code. + // TODO(b/287206497): refactor once we start conditionally compiling init for Microdroid. + std::string monolithic_policy_file = access(kMicrodroidPrecompiledSepolicy, R_OK) == 0 + ? kMicrodroidPrecompiledSepolicy + : kSepolicyFile; + + LOG(INFO) << "Opening SELinux policy from monolithic file " << monolithic_policy_file; + policy_file->fd.reset(open(monolithic_policy_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); if (policy_file->fd < 0) { PLOG(ERROR) << "Failed to open monolithic SELinux policy"; return false; } - policy_file->path = kSepolicyFile; + policy_file->path = monolithic_policy_file; return true; } From 2aba0a228324b2868e62df074fac616d7cc4e609 Mon Sep 17 00:00:00 2001 From: Fabien Sanglard Date: Wed, 14 Jun 2023 23:08:02 +0000 Subject: [PATCH 0117/1487] Fix LruCache, allow std:string caching The default initalization for mNullValue uses 0 which is in the case of a std::string TValue will invoke the contructor with undefined behavior parameter. Using an empty uniform initialization {} addresses the problem. Test: Already tested in lrucache_test.cpp Bug: 257127748 Change-Id: I37420ce8a16c99f3014538a0208d7e113870b1c7 --- libutils/LruCache_test.cpp | 11 +++++++---- libutils/include/utils/LruCache.h | 12 ++++++------ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/libutils/LruCache_test.cpp b/libutils/LruCache_test.cpp index 8b16947bef47..5cd3cbb90cf7 100644 --- a/libutils/LruCache_test.cpp +++ b/libutils/LruCache_test.cpp @@ -29,6 +29,8 @@ typedef const char* StringValue; struct ComplexKey { int k; + explicit ComplexKey() : k(0) { instanceCount += 1; } + explicit ComplexKey(int k) : k(k) { instanceCount += 1; } @@ -57,6 +59,8 @@ ssize_t ComplexKey::instanceCount = 0; struct ComplexValue { int v; + explicit ComplexValue() : v(0) { instanceCount += 1; } + explicit ComplexValue(int v) : v(v) { instanceCount += 1; } @@ -83,10 +87,9 @@ struct KeyWithPointer { struct KeyFailsOnCopy : public ComplexKey { public: - KeyFailsOnCopy(const KeyFailsOnCopy& key) : ComplexKey(key) { - ADD_FAILURE(); - } - KeyFailsOnCopy(int key) : ComplexKey(key) { } + KeyFailsOnCopy() : ComplexKey() {} + KeyFailsOnCopy(const KeyFailsOnCopy& key) : ComplexKey(key) { ADD_FAILURE(); } + KeyFailsOnCopy(int key) : ComplexKey(key) {} }; } // namespace diff --git a/libutils/include/utils/LruCache.h b/libutils/include/utils/LruCache.h index b4243a3dbe38..70901b63b4c5 100644 --- a/libutils/include/utils/LruCache.h +++ b/libutils/include/utils/LruCache.h @@ -161,12 +161,12 @@ class LruCache { // Implementation is here, because it's fully templated template LruCache::LruCache(uint32_t maxCapacity) - : mSet(new LruCacheSet()) - , mListener(nullptr) - , mOldest(nullptr) - , mYoungest(nullptr) - , mMaxCapacity(maxCapacity) - , mNullValue(0) { + : mSet(new LruCacheSet()), + mListener(nullptr), + mOldest(nullptr), + mYoungest(nullptr), + mMaxCapacity(maxCapacity), + mNullValue{} { mSet->max_load_factor(1.0); }; From 1501b0c344513b5d3dc521b91fffca71b2004054 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 14 Jun 2023 19:26:54 +0000 Subject: [PATCH 0118/1487] init_kill_services_test: binder logs on apexd fail Print logs necessary to understand why apexd isn't shutting down when this test fails, due to a rare flake. Bug: 285458033 Test: init_kill_services_test (and cause this error to be hit) Change-Id: Ic9cbf7b2b9fa89504e4a53597065e94c32233e12 --- init/test_kill_services/init_kill_services_test.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/init/test_kill_services/init_kill_services_test.cpp b/init/test_kill_services/init_kill_services_test.cpp index d9fcd9d45376..dd4606449621 100644 --- a/init/test_kill_services/init_kill_services_test.cpp +++ b/init/test_kill_services/init_kill_services_test.cpp @@ -27,10 +27,13 @@ using ::android::base::WaitForProperty; using std::literals::chrono_literals::operator""s; void ExpectKillingServiceRecovers(const std::string& service_name) { + LOG(INFO) << "before we say hi to " << service_name << ", I can't have apexd around!"; + // b/280514080 - servicemanager will restart apexd, and apexd will restart the // system when crashed. This is fine as the device recovers, but it causes // flakes in this test. - ASSERT_TRUE(WaitForProperty("init.svc.apexd", "stopped", 60s)) << "apexd won't stop"; + ASSERT_TRUE(WaitForProperty("init.svc.apexd", "stopped", 60s)) + << (system("cat /dev/binderfs/binder_logs/state"), "apexd won't stop"); LOG(INFO) << "hello " << service_name << "!"; const std::string status_prop = "init.svc." + service_name; From 691b78a0fdaef1080b0315fdda91bd85df9aa626 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 15 Jun 2023 11:00:30 -0700 Subject: [PATCH 0119/1487] inspect_cow: Switch to gflags. gflags is a lot cleaner to use than getopt, and we don't really need any advanced argument parsing. Test: inspect_cow Bug: N/A Change-Id: I19007a787a2e5cd3a67486c7949b34ba76f762e4 --- fs_mgr/libsnapshot/Android.bp | 1 + .../libsnapshot_cow/inspect_cow.cpp | 120 +++++------------- 2 files changed, 35 insertions(+), 86 deletions(-) diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index 046d30cc9a16..9d1ce7db9b79 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -417,6 +417,7 @@ cc_binary { "libbrotli", "libcrypto_static", "liblog", + "libgflags", "libsnapshot_cow", "libz", ], diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp index c2c86eefdda3..9bb0df344e53 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp @@ -24,8 +24,19 @@ #include #include +#include #include +DEFINE_bool(silent, false, "Run silently"); +DEFINE_bool(decompress, false, "Attempt to decompress data ops"); +DEFINE_bool(show_bad_data, false, "If an op fails to decompress, show its daw data"); +DEFINE_bool(show_ops, false, "Print all opcode information"); +DEFINE_string(order, "", "If show_ops is true, change the order (either merge or reverse-merge)"); +DEFINE_bool(show_merged, false, + "If show_ops is true, and order is merge or reverse-merge, include merged ops"); +DEFINE_bool(verify_merge_sequence, false, "Verify merge order sequencing"); +DEFINE_bool(show_merge_sequence, false, "Show merge order sequence"); + namespace android { namespace snapshot { @@ -38,32 +49,6 @@ void MyLogger(android::base::LogId, android::base::LogSeverity severity, const c } } -static void usage(void) { - std::cerr << "Usage: inspect_cow [-sd] \n"; - std::cerr << "\t -s Run Silent\n"; - std::cerr << "\t -d Attempt to decompress\n"; - std::cerr << "\t -b Show data for failed decompress\n"; - std::cerr << "\t -l Show ops\n"; - std::cerr << "\t -m Show ops in reverse merge order\n"; - std::cerr << "\t -n Show ops in merge order\n"; - std::cerr << "\t -a Include merged ops in any merge order listing\n"; - std::cerr << "\t -o Shows sequence op block order\n"; - std::cerr << "\t -v Verifies merge order has no conflicts\n"; -} - -enum OpIter { Normal, RevMerge, Merge }; - -struct Options { - bool silent; - bool decompress; - bool show_ops; - bool show_bad; - bool show_seq; - bool verify_sequence; - OpIter iter_type; - bool include_merged; -}; - static void ShowBad(CowReader& reader, const struct CowOperation* op) { size_t count; auto buffer = std::make_unique(op->data_length); @@ -82,7 +67,7 @@ static void ShowBad(CowReader& reader, const struct CowOperation* op) { } } -static bool Inspect(const std::string& path, Options opt) { +static bool Inspect(const std::string& path) { android::base::unique_fd fd(open(path.c_str(), O_RDONLY)); if (fd < 0) { PLOG(ERROR) << "open failed: " << path; @@ -103,7 +88,7 @@ static bool Inspect(const std::string& path, Options opt) { bool has_footer = false; if (reader.GetFooter(&footer)) has_footer = true; - if (!opt.silent) { + if (!FLAGS_silent) { std::cout << "Version: " << header.prefix.major_version << "." << header.prefix.minor_version << "\n"; std::cout << "Header size: " << header.prefix.header_size << "\n"; @@ -119,11 +104,11 @@ static bool Inspect(const std::string& path, Options opt) { } } - if (!opt.silent) { + if (!FLAGS_silent) { std::cout << "Parse time: " << (parse_time.count() * 1000) << "ms\n"; } - if (opt.verify_sequence) { + if (FLAGS_verify_merge_sequence) { std::cout << "\n"; if (reader.VerifyMergeOps()) { std::cout << "\nMerge sequence is consistent.\n"; @@ -133,12 +118,12 @@ static bool Inspect(const std::string& path, Options opt) { } std::unique_ptr iter; - if (opt.iter_type == Normal) { + if (FLAGS_order.empty()) { iter = reader.GetOpIter(); - } else if (opt.iter_type == RevMerge) { - iter = reader.GetRevMergeOpIter(opt.include_merged); - } else if (opt.iter_type == Merge) { - iter = reader.GetMergeOpIter(opt.include_merged); + } else if (FLAGS_order == "reverse-merge") { + iter = reader.GetRevMergeOpIter(FLAGS_show_merged); + } else if (FLAGS_order == "merge") { + iter = reader.GetMergeOpIter(FLAGS_show_merged); } std::string buffer(header.block_size, '\0'); @@ -148,17 +133,17 @@ static bool Inspect(const std::string& path, Options opt) { while (!iter->AtEnd()) { const CowOperation* op = iter->Get(); - if (!opt.silent && opt.show_ops) std::cout << *op << "\n"; + if (!FLAGS_silent && FLAGS_show_ops) std::cout << *op << "\n"; - if (opt.decompress && op->type == kCowReplaceOp && op->compression != kCowCompressNone) { + if (FLAGS_decompress && op->type == kCowReplaceOp && op->compression != kCowCompressNone) { if (reader.ReadData(op, buffer.data(), buffer.size()) < 0) { std::cerr << "Failed to decompress for :" << *op << "\n"; success = false; - if (opt.show_bad) ShowBad(reader, op); + if (FLAGS_show_bad_data) ShowBad(reader, op); } } - if (op->type == kCowSequenceOp && opt.show_seq) { + if (op->type == kCowSequenceOp && FLAGS_show_merge_sequence) { size_t read; std::vector merge_op_blocks; size_t seq_len = op->data_length / sizeof(uint32_t); @@ -167,7 +152,7 @@ static bool Inspect(const std::string& path, Options opt) { PLOG(ERROR) << "Failed to read sequence op!"; return false; } - if (!opt.silent) { + if (!FLAGS_silent) { std::cout << "Sequence for " << *op << " is :\n"; for (size_t i = 0; i < seq_len; i++) { std::cout << std::setfill('0') << std::setw(6) << merge_op_blocks[i] << ", "; @@ -189,7 +174,7 @@ static bool Inspect(const std::string& path, Options opt) { iter->Next(); } - if (!opt.silent) { + if (!FLAGS_silent) { auto total_ops = replace_ops + zero_ops + copy_ops + xor_ops; std::cout << "Data ops: " << total_ops << "\n"; std::cout << "Replace ops: " << replace_ops << "\n"; @@ -205,57 +190,20 @@ static bool Inspect(const std::string& path, Options opt) { } // namespace android int main(int argc, char** argv) { - int ch; - struct android::snapshot::Options opt; - opt.silent = false; - opt.decompress = false; - opt.show_bad = false; - opt.iter_type = android::snapshot::Normal; - opt.verify_sequence = false; - opt.include_merged = false; - while ((ch = getopt(argc, argv, "sdbmnolva")) != -1) { - switch (ch) { - case 's': - opt.silent = true; - break; - case 'd': - opt.decompress = true; - break; - case 'b': - opt.show_bad = true; - break; - 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(); - return 1; - } - } + gflags::ParseCommandLineFlags(&argc, &argv, true); - if (argc < optind + 1) { - android::snapshot::usage(); + if (argc < 2) { + gflags::ShowUsageWithFlags(argv[0]); + return 1; + } + if (FLAGS_order != "" && FLAGS_order != "merge" && FLAGS_order != "reverse-merge") { + std::cerr << "Order must either be \"merge\" or \"reverse-merge\".\n"; return 1; } android::base::InitLogging(argv, android::snapshot::MyLogger); - if (!android::snapshot::Inspect(argv[optind], opt)) { + if (!android::snapshot::Inspect(argv[1])) { return 1; } return 0; From 17421a93ba0c3d36fd1673bb3cd18a6f51149f4e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 15 Jun 2023 11:18:25 -0700 Subject: [PATCH 0120/1487] inspect_cow: Add --show_raw_ops. This bypasses CowReader and shows ops directly from CowParserV2. This will come in handy once CowOperation is versioned and CowReader will be translating from older versions to new versions. Bug: 280529365 Test: inspect_cow Change-Id: Icaeba86105c31c4dfe2812309a4028dd1d0248c0 --- .../libsnapshot_cow/inspect_cow.cpp | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp index 9bb0df344e53..148ecb006e5c 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp @@ -26,6 +26,7 @@ #include #include #include +#include "parser_v2.h" DEFINE_bool(silent, false, "Run silently"); DEFINE_bool(decompress, false, "Attempt to decompress data ops"); @@ -36,10 +37,13 @@ DEFINE_bool(show_merged, false, "If show_ops is true, and order is merge or reverse-merge, include merged ops"); DEFINE_bool(verify_merge_sequence, false, "Verify merge order sequencing"); DEFINE_bool(show_merge_sequence, false, "Show merge order sequence"); +DEFINE_bool(show_raw_ops, false, "Show raw ops directly from the underlying parser"); namespace android { namespace snapshot { +using android::base::borrowed_fd; + void MyLogger(android::base::LogId, android::base::LogSeverity severity, const char*, const char*, unsigned int, const char* message) { if (severity == android::base::ERROR) { @@ -67,6 +71,38 @@ static void ShowBad(CowReader& reader, const struct CowOperation* op) { } } +static bool ShowRawOpStreamV2(borrowed_fd fd, const CowHeader& header) { + CowParserV2 parser; + if (!parser.Parse(fd, header)) { + LOG(ERROR) << "v2 parser failed"; + return false; + } + for (const auto& op : *parser.ops()) { + std::cout << op << "\n"; + if (auto iter = parser.data_loc()->find(op.new_block); iter != parser.data_loc()->end()) { + std::cout << " data loc: " << iter->second << "\n"; + } + } + return true; +} + +static bool ShowRawOpStream(borrowed_fd fd) { + CowHeader header; + if (!ReadCowHeader(fd, &header)) { + LOG(ERROR) << "parse header failed"; + return false; + } + + switch (header.prefix.major_version) { + case 1: + case 2: + return ShowRawOpStreamV2(fd, header); + default: + LOG(ERROR) << "unknown COW version: " << header.prefix.major_version; + return false; + } +} + static bool Inspect(const std::string& path) { android::base::unique_fd fd(open(path.c_str(), O_RDONLY)); if (fd < 0) { @@ -128,6 +164,21 @@ static bool Inspect(const std::string& path) { std::string buffer(header.block_size, '\0'); + if (!FLAGS_silent && FLAGS_show_raw_ops) { + std::cout << "\n"; + std::cout << "Listing raw op stream:\n"; + std::cout << "----------------------\n"; + if (!ShowRawOpStream(fd)) { + return false; + } + } + + if (!FLAGS_silent && FLAGS_show_ops) { + std::cout << "\n"; + std::cout << "Listing op stream:\n"; + std::cout << "------------------\n"; + } + bool success = true; uint64_t xor_ops = 0, copy_ops = 0, replace_ops = 0, zero_ops = 0; while (!iter->AtEnd()) { From d1d5f5ab6988f441780d95ddcb566a2d9030f3d9 Mon Sep 17 00:00:00 2001 From: Roy Luo Date: Tue, 20 Jun 2023 21:44:53 +0000 Subject: [PATCH 0121/1487] fastboot: remove retries on invalid IO iterator in OSX When IOServiceGetMatchingServices returns an invalid iterator, IOIteratorReset doesn't help. Break the loop to prevent being stuck in the reset loop forever. This should be fine as the open_device() call in the upper layer is already doing retries. Bug: 286495045 Test: fastboot update Change-Id: Ia58fa9285640be34aa22cd77e4f58cc9092679a4 --- fastboot/usb_osx.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/fastboot/usb_osx.cpp b/fastboot/usb_osx.cpp index 5b9e5c8af0b5..8b852f567a1f 100644 --- a/fastboot/usb_osx.cpp +++ b/fastboot/usb_osx.cpp @@ -436,12 +436,7 @@ static int init_usb(ifc_match_func callback, std::unique_ptr* handle for (;;) { if (! IOIteratorIsValid(iterator)) { - /* - * Apple documentation advises resetting the iterator if - * it should become invalid during iteration. - */ - IOIteratorReset(iterator); - continue; + break; } io_service_t device = IOIteratorNext(iterator); From e09de2a5ca600d1bd0d0c70f75503c44c034c0bb Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Tue, 20 Jun 2023 23:02:01 +0900 Subject: [PATCH 0122/1487] libdm: don't expect uevent for devices that have never been activated Previously, libdm ensured that uevent will be generated when a dm device is deleted. However, there actually are cases where uevent can't be expected; for example, if an empty dm device is created, but then gets deleted without being activated, then there should be no uevent upon deleting because there actually is nothing to remove from /dev. (dm device gets added to /dev only if it is activated). Actually such a case exists in apexd. As a performance optimization, it proactively creates empty dm devices for all APEXes it scanns. But some of them don't ever get activated if the APEX is already in a dm-verity protected block device (i.e. the pre-instaled APEX is the latest one). In that cases, the empty dm devices are deleted at the end of the boot process as a clean up. The libdm triggered error during the clean up, because there was no uevent generated for the empty dm devices. This has triggered a lot of false alarms to the apex team. This CL fixes this by ensuring uevent only for activate dm devices. If the dm device doesn't show up in /dev, we just delete the in-kernel object and don't expect it to generate uevent for it - which actually is the kernel's behavior. Bug: 286176029 Test: build and run aosp_cf_x86_64_phone. observe dmesg. Before the change: I apexd : Deleting unused dm device com.android.hardware.core_permissions E apexd : Didn't generate uevent for [com.android.hardware.core_permissions] removal W apexd : Failed to delete dm-device com.android.hardware.core_permissions After the change: I apexd : Deleting unused dm device com.android.hardware.core_permissions Change-Id: I52042de7d4d9ab62e6a13428c32a67e13395d1b5 --- fs_mgr/libdm/dm.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index 1e8c14fe2c01..3a9ed9b1a4de 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -106,6 +106,10 @@ bool DeviceMapper::DeleteDevice(const std::string& name, if (!GetDeviceUniquePath(name, &unique_path)) { LOG(ERROR) << "Failed to get unique path for device " << name; } + // Expect to have uevent generated if the unique path actually exists. This may not exist + // if the device was created but has never been activated before it gets deleted. + bool need_uevent = !unique_path.empty() && access(unique_path.c_str(), F_OK) == 0; + struct dm_ioctl io; InitIo(&io, name); @@ -116,7 +120,7 @@ bool DeviceMapper::DeleteDevice(const std::string& name, // Check to make sure appropriate uevent is generated so ueventd will // do the right thing and remove the corresponding device node and symlinks. - if ((io.flags & DM_UEVENT_GENERATED_FLAG) == 0) { + if (need_uevent && (io.flags & DM_UEVENT_GENERATED_FLAG) == 0) { LOG(ERROR) << "Didn't generate uevent for [" << name << "] removal"; return false; } From 55dd32538f16e498465eb7fb49407e5754ee68f3 Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Wed, 21 Jun 2023 16:44:40 +0100 Subject: [PATCH 0123/1487] Introduce microdroid variants of init_first_stage and init_second_stage These variants will compile with -DMICRODROID flag, which will allow us to exclude init features that are not needed for Microdroid, and introduce features that only work in Microdroid. Bug: 287206497 Test: build com.android.virt APEX Change-Id: Ib9af0cfcdf06c70fc39e6e6ac8ef07bb69982969 --- init/Android.bp | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/init/Android.bp b/init/Android.bp index 41c7a953abc2..f62d7b767dfe 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -265,8 +265,8 @@ phony { ], } -cc_binary { - name: "init_second_stage", +cc_defaults { + name: "init_second_stage_defaults", recovery_available: true, stem: "init", defaults: ["init_defaults"], @@ -304,9 +304,22 @@ cc_binary { ], }, }, +} + +cc_binary { + name: "init_second_stage", + defaults: ["init_second_stage_defaults"], +} + +cc_binary { + name: "init_second_stage.microdroid", + defaults: ["init_second_stage_defaults"], + cflags: ["-DMICRODROID"], + installable: false, visibility: ["//packages/modules/Virtualization/microdroid"], } + soong_config_module_type { name: "init_first_stage_cc_defaults", module_type: "cc_defaults", @@ -324,12 +337,8 @@ init_first_stage_cc_defaults { installable: false, }, }, -} -cc_binary { - name: "init_first_stage", stem: "init", - defaults: ["init_first_stage_defaults"], srcs: [ "block_dev_initializer.cpp", @@ -443,6 +452,18 @@ cc_binary { install_in_root: true, } +cc_binary { + name: "init_first_stage", + defaults: ["init_first_stage_defaults"], +} + +cc_binary { + name: "init_first_stage.microdroid", + defaults: ["init_first_stage_defaults"], + cflags: ["-DMICRODROID"], + installable: false, +} + phony { name: "init_system", required: ["init_second_stage"], From 73b983a7d41910031fc54467f39c077243a8d0a9 Mon Sep 17 00:00:00 2001 From: Subrahmanya Manikanta Venkateswarlu Bhamidipati Kameswara Sri Date: Tue, 13 Jun 2023 17:37:29 +0000 Subject: [PATCH 0124/1487] Check AServiceManager_isDeclared before AServiceManager_getService Call AServiceManager_isDeclared before calling AServiceManager_getService to avoid the waiting time when aidl service is not available. Bug: 286969060 Test: run VtsHalGatekeeperTarget (cherry picked from https://android-review.googlesource.com/q/commit:32e1c70f275991ec7fe4d4a2d6e3eeba2a172540) Merged-In: I7d652a546cb810a601338a68950f01d065aea7a5 Change-Id: I7d652a546cb810a601338a68950f01d065aea7a5 --- gatekeeperd/gatekeeperd.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp index eb43a337816b..d2fc65120d5f 100644 --- a/gatekeeperd/gatekeeperd.cpp +++ b/gatekeeperd/gatekeeperd.cpp @@ -74,9 +74,13 @@ class GateKeeperProxy : public BnGateKeeperService { public: GateKeeperProxy() { clear_state_if_needed_done = false; - hw_device = IGatekeeper::getService(); - ::ndk::SpAIBinder ks2Binder(AServiceManager_getService(gatekeeperServiceName)); - aidl_hw_device = AidlIGatekeeper::fromBinder(ks2Binder); + if (AServiceManager_isDeclared(gatekeeperServiceName)) { + ::ndk::SpAIBinder ks2Binder(AServiceManager_waitForService(gatekeeperServiceName)); + aidl_hw_device = AidlIGatekeeper::fromBinder(ks2Binder); + } + if (!aidl_hw_device) { + hw_device = IGatekeeper::getService(); + } is_running_gsi = android::base::GetBoolProperty(android::gsi::kGsiBootedProp, false); if (!aidl_hw_device && !hw_device) { From 7f8fff0360233e5f8af74ba1715e8d7c07342829 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Wed, 21 Jun 2023 14:23:56 -0700 Subject: [PATCH 0125/1487] Moving source class declaration Moving zipImageSource and localImageSource to header file to be used for testing purposes Test: m fastboot Bug: 194686221 Change-Id: I689e73eb0102d3b2cdd0c4fc232b2b60b9022c47 --- fastboot/fastboot.cpp | 16 ---------------- fastboot/fastboot.h | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 287285bcdf73..46786553adbe 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1902,16 +1902,6 @@ void FlashAllTool::FlashImage(const Image& image, const std::string& slot, fastb do_for_partitions(image.part_name, slot, flash, false); } -class ZipImageSource final : public ImageSource { - public: - explicit ZipImageSource(ZipArchiveHandle zip) : zip_(zip) {} - bool ReadFile(const std::string& name, std::vector* out) const override; - unique_fd OpenFile(const std::string& name) const override; - - private: - ZipArchiveHandle zip_; -}; - bool ZipImageSource::ReadFile(const std::string& name, std::vector* out) const { return UnzipToMemory(zip_, name, out); } @@ -1935,12 +1925,6 @@ static void do_update(const char* filename, FlashingPlan* fp) { CloseArchive(zip); } -class LocalImageSource final : public ImageSource { - public: - bool ReadFile(const std::string& name, std::vector* out) const override; - unique_fd OpenFile(const std::string& name) const override; -}; - bool LocalImageSource::ReadFile(const std::string& name, std::vector* out) const { auto path = find_item_given_name(name); if (path.empty()) { diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index abdf63695053..4b48d4a2d3a6 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -40,6 +40,7 @@ #include "result.h" #include "socket.h" #include "util.h" +#include "ziparchive/zip_archive.h" class FastBootTool { public: @@ -122,6 +123,22 @@ class FlashAllTool { FlashingPlan* fp_; }; +class ZipImageSource final : public ImageSource { + public: + explicit ZipImageSource(ZipArchiveHandle zip) : zip_(zip) {} + bool ReadFile(const std::string& name, std::vector* out) const override; + unique_fd OpenFile(const std::string& name) const override; + + private: + ZipArchiveHandle zip_; +}; + +class LocalImageSource final : public ImageSource { + public: + bool ReadFile(const std::string& name, std::vector* out) const override; + unique_fd OpenFile(const std::string& name) const override; +}; + bool should_flash_in_userspace(const std::string& partition_name); bool is_userspace_fastboot(); void do_flash(const char* pname, const char* fname, const bool apply_vbmeta, From 2127b87b706d5be964ba2ee7015cf88eed35bdea Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 21 Jun 2023 18:45:16 -0700 Subject: [PATCH 0126/1487] Only skip checkpointing for freshly formatted ext4 "Do not reboot with commit failure when ext4 userdata is wiped" has caused a regression in cuttlefish on f2fs. Overlay.img rapidly grows to the full userdata size. This updates that CL to only affect partitions marked for block based checkpointing. Test: Boot Cuttlefish, monitor overlay.img for 5 minutes Bug: 285019395 Change-Id: I7d8634e6535ee1531a0df9fb51c6f9c410cbfe92 --- fs_mgr/fs_mgr.cpp | 21 +++++++++++++-------- fs_mgr/include/fs_mgr.h | 3 ++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 742cdfab012a..debcb3e58e08 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -1096,8 +1096,11 @@ static bool SupportsCheckpoint(FstabEntry* entry) { class CheckpointManager { public: - CheckpointManager(int needs_checkpoint = -1, bool metadata_encrypted = false) - : needs_checkpoint_(needs_checkpoint), metadata_encrypted_(metadata_encrypted) {} + CheckpointManager(int needs_checkpoint = -1, bool metadata_encrypted = false, + bool needs_encrypt = false) + : needs_checkpoint_(needs_checkpoint), + metadata_encrypted_(metadata_encrypted), + needs_encrypt_(needs_encrypt) {} bool NeedsCheckpoint() { if (needs_checkpoint_ != UNKNOWN) { @@ -1160,7 +1163,7 @@ class CheckpointManager { } else { LERROR << entry->fs_type << " does not implement checkpoints."; } - } else if (entry->fs_mgr_flags.checkpoint_blk) { + } else if (entry->fs_mgr_flags.checkpoint_blk && !needs_encrypt_) { auto actual_block_device = block_device.empty() ? entry->blk_device : block_device; if (fs_mgr_find_bow_device(actual_block_device).empty()) { unique_fd fd( @@ -1228,6 +1231,7 @@ class CheckpointManager { enum { UNKNOWN = -1, NO = 0, YES = 1 }; int needs_checkpoint_; bool metadata_encrypted_; + bool needs_encrypt_; std::map device_map_; }; @@ -1851,11 +1855,12 @@ int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& alt_mount_po // in turn, and stop on 1st success, or no more match. static int fs_mgr_do_mount_helper(Fstab* fstab, const std::string& n_name, const std::string& n_blk_device, const char* tmp_mount_point, - int needs_checkpoint, bool metadata_encrypted) { + int needs_checkpoint, bool metadata_encrypted, + bool needs_encrypt) { int mount_errors = 0; int first_mount_errno = 0; std::string mount_point; - CheckpointManager checkpoint_manager(needs_checkpoint, metadata_encrypted); + CheckpointManager checkpoint_manager(needs_checkpoint, metadata_encrypted, needs_encrypt); AvbUniquePtr avb_handle(nullptr); if (!fstab) { @@ -1959,13 +1964,13 @@ static int fs_mgr_do_mount_helper(Fstab* fstab, const std::string& n_name, } int fs_mgr_do_mount(Fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point) { - return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, -1, false); + return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, -1, false, false); } int fs_mgr_do_mount(Fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point, - bool needs_checkpoint, bool metadata_encrypted) { + bool needs_checkpoint, bool metadata_encrypted, bool needs_encrypt) { return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, needs_checkpoint, - metadata_encrypted); + metadata_encrypted, needs_encrypt); } /* diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 43de6d84c388..37515d4653c7 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -88,7 +88,8 @@ MountAllResult fs_mgr_mount_all(android::fs_mgr::Fstab* fstab, int mount_mode); int fs_mgr_do_mount(android::fs_mgr::Fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point); int fs_mgr_do_mount(android::fs_mgr::Fstab* fstab, const char* n_name, char* n_blk_device, - char* tmp_mount_point, bool need_cp, bool metadata_encrypted); + char* tmp_mount_point, bool need_cp, bool metadata_encrypted, + bool need_encrypted); int fs_mgr_do_mount_one(const android::fs_mgr::FstabEntry& entry, const std::string& mount_point = ""); int fs_mgr_do_tmpfs_mount(const char *n_name); From 59c22c33a090f98493e3e10a0f7b334d530b54af Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Wed, 21 Jun 2023 14:30:46 -0700 Subject: [PATCH 0127/1487] Removing local image lookup from load_buf The initial logic for adding this in was incorrect. This changed had allowed us to do fastboot flash dts dt.img on command line. But really we should enforce that we pass in the path to the image. This change was added so the command line tool with resemble fastboot-info format which will support flash dts dt.img (situation where image name and partition name don't match). Test: fastboot flash {partition}, fastboot flashall Bug: 194686221 Change-Id: I62f170e14860d865453ab52793e346fe4066c6d4 --- fastboot/fastboot.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 46786553adbe..faaca1d69466 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1076,9 +1076,7 @@ static bool load_buf(const char* fname, struct fastboot_buffer* buf) { unique_fd fd(TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_BINARY))); if (fd == -1) { - auto path = find_item_given_name(fname); - fd = unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_BINARY))); - if (fd == -1) return false; + return false; } struct stat s; From d62002cf06cd01b687d192095eb1514130095fc0 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Wed, 21 Jun 2023 14:27:35 -0700 Subject: [PATCH 0128/1487] Add flag to disable super optimization Adding flag to turn off the super optimization. Makes for easier testing as dynamic partitions flash tasks won't be replaced by one flash super layout task Test: fastboot flashall --disable-super-optimization Bug: 194686221 Change-Id: I9142490ecfe587725872e4b734486d3db1728aa7 --- fastboot/fastboot.cpp | 3 +++ fastboot/fastboot.h | 1 + fastboot/task.cpp | 8 ++++++++ 3 files changed, 12 insertions(+) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index faaca1d69466..42d4f60d0fa9 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -2191,6 +2191,7 @@ int FastBootTool::Main(int argc, char* argv[]) { {"cmdline", required_argument, 0, 0}, {"disable-verification", no_argument, 0, 0}, {"disable-verity", no_argument, 0, 0}, + {"disable-super-optimization", no_argument, 0, 0}, {"force", no_argument, 0, 0}, {"fs-options", required_argument, 0, 0}, {"header-version", required_argument, 0, 0}, @@ -2228,6 +2229,8 @@ int FastBootTool::Main(int argc, char* argv[]) { g_disable_verification = true; } else if (name == "disable-verity") { g_disable_verity = true; + } else if (name == "disable-super-optimization") { + fp->should_optimize_flash_super = false; } else if (name == "force") { fp->force_flash = true; } else if (name == "fs-options") { diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index 4b48d4a2d3a6..ae488d82d2c7 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -96,6 +96,7 @@ struct FlashingPlan { bool wants_set_active = false; bool skip_secondary = false; bool force_flash = false; + bool should_optimize_flash_super = true; std::string slot_override; std::string current_slot; diff --git a/fastboot/task.cpp b/fastboot/task.cpp index 03f9b8942bb2..96b952c94521 100644 --- a/fastboot/task.cpp +++ b/fastboot/task.cpp @@ -124,6 +124,10 @@ std::string FlashSuperLayoutTask::ToString() { std::unique_ptr FlashSuperLayoutTask::Initialize( const FlashingPlan* fp, std::vector& os_images) { + if (!fp->should_optimize_flash_super) { + LOG(INFO) << "super optimization is disabled"; + return nullptr; + } if (!supports_AB()) { LOG(VERBOSE) << "Cannot optimize flashing super on non-AB device"; return nullptr; @@ -188,6 +192,10 @@ std::unique_ptr FlashSuperLayoutTask::Initialize( std::unique_ptr FlashSuperLayoutTask::InitializeFromTasks( const FlashingPlan* fp, std::vector>& tasks) { + if (!fp->should_optimize_flash_super) { + LOG(INFO) << "super optimization is disabled"; + return nullptr; + } if (!supports_AB()) { LOG(VERBOSE) << "Cannot optimize flashing super on non-AB device"; return nullptr; From 5769b268bf23fcbcb74d70b883339745d446847f Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Wed, 21 Jun 2023 14:41:11 -0700 Subject: [PATCH 0129/1487] use FlashingPlan sparse_limit for testing Have get_sparse_limit() return FlashingPlan's sparse limit if set. Used for testing to compare task lists Test: fastboot_test Change-Id: I7ac1eb4dc83a53b3d7aa59aa668a780b4b550664 --- fastboot/fastboot.cpp | 36 ++++++++++++++++++------------------ fastboot/fastboot.h | 5 +++-- fastboot/task.cpp | 14 ++++++++------ fastboot/task.h | 3 ++- 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 42d4f60d0fa9..7a036a25577e 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -104,7 +104,6 @@ static bool g_long_listing = false; // libsparse will support INT_MAX, but this results in large allocations, so // let's keep it at 1GB to avoid memory pressure on the host. static constexpr int64_t RESPARSE_LIMIT = 1 * 1024 * 1024 * 1024; -static uint64_t sparse_limit = 0; static int64_t target_sparse_limit = -1; static unsigned g_base_addr = 0x10000000; @@ -1016,8 +1015,8 @@ static uint64_t get_uint_var(const char* var_name) { return value; } -int64_t get_sparse_limit(int64_t size) { - int64_t limit = sparse_limit; +int64_t get_sparse_limit(int64_t size, const FlashingPlan* fp) { + int64_t limit = int64_t(fp->sparse_limit); if (limit == 0) { // Unlimited, so see what the target device's limit is. // TODO: shouldn't we apply this limit even if you've used -S? @@ -1038,7 +1037,7 @@ int64_t get_sparse_limit(int64_t size) { return 0; } -static bool load_buf_fd(unique_fd fd, struct fastboot_buffer* buf) { +static bool load_buf_fd(unique_fd fd, struct fastboot_buffer* buf, const FlashingPlan* fp) { int64_t sz = get_file_size(fd); if (sz == -1) { return false; @@ -1056,7 +1055,7 @@ static bool load_buf_fd(unique_fd fd, struct fastboot_buffer* buf) { } lseek(fd.get(), 0, SEEK_SET); - int64_t limit = get_sparse_limit(sz); + int64_t limit = get_sparse_limit(sz, fp); buf->fd = std::move(fd); if (limit) { buf->files = load_sparse_files(buf->fd.get(), limit); @@ -1072,7 +1071,7 @@ static bool load_buf_fd(unique_fd fd, struct fastboot_buffer* buf) { return true; } -static bool load_buf(const char* fname, struct fastboot_buffer* buf) { +static bool load_buf(const char* fname, struct fastboot_buffer* buf, const FlashingPlan* fp) { unique_fd fd(TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_BINARY))); if (fd == -1) { @@ -1088,7 +1087,7 @@ static bool load_buf(const char* fname, struct fastboot_buffer* buf) { return false; } - return load_buf_fd(std::move(fd), buf); + return load_buf_fd(std::move(fd), buf, fp); } static void rewrite_vbmeta_buffer(struct fastboot_buffer* buf, bool vbmeta_in_boot) { @@ -1490,12 +1489,12 @@ void do_flash(const char* pname, const char* fname, const bool apply_vbmeta, verbose("Do flash %s %s", pname, fname); struct fastboot_buffer buf; - if (fp->source) { + if (fp && fp->source) { unique_fd fd = fp->source->OpenFile(fname); - if (fd < 0 || !load_buf_fd(std::move(fd), &buf)) { + if (fd < 0 || !load_buf_fd(std::move(fd), &buf, fp)) { die("could not load '%s': %s", fname, strerror(errno)); } - } else if (!load_buf(fname, &buf)) { + } else if (!load_buf(fname, &buf, fp)) { die("cannot load '%s': %s", fname, strerror(errno)); } @@ -1873,7 +1872,7 @@ void FlashAllTool::FlashImages(const std::vectorsource->OpenFile(image->img_name); - if (fd < 0 || !load_buf_fd(std::move(fd), &buf)) { + if (fd < 0 || !load_buf_fd(std::move(fd), &buf, fp_)) { if (image->optional_if_no_image) { continue; } @@ -1982,7 +1981,7 @@ static unsigned fb_get_flash_block_size(std::string name) { void fb_perform_format(const std::string& partition, int skip_if_not_supported, const std::string& type_override, const std::string& size_override, - const unsigned fs_options) { + const unsigned fs_options, const FlashingPlan* fp) { std::string partition_type, partition_size; struct fastboot_buffer buf; @@ -1995,8 +1994,8 @@ void fb_perform_format(const std::string& partition, int skip_if_not_supported, if (target_sparse_limit > 0 && target_sparse_limit < limit) { limit = target_sparse_limit; } - if (sparse_limit > 0 && sparse_limit < limit) { - limit = sparse_limit; + if (fp->sparse_limit > 0 && fp->sparse_limit < limit) { + limit = fp->sparse_limit; } if (fb->GetVar("partition-type:" + partition, &partition_type) != fastboot::SUCCESS) { @@ -2051,7 +2050,7 @@ void fb_perform_format(const std::string& partition, int skip_if_not_supported, if (fd == -1) { die("Cannot open generated image: %s", strerror(errno)); } - if (!load_buf_fd(std::move(fd), &buf)) { + if (!load_buf_fd(std::move(fd), &buf, fp)) { die("Cannot read image: %s", strerror(errno)); } flash_buf(partition, &buf, is_vbmeta_partition(partition)); @@ -2286,7 +2285,7 @@ int FastBootTool::Main(int argc, char* argv[]) { serial = optarg; break; case 'S': - if (!android::base::ParseByteCount(optarg, &sparse_limit)) { + if (!android::base::ParseByteCount(optarg, &fp->sparse_limit)) { die("invalid sparse limit %s", optarg); } break; @@ -2404,7 +2403,8 @@ int FastBootTool::Main(int argc, char* argv[]) { std::string partition = next_arg(&args); auto format = [&](const std::string& partition) { - fb_perform_format(partition, 0, type_override, size_override, fp->fs_options); + fb_perform_format(partition, 0, type_override, size_override, fp->fs_options, + fp.get()); }; do_for_partitions(partition, fp->slot_override, format, true); } else if (command == "signature") { @@ -2498,7 +2498,7 @@ int FastBootTool::Main(int argc, char* argv[]) { std::string filename = next_arg(&args); struct fastboot_buffer buf; - if (!load_buf(filename.c_str(), &buf) || buf.type != FB_BUFFER_FD) { + if (!load_buf(filename.c_str(), &buf, fp.get()) || buf.type != FB_BUFFER_FD) { die("cannot load '%s'", filename.c_str()); } fb->Download(filename, buf.fd.get(), buf.sz); diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index ae488d82d2c7..d4e0ae902d5c 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -97,6 +97,7 @@ struct FlashingPlan { bool skip_secondary = false; bool force_flash = false; bool should_optimize_flash_super = true; + uint64_t sparse_limit = 0; std::string slot_override; std::string current_slot; @@ -176,11 +177,11 @@ Result ParseNetworkSerial(const std::string& seria bool supports_AB(); std::string GetPartitionName(const ImageEntry& entry, const std::string& current_slot_); void flash_partition_files(const std::string& partition, const std::vector& files); -int64_t get_sparse_limit(int64_t size); +int64_t get_sparse_limit(int64_t size, const FlashingPlan* fp); std::vector resparse_file(sparse_file* s, int64_t max_size); bool is_retrofit_device(); bool is_logical(const std::string& partition); void fb_perform_format(const std::string& partition, int skip_if_not_supported, const std::string& type_override, const std::string& size_override, - const unsigned fs_options); + const unsigned fs_options, const FlashingPlan* fp); diff --git a/fastboot/task.cpp b/fastboot/task.cpp index 96b952c94521..c1b9a31a121d 100644 --- a/fastboot/task.cpp +++ b/fastboot/task.cpp @@ -98,18 +98,20 @@ std::string RebootTask::ToString() { FlashSuperLayoutTask::FlashSuperLayoutTask(const std::string& super_name, std::unique_ptr helper, - SparsePtr sparse_layout, uint64_t super_size) + SparsePtr sparse_layout, uint64_t super_size, + const FlashingPlan* fp) : super_name_(super_name), helper_(std::move(helper)), sparse_layout_(std::move(sparse_layout)), - super_size_(super_size) {} + super_size_(super_size), + fp_(fp) {} void FlashSuperLayoutTask::Run() { // Use the reported super partition size as the upper limit, rather than // sparse_file_len, which (1) can fail and (2) is kind of expensive, since // it will map in all of the embedded fds. std::vector files; - if (int limit = get_sparse_limit(super_size_)) { + if (int limit = get_sparse_limit(super_size_, fp_)) { files = resparse_file(sparse_layout_.get(), limit); } else { files.emplace_back(std::move(sparse_layout_)); @@ -187,7 +189,7 @@ std::unique_ptr FlashSuperLayoutTask::Initialize( os_images.erase(std::remove_if(os_images.begin(), os_images.end(), remove_if_callback), os_images.end()); return std::make_unique(super_name, std::move(helper), std::move(s), - partition_size); + partition_size, fp); } std::unique_ptr FlashSuperLayoutTask::InitializeFromTasks( @@ -260,7 +262,7 @@ std::unique_ptr FlashSuperLayoutTask::InitializeFromTasks( tasks.erase(std::remove_if(tasks.begin(), tasks.end(), remove_if_callback), tasks.end()); return std::make_unique(super_name, std::move(helper), std::move(s), - partition_size); + partition_size, fp); } UpdateSuperTask::UpdateSuperTask(const FlashingPlan* fp) : fp_(fp) {} @@ -330,7 +332,7 @@ void WipeTask::Run() { LOG(ERROR) << "wipe task erase failed with partition: " << pname_; return; } - fb_perform_format(pname_, 1, partition_type, "", fp_->fs_options); + fb_perform_format(pname_, 1, partition_type, "", fp_->fs_options, fp_); } std::string WipeTask::ToString() { diff --git a/fastboot/task.h b/fastboot/task.h index 500655dbb7c3..858f43a2e86d 100644 --- a/fastboot/task.h +++ b/fastboot/task.h @@ -82,7 +82,7 @@ class RebootTask : public Task { class FlashSuperLayoutTask : public Task { public: FlashSuperLayoutTask(const std::string& super_name, std::unique_ptr helper, - SparsePtr sparse_layout, uint64_t super_size); + SparsePtr sparse_layout, uint64_t super_size, const FlashingPlan* fp); static std::unique_ptr Initialize(const FlashingPlan* fp, std::vector& os_images); static std::unique_ptr InitializeFromTasks( @@ -96,6 +96,7 @@ class FlashSuperLayoutTask : public Task { std::unique_ptr helper_; SparsePtr sparse_layout_; uint64_t super_size_; + const FlashingPlan* fp_; }; class UpdateSuperTask : public Task { From ba07ef57329c857592c9c10da9e71a5efb4a27aa Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Wed, 21 Jun 2023 14:14:19 -0700 Subject: [PATCH 0130/1487] Change HardcodedFlash to add flashtasks Changing Hardcoded FLash to add flash tasks, also modifying do_flash to download signature data if a source is provided Test: fastboot flashall Change-Id: Ic33bc4076f269d0d48146a3de457a72eedd5e6df --- fastboot/fastboot.cpp | 46 ++++++++++++++++++------------------------- fastboot/fastboot.h | 8 +++++--- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 7a036a25577e..30eb7b5fcd5b 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1494,6 +1494,13 @@ void do_flash(const char* pname, const char* fname, const bool apply_vbmeta, if (fd < 0 || !load_buf_fd(std::move(fd), &buf, fp)) { die("could not load '%s': %s", fname, strerror(errno)); } + std::vector signature_data; + std::string file_string(fname); + if (fp->source->ReadFile(file_string.substr(0, file_string.find('.')) + ".sig", + &signature_data)) { + fb->Download("signature", signature_data); + fb->RawCommand("signature", "installing signature"); + } } else if (!load_buf(fname, &buf, fp)) { die("cannot load '%s': %s", fname, strerror(errno)); } @@ -1780,7 +1787,10 @@ void FlashAllTool::Flash() { CancelSnapshotIfNeeded(); - HardcodedFlash(); + tasks_ = CollectTasksFromImageList(); + for (auto& task : tasks_) { + task->Run(); + } return; } @@ -1832,13 +1842,12 @@ void FlashAllTool::CollectImages() { } } -void FlashAllTool::HardcodedFlash() { +std::vector> FlashAllTool::CollectTasksFromImageList() { CollectImages(); // First flash boot partitions. We allow this to happen either in userspace // or in bootloader fastboot. - FlashImages(boot_images_); - std::vector> tasks; + AddFlashTasks(boot_images_, tasks); if (auto flash_super_task = FlashSuperLayoutTask::Initialize(fp_, os_images_)) { tasks.emplace_back(std::move(flash_super_task)); @@ -1862,13 +1871,12 @@ void FlashAllTool::HardcodedFlash() { tasks.emplace_back(std::make_unique(fp_, image->part_name, "0", slot)); } } - for (auto& i : tasks) { - i->Run(); - } - FlashImages(os_images_); + AddFlashTasks(os_images_, tasks); + return tasks; } -void FlashAllTool::FlashImages(const std::vector>& images) { +void FlashAllTool::AddFlashTasks(const std::vector>& images, + std::vector>& tasks) { for (const auto& [image, slot] : images) { fastboot_buffer buf; unique_fd fd = fp_->source->OpenFile(image->img_name); @@ -1878,27 +1886,11 @@ void FlashAllTool::FlashImages(const std::vectorimg_name.c_str(), strerror(errno)); } - FlashImage(*image, slot, &buf); + tasks.emplace_back(std::make_unique(slot, image->part_name, image->img_name, + is_vbmeta_partition(image->part_name), fp_)); } } -void FlashAllTool::FlashImage(const Image& image, const std::string& slot, fastboot_buffer* buf) { - auto flash = [&, this](const std::string& partition_name) { - std::vector signature_data; - if (fp_->source->ReadFile(image.sig_name, &signature_data)) { - fb->Download("signature", signature_data); - fb->RawCommand("signature", "installing signature"); - } - - if (is_logical(partition_name)) { - fb->ResizePartition(partition_name, std::to_string(buf->image_size)); - } - - flash_buf(partition_name.c_str(), buf, is_vbmeta_partition(partition_name)); - }; - do_for_partitions(image.part_name, slot, flash, false); -} - bool ZipImageSource::ReadFile(const std::string& name, std::vector* out) const { return UnzipToMemory(zip_, name, out); } diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index d4e0ae902d5c..196bd67261ca 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -116,12 +116,14 @@ class FlashAllTool { void CheckRequirements(); void DetermineSlot(); void CollectImages(); - void FlashImages(const std::vector>& images); - void FlashImage(const Image& image, const std::string& slot, fastboot_buffer* buf); - void HardcodedFlash(); + void AddFlashTasks(const std::vector>& images, + std::vector>& tasks); + std::vector> CollectTasksFromImageList(); std::vector boot_images_; std::vector os_images_; + std::vector> tasks_; + FlashingPlan* fp_; }; From 14e7b76dcf917041b2d2e6256c850fe9f987c35d Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 22 Jun 2023 18:56:07 +0000 Subject: [PATCH 0131/1487] init_kill_services_test: wait 120s for apexd This is likely waiting for the Java garbage collector to run, and due to the lockless implementation of BinderProxyNativeData and BpBinder, it's very difficult to efficiently force this object to be deleted. Change-Id: I4df667b9b47327967a43d75664fb506b8704f905 Fixes: 285458033 Test: N/A --- init/test_kill_services/init_kill_services_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/init/test_kill_services/init_kill_services_test.cpp b/init/test_kill_services/init_kill_services_test.cpp index dd4606449621..510ad8aee898 100644 --- a/init/test_kill_services/init_kill_services_test.cpp +++ b/init/test_kill_services/init_kill_services_test.cpp @@ -32,7 +32,7 @@ void ExpectKillingServiceRecovers(const std::string& service_name) { // b/280514080 - servicemanager will restart apexd, and apexd will restart the // system when crashed. This is fine as the device recovers, but it causes // flakes in this test. - ASSERT_TRUE(WaitForProperty("init.svc.apexd", "stopped", 60s)) + ASSERT_TRUE(WaitForProperty("init.svc.apexd", "stopped", 120s)) << (system("cat /dev/binderfs/binder_logs/state"), "apexd won't stop"); LOG(INFO) << "hello " << service_name << "!"; From 0236af54cd25eb3e3f9c7238affc53df07e4b1a2 Mon Sep 17 00:00:00 2001 From: "A. Cody Schuffelen" Date: Thu, 22 Jun 2023 17:06:40 -0700 Subject: [PATCH 0132/1487] Build libsparse and simg2img for Mac OS X as part of Cuttlefish launcher tools Bug: 288493595 Test: m libsparse simg2img Change-Id: I9e0c5c77b9b2b5994bf52e1ca9fdb84bc1523d5d --- libsparse/Android.bp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libsparse/Android.bp b/libsparse/Android.bp index 8e83e1670ecd..5a7d0fc78f7c 100644 --- a/libsparse/Android.bp +++ b/libsparse/Android.bp @@ -28,6 +28,9 @@ cc_library { "libbase", ], target: { + darwin: { + enabled: true, + }, windows: { enabled: true, }, @@ -52,6 +55,11 @@ cc_binary { ], cflags: ["-Werror"], + target: { + darwin: { + enabled: true, + }, + }, } cc_binary { From 27fb5200aad12c597d74af696a6e94cf187b3876 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 15 Jun 2023 12:13:29 -0700 Subject: [PATCH 0133/1487] libsnapshot: Add a helper around CowReader::GetRawBytes. This avoids having to use op->source which will require more work after the new format lands. Bug: 280529365 Test: inspect_cow Change-Id: Iffa18974bb0152dad73d69bb03c683f1aa549031 --- .../libsnapshot/include/libsnapshot/cow_reader.h | 1 + fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp | 14 +++++++++++++- fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp | 4 ++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h index 3890b175434a..f5995015a8a3 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h @@ -133,6 +133,7 @@ class CowReader final : public ICowReader { CowHeader& GetHeader() override { return header_; } + bool GetRawBytes(const CowOperation* op, void* buffer, size_t len, size_t* read); bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read); // Returns the total number of data ops that should be merged. This is the diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp index c2a7fdb39519..4ac89ae4f550 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp @@ -230,7 +230,7 @@ bool CowReader::PrepMergeOps() { size_t seq_len = current_op.data_length / sizeof(uint32_t); merge_op_blocks->resize(merge_op_blocks->size() + seq_len); - if (!GetRawBytes(current_op.source, &merge_op_blocks->data()[num_seqs], + if (!GetRawBytes(¤t_op, &merge_op_blocks->data()[num_seqs], current_op.data_length, &read)) { PLOG(ERROR) << "Failed to read sequence op!"; return false; @@ -516,6 +516,18 @@ std::unique_ptr CowReader::GetMergeOpIter(bool ignore_progress) { ignore_progress ? 0 : merge_op_start_); } +bool CowReader::GetRawBytes(const CowOperation* op, void* buffer, size_t len, size_t* read) { + switch (op->type) { + case kCowSequenceOp: + case kCowReplaceOp: + case kCowXorOp: + return GetRawBytes(op->source, buffer, len, read); + default: + LOG(ERROR) << "Cannot get raw bytes of non-data op: " << *op; + return false; + } +} + bool CowReader::GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read) { // Validate the offset, taking care to acknowledge possible overflow of offset+len. if (offset < header_.prefix.header_size || offset >= fd_size_ - sizeof(CowFooter) || diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp index 148ecb006e5c..a6dee4f43138 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp @@ -57,7 +57,7 @@ static void ShowBad(CowReader& reader, const struct CowOperation* op) { size_t count; auto buffer = std::make_unique(op->data_length); - if (!reader.GetRawBytes(op->source, buffer.get(), op->data_length, &count)) { + if (!reader.GetRawBytes(op, buffer.get(), op->data_length, &count)) { std::cerr << "Failed to read at all!\n"; } else { std::cout << "The Block data is:\n"; @@ -199,7 +199,7 @@ static bool Inspect(const std::string& path) { std::vector merge_op_blocks; size_t seq_len = op->data_length / sizeof(uint32_t); merge_op_blocks.resize(seq_len); - if (!reader.GetRawBytes(op->source, merge_op_blocks.data(), op->data_length, &read)) { + if (!reader.GetRawBytes(op, merge_op_blocks.data(), op->data_length, &read)) { PLOG(ERROR) << "Failed to read sequence op!"; return false; } From 918971c69ea76c5638dd0e9c7334b69d7d628f03 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Fri, 23 Jun 2023 14:16:31 +0900 Subject: [PATCH 0134/1487] No need to read ro.apex.updatable now Bug: 288202251 Test: m Test: device boots Change-Id: I97a3c2fab69489cdfbb5103b148194d7e2ee4d1a --- init/Android.bp | 1 - init/mount_namespace.cpp | 19 +------------------ init/service.cpp | 3 +-- 3 files changed, 2 insertions(+), 21 deletions(-) diff --git a/init/Android.bp b/init/Android.bp index f62d7b767dfe..b4184d0bf0ea 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -228,7 +228,6 @@ cc_library_static { ], whole_static_libs: [ "libcap", - "libcom.android.sysprop.apex", "libcom.android.sysprop.init", ], header_libs: ["bootimg_headers"], diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp index fead371d1e94..5b53d5092227 100644 --- a/init/mount_namespace.cpp +++ b/init/mount_namespace.cpp @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -30,16 +29,6 @@ #include "util.h" -#ifndef RECOVERY -#define ACTIVATE_FLATTENED_APEX 1 -#endif - -#ifdef ACTIVATE_FLATTENED_APEX -#include -#include -#include -#endif // ACTIVATE_FLATTENED_APEX - namespace android { namespace init { namespace { @@ -77,15 +66,9 @@ static std::string GetMountNamespaceId() { return ret; } -static bool IsApexUpdatable() { - static bool updatable = android::sysprop::ApexProperties::updatable().value_or(false); - return updatable; -} - // In case we have two sets of APEXes (non-updatable, updatable), we need two separate mount // namespaces. static bool NeedsTwoMountNamespaces() { - if (!IsApexUpdatable()) return false; if (IsRecoveryMode()) return false; // In microdroid, there's only one set of APEXes in built-in directories include block devices. if (IsMicrodroid()) return false; @@ -193,7 +176,7 @@ bool SetupMountNamespaces() { // Switch the mount namespace of the current process from bootstrap to default OR from default to // bootstrap. If the current mount namespace is neither bootstrap nor default, keep it that way. Result SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespace) { - if (IsRecoveryMode() || !IsApexUpdatable()) { + if (IsRecoveryMode()) { // we don't have multiple namespaces in recovery mode or if apex is not updatable return {}; } diff --git a/init/service.cpp b/init/service.cpp index 29457084b05f..a0b3478c0b41 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -50,7 +50,6 @@ #endif #ifdef INIT_FULL_SOURCES -#include #include #include "mount_namespace.h" @@ -323,7 +322,7 @@ void Service::Reap(const siginfo_t& siginfo) { } #if INIT_FULL_SOURCES - static bool is_apex_updatable = android::sysprop::ApexProperties::updatable().value_or(false); + static bool is_apex_updatable = true; #else static bool is_apex_updatable = false; #endif From c7998f2abbe67595100bb7db4711d3d991b59a45 Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Thu, 22 Jun 2023 08:44:11 -0700 Subject: [PATCH 0135/1487] Remove dead code from fs_mgr Test: Compiles Change-Id: I76402758396b658fc1539f81541b162723b709a2 --- fs_mgr/fs_mgr.cpp | 45 ++++------------------------------------- fs_mgr/include/fs_mgr.h | 8 ++------ 2 files changed, 6 insertions(+), 47 deletions(-) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index debcb3e58e08..7f4959f7f1f8 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -1849,18 +1849,14 @@ int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& alt_mount_po return ret; } -// If tmp_mount_point is non-null, mount the filesystem there. This is for the -// tmp mount we do to check the user password // If multiple fstab entries are to be mounted on "n_name", it will try to mount each one // in turn, and stop on 1st success, or no more match. -static int fs_mgr_do_mount_helper(Fstab* fstab, const std::string& n_name, - const std::string& n_blk_device, const char* tmp_mount_point, - int needs_checkpoint, bool metadata_encrypted, - bool needs_encrypt) { +int fs_mgr_do_mount(Fstab* fstab, const std::string& n_name, const std::string& n_blk_device, + int needs_checkpoint, bool needs_encrypt) { int mount_errors = 0; int first_mount_errno = 0; std::string mount_point; - CheckpointManager checkpoint_manager(needs_checkpoint, metadata_encrypted, needs_encrypt); + CheckpointManager checkpoint_manager(needs_checkpoint, true, needs_encrypt); AvbUniquePtr avb_handle(nullptr); if (!fstab) { @@ -1902,11 +1898,7 @@ static int fs_mgr_do_mount_helper(Fstab* fstab, const std::string& n_name, } // Now mount it where requested */ - if (tmp_mount_point) { - mount_point = tmp_mount_point; - } else { - mount_point = fstab_entry.mount_point; - } + mount_point = fstab_entry.mount_point; int fs_stat = prepare_fs_for_mount(n_blk_device, fstab_entry, mount_point); @@ -1963,35 +1955,6 @@ static int fs_mgr_do_mount_helper(Fstab* fstab, const std::string& n_name, return FS_MGR_DOMNT_FAILED; } -int fs_mgr_do_mount(Fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point) { - return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, -1, false, false); -} - -int fs_mgr_do_mount(Fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point, - bool needs_checkpoint, bool metadata_encrypted, bool needs_encrypt) { - return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, needs_checkpoint, - metadata_encrypted, needs_encrypt); -} - -/* - * mount a tmpfs filesystem at the given point. - * return 0 on success, non-zero on failure. - */ -int fs_mgr_do_tmpfs_mount(const char *n_name) -{ - int ret; - - ret = mount("tmpfs", n_name, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV | MS_NOEXEC, - CRYPTO_TMPFS_OPTIONS); - if (ret < 0) { - LERROR << "Cannot mount tmpfs filesystem at " << n_name; - return -1; - } - - /* Success */ - return 0; -} - static bool ConfigureIoScheduler(const std::string& device_path) { if (!StartsWith(device_path, "/dev/")) { LERROR << __func__ << ": invalid argument " << device_path; diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 37515d4653c7..bc4a7a6c2cf5 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -85,14 +85,10 @@ MountAllResult fs_mgr_mount_all(android::fs_mgr::Fstab* fstab, int mount_mode); #define FS_MGR_DOMNT_FAILED (-1) #define FS_MGR_DOMNT_BUSY (-2) #define FS_MGR_DOMNT_SUCCESS 0 -int fs_mgr_do_mount(android::fs_mgr::Fstab* fstab, const char* n_name, char* n_blk_device, - char* tmp_mount_point); -int fs_mgr_do_mount(android::fs_mgr::Fstab* fstab, const char* n_name, char* n_blk_device, - char* tmp_mount_point, bool need_cp, bool metadata_encrypted, - bool need_encrypted); +int fs_mgr_do_mount(android::fs_mgr::Fstab* fstab, const std::string& n_name, + const std::string& n_blk_device, int needs_checkpoint, bool needs_encrypt); int fs_mgr_do_mount_one(const android::fs_mgr::FstabEntry& entry, const std::string& mount_point = ""); -int fs_mgr_do_tmpfs_mount(const char *n_name); bool fs_mgr_load_verity_state(int* mode); // Returns true if verity is enabled on this particular FstabEntry. bool fs_mgr_is_verity_enabled(const android::fs_mgr::FstabEntry& entry); From 09ccef4961659a724b860a5e166024a65757c15e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Jun 2023 13:47:56 -0700 Subject: [PATCH 0136/1487] libsnapshot: Add helpers for accessing CowOperation offsets. These helpers avoid manual inspection of CowOperation::source, and fiddling with block sizes. Bug: 280529365 Test: cow_api_test vts_libsnapshot_test apply OTA Change-Id: I1ba276e155eb8232a3115066caaa11030c171e11 --- .../include/libsnapshot/cow_reader.h | 13 ++++++++ .../libsnapshot_cow/cow_reader.cpp | 29 ++++++++++------ .../libsnapshot_cow/snapshot_reader.cpp | 14 ++++++-- .../dm-snapshot-merge/snapuserd_worker.cpp | 13 ++++---- .../user-space-merge/snapuserd_dm_user.cpp | 11 ++++--- .../user-space-merge/snapuserd_readahead.cpp | 33 +++++++++++-------- .../user-space-merge/snapuserd_readahead.h | 1 + 7 files changed, 77 insertions(+), 37 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h index f5995015a8a3..d0369e5d7d1b 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h @@ -73,8 +73,20 @@ class ICowReader { // The operation pointer must derive from ICowOpIter::Get(). virtual ssize_t ReadData(const CowOperation* op, void* buffer, size_t buffer_size, size_t ignore_bytes = 0) = 0; + + // Get the absolute source offset, in bytes, of a CowOperation. Returns + // false if the operation does not read from source partitions. + virtual bool GetSourceOffset(const CowOperation* op, uint64_t* source_offset) = 0; }; +static constexpr uint64_t GetBlockFromOffset(const CowHeader& header, uint64_t offset) { + return offset / header.block_size; +} + +static constexpr uint64_t GetBlockRelativeOffset(const CowHeader& header, uint64_t offset) { + return offset % header.block_size; +} + // Iterate over a sequence of COW operations. The iterator is bidirectional. class ICowOpIter { public: @@ -119,6 +131,7 @@ class CowReader final : public ICowReader { bool VerifyMergeOps() override; bool GetFooter(CowFooter* footer) override; bool GetLastLabel(uint64_t* label) override; + bool GetSourceOffset(const CowOperation* op, uint64_t* source_offset) override; // Create a CowOpIter object which contains footer_.num_ops // CowOperation objects. Get() returns a unique CowOperation object diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp index 4ac89ae4f550..cffc8dedbea6 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp @@ -312,19 +312,15 @@ bool CowReader::VerifyMergeOps() { std::unordered_map overwritten_blocks; while (!itr->AtEnd()) { const auto& 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 / header_.block_size; - offset = (op->source % header_.block_size) != 0; - } else { + uint64_t offset; + if (!GetSourceOffset(op, &offset)) { itr->Next(); continue; } + uint64_t block = GetBlockFromOffset(header_, offset); + bool misaligned = (GetBlockRelativeOffset(header_, offset) != 0); + const CowOperation* overwrite = nullptr; if (overwritten_blocks.count(block)) { overwrite = overwritten_blocks[block]; @@ -332,7 +328,7 @@ bool CowReader::VerifyMergeOps() { << op << "\noverwritten by previously merged op:\n" << *overwrite; } - if (offset && overwritten_blocks.count(block + 1)) { + if (misaligned && 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" @@ -622,5 +618,18 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_ return decompressor->Decompress(buffer, buffer_size, header_.block_size, ignore_bytes); } +bool CowReader::GetSourceOffset(const CowOperation* op, uint64_t* source_offset) { + switch (op->type) { + case kCowCopyOp: + *source_offset = op->source * header_.block_size; + return true; + case kCowXorOp: + *source_offset = op->source; + return true; + default: + return false; + } +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp index f9cdbc0febf9..a3e40d962ce7 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp @@ -155,7 +155,12 @@ ssize_t CompressedSnapshotReader::ReadBlock(uint64_t chunk, size_t start_offset, } if (op) { - chunk = op->source; + uint64_t source_offset; + if (!cow_->GetSourceOffset(op, &source_offset)) { + LOG(ERROR) << "GetSourceOffset failed in CompressedSnapshotReader for op: " << *op; + return false; + } + chunk = GetBlockFromOffset(cow_->GetHeader(), source_offset); } off64_t offset = (chunk * block_size_) + start_offset; @@ -179,7 +184,12 @@ ssize_t CompressedSnapshotReader::ReadBlock(uint64_t chunk, size_t start_offset, return -1; } - off64_t offset = op->source + start_offset; + uint64_t source_offset; + if (!cow_->GetSourceOffset(op, &source_offset)) { + LOG(ERROR) << "GetSourceOffset failed in CompressedSnapshotReader for op: " << *op; + return false; + } + off64_t offset = source_offset + start_offset; std::string data(bytes_to_read, '\0'); if (!android::base::ReadFullyAtOffset(fd, data.data(), data.size(), offset)) { 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 922df34247c7..559dcc793e98 100644 --- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp @@ -115,12 +115,13 @@ bool WorkerThread::ReadFromBaseDevice(const CowOperation* cow_op) { SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get payload buffer"; return false; } - SNAP_LOG(DEBUG) << " ReadFromBaseDevice...: new-block: " << cow_op->new_block - << " Source: " << cow_op->source; - uint64_t offset = cow_op->source; - if (cow_op->type == kCowCopyOp) { - offset *= BLOCK_SZ; + uint64_t offset; + if (!reader_->GetSourceOffset(cow_op, &offset)) { + SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get source offset"; + return false; } + SNAP_LOG(DEBUG) << " ReadFromBaseDevice...: new-block: " << cow_op->new_block + << " Source: " << offset; if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SZ, offset)) { SNAP_PLOG(ERROR) << "Copy op failed. Read from backing store: " << backing_store_device_ << "at block :" << offset / BLOCK_SZ << " offset:" << offset % BLOCK_SZ; @@ -508,7 +509,7 @@ int WorkerThread::GetNumberOfMergedOps(void* merged_buffer, void* unmerged_buffe if (read_ahead_buffer_map.find(cow_op->new_block) == read_ahead_buffer_map.end()) { SNAP_LOG(ERROR) << " Block: " << cow_op->new_block << " not found in read-ahead cache" - << " Source: " << cow_op->source; + << " Op: " << *cow_op; return -1; } // If this is a final block merged in the read-ahead buffer diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp index 78582164f175..44b731912692 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp @@ -94,12 +94,13 @@ bool Worker::ReadFromSourceDevice(const CowOperation* cow_op) { SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get payload buffer"; return false; } - SNAP_LOG(DEBUG) << " ReadFromBaseDevice...: new-block: " << cow_op->new_block - << " Source: " << cow_op->source; - uint64_t offset = cow_op->source; - if (cow_op->type == kCowCopyOp) { - offset *= BLOCK_SZ; + uint64_t offset; + if (!reader_->GetSourceOffset(cow_op, &offset)) { + SNAP_LOG(ERROR) << "ReadFromSourceDevice: Failed to get source offset"; + return false; } + SNAP_LOG(DEBUG) << " ReadFromBaseDevice...: new-block: " << cow_op->new_block + << " Op: " << *cow_op; if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SZ, offset)) { std::string op; if (cow_op->type == kCowCopyOp) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp index af2428602962..399f7b81baf0 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp @@ -34,14 +34,17 @@ ReadAhead::ReadAhead(const std::string& cow_device, const std::string& backing_d } void ReadAhead::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; + uint64_t source_offset; + if (!reader_->GetSourceOffset(cow_op, &source_offset)) { + SNAP_LOG(ERROR) << "ReadAhead operation has no source offset: " << *cow_op; + return; } + + uint64_t source_block = GetBlockFromOffset(header_, source_offset); + bool misaligned = (GetBlockRelativeOffset(header_, source_offset) != 0); + if (dest_blocks_.count(cow_op->new_block) || source_blocks_.count(source_block) || - (source_offset > 0 && source_blocks_.count(source_block + 1))) { + (misaligned && source_blocks_.count(source_block + 1))) { overlap_ = true; } @@ -66,11 +69,12 @@ int ReadAhead::PrepareNextReadAhead(uint64_t* source_offset, int* pending_ops, // Get the first block with offset const CowOperation* cow_op = GetRAOpIter(); - *source_offset = cow_op->source; - if (cow_op->type == kCowCopyOp) { - *source_offset *= BLOCK_SZ; - } else if (cow_op->type == kCowXorOp) { + if (!reader_->GetSourceOffset(cow_op, source_offset)) { + SNAP_LOG(ERROR) << "PrepareNextReadAhead operation has no source offset: " << *cow_op; + return nr_consecutive; + } + if (cow_op->type == kCowXorOp) { xor_op_vec.push_back(cow_op); } @@ -88,10 +92,10 @@ int ReadAhead::PrepareNextReadAhead(uint64_t* source_offset, int* pending_ops, */ while (!RAIterDone() && num_ops) { const CowOperation* op = GetRAOpIter(); - uint64_t next_offset = op->source; - - if (cow_op->type == kCowCopyOp) { - next_offset *= BLOCK_SZ; + uint64_t next_offset; + if (!reader_->GetSourceOffset(op, &next_offset)) { + SNAP_LOG(ERROR) << "PrepareNextReadAhead operation has no source offset: " << *cow_op; + break; } // Check for consecutive blocks @@ -803,6 +807,7 @@ bool ReadAhead::InitReader() { if (!reader_->InitForMerge(std::move(cow_fd_))) { return false; } + header_ = reader_->GetHeader(); return true; } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.h index 5e94de005511..d3ba1265bb83 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.h @@ -85,6 +85,7 @@ class ReadAhead { std::shared_ptr snapuserd_; std::unique_ptr reader_; + CowHeader header_; std::unordered_set dest_blocks_; std::unordered_set source_blocks_; From cf311bd00f72a4a36e7857beebc29369b9bcd4a0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 16 Jun 2023 13:59:31 -0700 Subject: [PATCH 0137/1487] libsnapshot: Remove direct accesses of CowOperation::source and compression. For the remaining use cases of accessing CowOperation::source and compression, directly, introduce helper functions, since these fields will be removed in the v3 format. Bug: 280529365 Test: cow_api_test Change-Id: I07031e8968525a7c1314ca45c284e476b51d8104 --- .../libsnapshot/include/libsnapshot/cow_format.h | 7 +++++++ .../libsnapshot/include/libsnapshot/cow_reader.h | 1 + .../libsnapshot/libsnapshot_cow/cow_reader.cpp | 16 ++++++++++------ fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp | 16 ++++++++-------- .../snapuserd/dm-snapshot-merge/snapuserd.cpp | 2 +- .../dm-snapshot-merge/snapuserd_readahead.cpp | 6 +++--- 6 files changed, 30 insertions(+), 18 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h index dd626bc4683a..3a81f6384e7d 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h @@ -166,6 +166,13 @@ static constexpr uint8_t kCowReadAheadNotStarted = 0; static constexpr uint8_t kCowReadAheadInProgress = 1; static constexpr uint8_t kCowReadAheadDone = 2; +static inline uint64_t GetCowOpSourceInfoData(const CowOperation* op) { + return op->source; +} +static inline bool GetCowOpSourceInfoCompression(const CowOperation* op) { + return op->compression != kCowCompressNone; +} + struct CowFooter { CowFooterOperation op; uint8_t unused[64]; diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h index d0369e5d7d1b..f4ce52fa3622 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h @@ -168,6 +168,7 @@ class CowReader final : public ICowReader { bool ParseOps(std::optional label); bool PrepMergeOps(); uint64_t FindNumCopyops(); + uint8_t GetCompressionType(const CowOperation* op); android::base::unique_fd owned_fd_; android::base::borrowed_fd fd_; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp index cffc8dedbea6..489669ac0eae 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp @@ -517,7 +517,7 @@ bool CowReader::GetRawBytes(const CowOperation* op, void* buffer, size_t len, si case kCowSequenceOp: case kCowReplaceOp: case kCowXorOp: - return GetRawBytes(op->source, buffer, len, read); + return GetRawBytes(GetCowOpSourceInfoData(op), buffer, len, read); default: LOG(ERROR) << "Cannot get raw bytes of non-data op: " << *op; return false; @@ -574,10 +574,14 @@ class CowDataStream final : public IByteStream { size_t remaining_; }; +uint8_t CowReader::GetCompressionType(const CowOperation* op) { + return op->compression; +} + ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_size, size_t ignore_bytes) { std::unique_ptr decompressor; - switch (op->compression) { + switch (GetCompressionType(op)) { case kCowCompressNone: break; case kCowCompressGz: @@ -597,7 +601,7 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_ } break; default: - LOG(ERROR) << "Unknown compression type: " << op->compression; + LOG(ERROR) << "Unknown compression type: " << GetCompressionType(op); return -1; } @@ -605,7 +609,7 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_ if (op->type == kCowXorOp) { offset = data_loc_->at(op->new_block); } else { - offset = op->source; + offset = GetCowOpSourceInfoData(op); } if (!decompressor) { @@ -621,10 +625,10 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_ bool CowReader::GetSourceOffset(const CowOperation* op, uint64_t* source_offset) { switch (op->type) { case kCowCopyOp: - *source_offset = op->source * header_.block_size; + *source_offset = GetCowOpSourceInfoData(op) * header_.block_size; return true; case kCowXorOp: - *source_offset = op->source; + *source_offset = GetCowOpSourceInfoData(op); return true; default: return false; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp index 120b2c062c83..31b9a5840934 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp @@ -145,7 +145,7 @@ TEST_F(CowTest, ReadWrite) { op = iter->Get(); ASSERT_EQ(op->type, kCowReplaceOp); - ASSERT_EQ(op->compression, kCowCompressNone); + ASSERT_FALSE(GetCowOpSourceInfoCompression(op)); ASSERT_EQ(op->data_length, 4096); ASSERT_EQ(op->new_block, 50); ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size())); @@ -224,10 +224,10 @@ TEST_F(CowTest, ReadWriteXor) { op = iter->Get(); ASSERT_EQ(op->type, kCowXorOp); - ASSERT_EQ(op->compression, kCowCompressNone); + ASSERT_FALSE(GetCowOpSourceInfoCompression(op)); ASSERT_EQ(op->data_length, 4096); ASSERT_EQ(op->new_block, 50); - ASSERT_EQ(op->source, 98314); // 4096 * 24 + 10 + ASSERT_EQ(GetCowOpSourceInfoData(op), 98314); // 4096 * 24 + 10 ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size())); ASSERT_EQ(sink, data); @@ -283,7 +283,7 @@ TEST_F(CowTest, CompressGz) { std::string sink(data.size(), '\0'); ASSERT_EQ(op->type, kCowReplaceOp); - ASSERT_EQ(op->compression, kCowCompressGz); + ASSERT_TRUE(GetCowOpSourceInfoCompression(op)); ASSERT_EQ(op->data_length, 56); // compressed! ASSERT_EQ(op->new_block, 50); ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size())); @@ -339,7 +339,7 @@ TEST_P(CompressionTest, ThreadedBatchWrites) { total_blocks += 1; std::string sink(xor_data.size(), '\0'); ASSERT_EQ(op->new_block, 50); - ASSERT_EQ(op->source, 98314); // 4096 * 24 + 10 + ASSERT_EQ(GetCowOpSourceInfoData(op), 98314); // 4096 * 24 + 10 ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size())); ASSERT_EQ(sink, xor_data); } @@ -528,7 +528,7 @@ TEST_F(CowTest, ClusterCompressGz) { std::string sink(data.size(), '\0'); ASSERT_EQ(op->type, kCowReplaceOp); - ASSERT_EQ(op->compression, kCowCompressGz); + ASSERT_TRUE(GetCowOpSourceInfoCompression(op)); ASSERT_EQ(op->data_length, 56); // compressed! ASSERT_EQ(op->new_block, 50); ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size())); @@ -546,7 +546,7 @@ TEST_F(CowTest, ClusterCompressGz) { sink = {}; sink.resize(data2.size(), '\0'); - ASSERT_EQ(op->compression, kCowCompressGz); + ASSERT_TRUE(GetCowOpSourceInfoCompression(op)); ASSERT_EQ(op->data_length, 41); // compressed! ASSERT_EQ(op->new_block, 51); ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size())); @@ -591,7 +591,7 @@ TEST_F(CowTest, CompressTwoBlocks) { auto op = iter->Get(); ASSERT_EQ(op->type, kCowReplaceOp); - ASSERT_EQ(op->compression, kCowCompressGz); + ASSERT_TRUE(GetCowOpSourceInfoCompression(op)); ASSERT_EQ(op->new_block, 51); ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size())); } diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp index da9bd113f6d4..978a7f25c510 100644 --- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp +++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp @@ -508,7 +508,7 @@ bool Snapuserd::ReadMetadata() { // the merge of operations are done based on the ops present // in the file. //=========================================================== - uint64_t block_source = cow_op->source; + uint64_t block_source = GetCowOpSourceInfoData(cow_op); if (prev_id.has_value()) { if (dest_blocks.count(cow_op->new_block) || source_blocks.count(block_source)) { break; 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 a32c2bfdd2ac..d5fbe91a32f1 100644 --- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp +++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp @@ -172,7 +172,7 @@ ReadAheadThread::ReadAheadThread(const std::string& cow_device, const std::strin } void ReadAheadThread::CheckOverlap(const CowOperation* cow_op) { - uint64_t source_block = cow_op->source; + uint64_t source_block = GetCowOpSourceInfoData(cow_op); if (dest_blocks_.count(cow_op->new_block) || source_blocks_.count(source_block)) { overlap_ = true; } @@ -191,7 +191,7 @@ void ReadAheadThread::PrepareReadAhead(uint64_t* source_offset, int* pending_ops // Get the first block with offset const CowOperation* cow_op = GetRAOpIter(); CHECK_NE(cow_op, nullptr); - *source_offset = cow_op->source; + *source_offset = GetCowOpSourceInfoData(cow_op); if (cow_op->type == kCowCopyOp) { *source_offset *= BLOCK_SZ; } @@ -210,7 +210,7 @@ void ReadAheadThread::PrepareReadAhead(uint64_t* source_offset, int* pending_ops while (!RAIterDone() && num_ops) { const CowOperation* op = GetRAOpIter(); CHECK_NE(op, nullptr); - uint64_t next_offset = op->source; + uint64_t next_offset = GetCowOpSourceInfoData(op); if (op->type == kCowCopyOp) { next_offset *= BLOCK_SZ; } From d4e035ebc3e4fbabe5065f352d7396abe4840d0d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 21 Jun 2023 09:42:38 -0700 Subject: [PATCH 0138/1487] snapuserd: Make header_response a state variable. header_response is meant to only be true for the first call to WriteDmUserPayload. Codify this by making it a member variable and resetting it on each request. Bug: 288273605 Test: snapuserd_test Change-Id: Ia125f86b7f22f4801be1e0796e8f85540ed5f31f --- .../user-space-merge/snapuserd_core.h | 7 +-- .../user-space-merge/snapuserd_dm_user.cpp | 46 +++++++++---------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index c16ad24a5c69..cf38875848f7 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -120,7 +120,7 @@ class Worker { // Functions interacting with dm-user bool ReadDmUserHeader(); - bool WriteDmUserPayload(size_t size, bool header_response); + bool WriteDmUserPayload(size_t size); bool DmuserReadRequest(); // IO Path @@ -130,11 +130,11 @@ class Worker { bool ReadDataFromBaseDevice(sector_t sector, size_t read_size); bool ReadFromSourceDevice(const CowOperation* cow_op); - bool ReadAlignedSector(sector_t sector, size_t sz, bool header_response); + bool ReadAlignedSector(sector_t sector, size_t sz); bool ReadUnalignedSector(sector_t sector, size_t size); int ReadUnalignedSector(sector_t sector, size_t size, std::vector>::iterator& it); - bool RespondIOError(bool header_response); + bool RespondIOError(); // Processing COW operations bool ProcessCowOp(const CowOperation* cow_op); @@ -176,6 +176,7 @@ class Worker { unique_fd backing_store_fd_; unique_fd base_path_merge_fd_; unique_fd ctrl_fd_; + bool header_response_ = false; std::unique_ptr cowop_iter_; size_t ra_block_index_ = 0; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp index 44b731912692..c505c32a15eb 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp @@ -306,10 +306,10 @@ bool Worker::ReadDmUserHeader() { } // Send the payload/data back to dm-user misc device. -bool Worker::WriteDmUserPayload(size_t size, bool header_response) { +bool Worker::WriteDmUserPayload(size_t size) { size_t payload_size = size; void* buf = bufsink_.GetPayloadBufPtr(); - if (header_response) { + if (header_response_) { payload_size += sizeof(struct dm_user_header); buf = bufsink_.GetBufPtr(); } @@ -319,6 +319,9 @@ bool Worker::WriteDmUserPayload(size_t size, bool header_response) { return false; } + // After the first header is sent in response to a request, we cannot + // send any additional headers. + header_response_ = false; return true; } @@ -341,7 +344,7 @@ bool Worker::ReadDataFromBaseDevice(sector_t sector, size_t read_size) { return true; } -bool Worker::ReadAlignedSector(sector_t sector, size_t sz, bool header_response) { +bool Worker::ReadAlignedSector(sector_t sector, size_t sz) { struct dm_user_header* header = bufsink_.GetHeaderPtr(); size_t remaining_size = sz; std::vector>& chunk_vec = snapuserd_->GetChunkVec(); @@ -389,7 +392,7 @@ bool Worker::ReadAlignedSector(sector_t sector, size_t sz, bool header_response) // Just return the header if it is an error if (header->type == DM_USER_RESP_ERROR) { - if (!RespondIOError(header_response)) { + if (!RespondIOError()) { return false; } @@ -404,14 +407,12 @@ bool Worker::ReadAlignedSector(sector_t sector, size_t sz, bool header_response) } if (!io_error) { - if (!WriteDmUserPayload(total_bytes_read, header_response)) { + if (!WriteDmUserPayload(total_bytes_read)) { return false; } SNAP_LOG(DEBUG) << "WriteDmUserPayload success total_bytes_read: " << total_bytes_read - << " header-response: " << header_response << " remaining_size: " << remaining_size; - header_response = false; remaining_size -= total_bytes_read; } } while (remaining_size > 0 && !io_error); @@ -484,7 +485,6 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { // to any COW ops. In that case, we just need to read from the base // device. bool merge_complete = false; - bool header_response = true; if (it == chunk_vec.end()) { if (chunk_vec.size() > 0) { // I/O request beyond the last mapped sector @@ -503,7 +503,7 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { --it; } } else { - return ReadAlignedSector(sector, size, header_response); + return ReadAlignedSector(sector, size); } loff_t requested_offset = sector << SECTOR_SHIFT; @@ -537,7 +537,7 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { if (ret < 0) { SNAP_LOG(ERROR) << "ReadUnalignedSector failed for sector: " << sector << " size: " << size << " it->sector: " << it->first; - return RespondIOError(header_response); + return RespondIOError(); } remaining_size -= ret; @@ -545,14 +545,13 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { sector += (ret >> SECTOR_SHIFT); // Send the data back - if (!WriteDmUserPayload(total_bytes_read, header_response)) { + if (!WriteDmUserPayload(total_bytes_read)) { return false; } - header_response = false; // If we still have pending data to be processed, this will be aligned I/O if (remaining_size) { - return ReadAlignedSector(sector, remaining_size, header_response); + return ReadAlignedSector(sector, remaining_size); } } else { // This is all about handling I/O request to be routed to base device @@ -566,21 +565,21 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { CHECK(diff_size <= BLOCK_SZ); if (remaining_size < diff_size) { if (!ReadDataFromBaseDevice(sector, remaining_size)) { - return RespondIOError(header_response); + return RespondIOError(); } total_bytes_read += remaining_size; - if (!WriteDmUserPayload(total_bytes_read, header_response)) { + if (!WriteDmUserPayload(total_bytes_read)) { return false; } } else { if (!ReadDataFromBaseDevice(sector, diff_size)) { - return RespondIOError(header_response); + return RespondIOError(); } total_bytes_read += diff_size; - if (!WriteDmUserPayload(total_bytes_read, header_response)) { + if (!WriteDmUserPayload(total_bytes_read)) { return false; } @@ -588,17 +587,16 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { size_t num_sectors_read = (diff_size >> SECTOR_SHIFT); sector += num_sectors_read; CHECK(IsBlockAligned(sector << SECTOR_SHIFT)); - header_response = false; // If we still have pending data to be processed, this will be aligned I/O - return ReadAlignedSector(sector, remaining_size, header_response); + return ReadAlignedSector(sector, remaining_size); } } return true; } -bool Worker::RespondIOError(bool header_response) { +bool Worker::RespondIOError() { struct dm_user_header* header = bufsink_.GetHeaderPtr(); header->type = DM_USER_RESP_ERROR; // This is an issue with the dm-user interface. There @@ -610,9 +608,9 @@ bool Worker::RespondIOError(bool header_response) { // this back to dm-user. // // TODO: Fix the interface - CHECK(header_response); + CHECK(header_response_); - if (!WriteDmUserPayload(0, header_response)) { + if (!WriteDmUserPayload(0)) { return false; } @@ -629,7 +627,7 @@ bool Worker::DmuserReadRequest() { return ReadUnalignedSector(header->sector, header->len); } - return ReadAlignedSector(header->sector, header->len, true); + return ReadAlignedSector(header->sector, header->len); } bool Worker::ProcessIORequest() { @@ -645,6 +643,8 @@ bool Worker::ProcessIORequest() { SNAP_LOG(DEBUG) << "Daemon: msg->type: " << std::dec << header->type; SNAP_LOG(DEBUG) << "Daemon: msg->flags: " << std::dec << header->flags; + header_response_ = true; + switch (header->type) { case DM_USER_REQ_MAP_READ: { if (!DmuserReadRequest()) { From cf16f4d794a7162e6f418d2308741c6b45806f01 Mon Sep 17 00:00:00 2001 From: Jiakai Zhang Date: Fri, 23 Jun 2023 11:04:17 +0100 Subject: [PATCH 0139/1487] Make libfstab available to APEXes. The ART module needs this library to determine whether to put dexopt artifacts in dalvik-cache. Bug: 287958783 Test: m Change-Id: Idf338702d4f54e9c40c0692ea29e7d83e91aca38 --- fs_mgr/Android.bp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp index dd612720f26d..bbd068bacc19 100644 --- a/fs_mgr/Android.bp +++ b/fs_mgr/Android.bp @@ -181,6 +181,10 @@ cc_library_static { ramdisk_available: true, vendor_ramdisk_available: true, recovery_available: true, + apex_available: [ + "//apex_available:anyapex", + "//apex_available:platform", + ], host_supported: true, defaults: ["fs_mgr_defaults"], srcs: [ @@ -206,6 +210,7 @@ cc_library_static { "libbase_headers", "libgsi_headers", ], + min_sdk_version: "31", } cc_binary { From a66adf45aa1458884903fa11679a2996755292c4 Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Mon, 26 Jun 2023 14:55:31 +0100 Subject: [PATCH 0140/1487] init selinux.cpp: use a better way to detect if we run in Microdroid We are now conditionally compiling init binaries & libinit for Microdroid (adding -DMICRODROID=1 cflag), so instead of checking for the presence of the /system/etc/selinux/microdroid_precompiled_sepolicy we can check if the code is compiled for Microdroid. In a follow-up changes we can split the sepolicy loading logic into 2 separate headers (one for Android and one for Microdroid) and include the necessary one depending on the target we compile for. Bug: 287206497 Test: atest MicrodroidTestApp Change-Id: Id9c837d03a96ff9564688d33955ec85094eee487 --- init/Android.bp | 26 +++++++++----- init/fuzzer/Android.bp | 8 ++--- init/selinux.cpp | 77 ++++++++++++++++++++++++++++-------------- init/util.cpp | 5 --- init/util.h | 9 ++++- 5 files changed, 80 insertions(+), 45 deletions(-) diff --git a/init/Android.bp b/init/Android.bp index f62d7b767dfe..06060db5bbeb 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -214,8 +214,8 @@ cc_library_headers { visibility: [":__subpackages__"], } -cc_library_static { - name: "libinit", +cc_defaults { + name: "libinit_defaults", recovery_available: true, defaults: [ "init_defaults", @@ -252,10 +252,17 @@ cc_library_static { ], }, }, - visibility: [ - "//system/apex/apexd", - "//frameworks/native/cmds/installd", - ], +} + +cc_library_static { + name: "libinit", + defaults: ["libinit_defaults"], +} + +cc_library_static { + name: "libinit.microdroid", + defaults: ["libinit_defaults"], + cflags: ["-DMICRODROID=1"], } phony { @@ -270,7 +277,6 @@ cc_defaults { recovery_available: true, stem: "init", defaults: ["init_defaults"], - static_libs: ["libinit"], srcs: ["main.cpp"], symlinks: ["ueventd"], target: { @@ -309,12 +315,14 @@ cc_defaults { cc_binary { name: "init_second_stage", defaults: ["init_second_stage_defaults"], + static_libs: ["libinit"], } cc_binary { name: "init_second_stage.microdroid", defaults: ["init_second_stage_defaults"], - cflags: ["-DMICRODROID"], + static_libs: ["libinit.microdroid"], + cflags: ["-DMICRODROID=1"], installable: false, visibility: ["//packages/modules/Virtualization/microdroid"], } @@ -460,7 +468,7 @@ cc_binary { cc_binary { name: "init_first_stage.microdroid", defaults: ["init_first_stage_defaults"], - cflags: ["-DMICRODROID"], + cflags: ["-DMICRODROID=1"], installable: false, } diff --git a/init/fuzzer/Android.bp b/init/fuzzer/Android.bp index c21a196a97f8..856ca8cf5737 100644 --- a/init/fuzzer/Android.bp +++ b/init/fuzzer/Android.bp @@ -18,7 +18,7 @@ package { } cc_defaults { - name: "libinit_defaults", + name: "libinit_fuzzer_defaults", static_libs: [ "libc++fs", "liblmkd_utils", @@ -53,7 +53,7 @@ cc_fuzz { ], shared_libs: ["libhidlmetadata",], defaults: [ - "libinit_defaults", + "libinit_fuzzer_defaults", ], } @@ -62,7 +62,7 @@ cc_fuzz { srcs: [ "init_property_fuzzer.cpp", ], - defaults: ["libinit_defaults"], + defaults: ["libinit_fuzzer_defaults"], } cc_fuzz { @@ -71,6 +71,6 @@ cc_fuzz { "init_ueventHandler_fuzzer.cpp", ], defaults: [ - "libinit_defaults", + "libinit_fuzzer_defaults", ], } diff --git a/init/selinux.cpp b/init/selinux.cpp index a9365323362f..e0ef4913c938 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -300,8 +300,6 @@ bool GetVendorMappingVersion(std::string* plat_vers) { } constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil"; -constexpr const char kMicrodroidPrecompiledSepolicy[] = - "/system/etc/selinux/microdroid_precompiled_sepolicy"; bool IsSplitPolicyDevice() { return access(plat_policy_cil_file, R_OK) != -1; @@ -499,19 +497,14 @@ bool OpenSplitPolicy(PolicyFile* policy_file) { bool OpenMonolithicPolicy(PolicyFile* policy_file) { static constexpr char kSepolicyFile[] = "/sepolicy"; - // In Microdroid the precompiled sepolicy is located on /system, since there is no vendor code. - // TODO(b/287206497): refactor once we start conditionally compiling init for Microdroid. - std::string monolithic_policy_file = access(kMicrodroidPrecompiledSepolicy, R_OK) == 0 - ? kMicrodroidPrecompiledSepolicy - : kSepolicyFile; - - LOG(INFO) << "Opening SELinux policy from monolithic file " << monolithic_policy_file; - policy_file->fd.reset(open(monolithic_policy_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); + + LOG(INFO) << "Opening SELinux policy from monolithic file " << kSepolicyFile; + policy_file->fd.reset(open(kSepolicyFile, O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); if (policy_file->fd < 0) { PLOG(ERROR) << "Failed to open monolithic SELinux policy"; return false; } - policy_file->path = monolithic_policy_file; + policy_file->path = kSepolicyFile; return true; } @@ -858,6 +851,10 @@ void SelinuxSetupKernelLogging() { } int SelinuxGetVendorAndroidVersion() { + if (IsMicrodroid()) { + // As of now Microdroid doesn't have any vendor code. + return __ANDROID_API_FUTURE__; + } static int vendor_android_version = [] { if (!IsSplitPolicyDevice()) { // If this device does not split sepolicy files, it's not a Treble device and therefore, @@ -961,6 +958,26 @@ static void LoadSelinuxPolicy(std::string& policy) { } } +// Encapsulates steps to load SELinux policy in Microdroid. +// So far the process is very straightforward - just load the precompiled policy from /system. +void LoadSelinuxPolicyMicrodroid() { + constexpr const char kMicrodroidPrecompiledSepolicy[] = + "/system/etc/selinux/microdroid_precompiled_sepolicy"; + + LOG(INFO) << "Opening SELinux policy from " << kMicrodroidPrecompiledSepolicy; + unique_fd policy_fd(open(kMicrodroidPrecompiledSepolicy, O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); + if (policy_fd < 0) { + PLOG(FATAL) << "Failed to open " << kMicrodroidPrecompiledSepolicy; + } + + std::string policy; + if (!android::base::ReadFdToString(policy_fd, &policy)) { + PLOG(FATAL) << "Failed to read policy file: " << kMicrodroidPrecompiledSepolicy; + } + + LoadSelinuxPolicy(policy); +} + // The SELinux setup process is carefully orchestrated around snapuserd. Policy // must be loaded off dynamic partitions, and during an OTA, those partitions // cannot be read without snapuserd. But, with kernel-privileged snapuserd @@ -976,20 +993,9 @@ static void LoadSelinuxPolicy(std::string& policy) { // (5) Re-launch snapuserd and attach it to the dm-user devices from step (2). // // After this sequence, it is safe to enable enforcing mode and continue booting. -int SetupSelinux(char** argv) { - SetStdioToDevNull(argv); - InitKernelLogging(argv); - - if (REBOOT_BOOTLOADER_ON_PANIC) { - InstallRebootSignalHandlers(); - } - - boot_clock::time_point start_time = boot_clock::now(); - +void LoadSelinuxPolicyAndroid() { MountMissingSystemPartitions(); - SelinuxSetupKernelLogging(); - LOG(INFO) << "Opening SELinux policy"; PrepareApexSepolicy(); @@ -1001,9 +1007,8 @@ int SetupSelinux(char** argv) { auto snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded(); if (snapuserd_helper) { - // Kill the old snapused to avoid audit messages. After this we cannot - // read from /system (or other dynamic partitions) until we call - // FinishTransition(). + // Kill the old snapused to avoid audit messages. After this we cannot read from /system + // (or other dynamic partitions) until we call FinishTransition(). snapuserd_helper->StartTransition(); } @@ -1021,6 +1026,26 @@ int SetupSelinux(char** argv) { if (selinux_android_restorecon("/dev/selinux/", SELINUX_ANDROID_RESTORECON_RECURSE) == -1) { PLOG(FATAL) << "restorecon failed of /dev/selinux failed"; } +} + +int SetupSelinux(char** argv) { + SetStdioToDevNull(argv); + InitKernelLogging(argv); + + if (REBOOT_BOOTLOADER_ON_PANIC) { + InstallRebootSignalHandlers(); + } + + boot_clock::time_point start_time = boot_clock::now(); + + SelinuxSetupKernelLogging(); + + // TODO(b/287206497): refactor into different headers to only include what we need. + if (IsMicrodroid()) { + LoadSelinuxPolicyMicrodroid(); + } else { + LoadSelinuxPolicyAndroid(); + } SelinuxSetEnforcement(); diff --git a/init/util.cpp b/init/util.cpp index bc8ea6eafe3f..d0478e80d005 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -732,11 +732,6 @@ void SetDefaultMountNamespaceReady() { is_default_mount_namespace_ready = true; } -bool IsMicrodroid() { - static bool is_microdroid = android::base::GetProperty("ro.hardware", "") == "microdroid"; - return is_microdroid; -} - bool Has32BitAbi() { static bool has = !android::base::GetProperty("ro.product.cpu.abilist32", "").empty(); return has; diff --git a/init/util.h b/init/util.h index e58e70e61788..3f0a4e023f08 100644 --- a/init/util.h +++ b/init/util.h @@ -105,7 +105,14 @@ bool IsRecoveryMode(); bool IsDefaultMountNamespaceReady(); void SetDefaultMountNamespaceReady(); -bool IsMicrodroid(); +inline constexpr bool IsMicrodroid() { +#ifdef MICRODROID + return MICRODROID; +#else + return false; +#endif +} + bool Has32BitAbi(); std::string GetApexNameFromFileName(const std::string& path); From dee32db2491a44e8d12f9f45faefe4ec1ab29156 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Mon, 26 Jun 2023 22:27:09 +0000 Subject: [PATCH 0141/1487] Bindgen 0.65.1 no longer supports size_t-is-usize The flag has been a default, and now is not accepted. Test: Treehugger, m rust Bug: 279198502 Bug: 276464273 Change-Id: Ifdf9968bfcdb278f73cf31ab68bc6b488b39436b --- libstats/pull_rust/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/libstats/pull_rust/Android.bp b/libstats/pull_rust/Android.bp index 85a38f8d77b5..4609e6bc4a81 100644 --- a/libstats/pull_rust/Android.bp +++ b/libstats/pull_rust/Android.bp @@ -28,7 +28,6 @@ rust_bindgen { ], source_stem: "bindings", bindgen_flags: [ - "--size_t-is-usize", "--allowlist-function=AStatsEventList_addStatsEvent", "--allowlist-function=AStatsEvent_.*", "--allowlist-function=AStatsManager_.*", From e2e8f55b81a0b92dcf3f80a6bc40158c76002eeb Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 27 Jun 2023 05:29:20 +0000 Subject: [PATCH 0142/1487] Revert "snapuserd: Make header_response a state variable." This reverts commit d4e035ebc3e4fbabe5065f352d7396abe4840d0d. Reason for revert: Breaks incremental OTAs Change-Id: Ib9703a66b83e08114ca4d11370d669b8bcdf4789 --- .../user-space-merge/snapuserd_core.h | 7 ++- .../user-space-merge/snapuserd_dm_user.cpp | 46 +++++++++---------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index cf38875848f7..c16ad24a5c69 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -120,7 +120,7 @@ class Worker { // Functions interacting with dm-user bool ReadDmUserHeader(); - bool WriteDmUserPayload(size_t size); + bool WriteDmUserPayload(size_t size, bool header_response); bool DmuserReadRequest(); // IO Path @@ -130,11 +130,11 @@ class Worker { bool ReadDataFromBaseDevice(sector_t sector, size_t read_size); bool ReadFromSourceDevice(const CowOperation* cow_op); - bool ReadAlignedSector(sector_t sector, size_t sz); + bool ReadAlignedSector(sector_t sector, size_t sz, bool header_response); bool ReadUnalignedSector(sector_t sector, size_t size); int ReadUnalignedSector(sector_t sector, size_t size, std::vector>::iterator& it); - bool RespondIOError(); + bool RespondIOError(bool header_response); // Processing COW operations bool ProcessCowOp(const CowOperation* cow_op); @@ -176,7 +176,6 @@ class Worker { unique_fd backing_store_fd_; unique_fd base_path_merge_fd_; unique_fd ctrl_fd_; - bool header_response_ = false; std::unique_ptr cowop_iter_; size_t ra_block_index_ = 0; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp index c505c32a15eb..44b731912692 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp @@ -306,10 +306,10 @@ bool Worker::ReadDmUserHeader() { } // Send the payload/data back to dm-user misc device. -bool Worker::WriteDmUserPayload(size_t size) { +bool Worker::WriteDmUserPayload(size_t size, bool header_response) { size_t payload_size = size; void* buf = bufsink_.GetPayloadBufPtr(); - if (header_response_) { + if (header_response) { payload_size += sizeof(struct dm_user_header); buf = bufsink_.GetBufPtr(); } @@ -319,9 +319,6 @@ bool Worker::WriteDmUserPayload(size_t size) { return false; } - // After the first header is sent in response to a request, we cannot - // send any additional headers. - header_response_ = false; return true; } @@ -344,7 +341,7 @@ bool Worker::ReadDataFromBaseDevice(sector_t sector, size_t read_size) { return true; } -bool Worker::ReadAlignedSector(sector_t sector, size_t sz) { +bool Worker::ReadAlignedSector(sector_t sector, size_t sz, bool header_response) { struct dm_user_header* header = bufsink_.GetHeaderPtr(); size_t remaining_size = sz; std::vector>& chunk_vec = snapuserd_->GetChunkVec(); @@ -392,7 +389,7 @@ bool Worker::ReadAlignedSector(sector_t sector, size_t sz) { // Just return the header if it is an error if (header->type == DM_USER_RESP_ERROR) { - if (!RespondIOError()) { + if (!RespondIOError(header_response)) { return false; } @@ -407,12 +404,14 @@ bool Worker::ReadAlignedSector(sector_t sector, size_t sz) { } if (!io_error) { - if (!WriteDmUserPayload(total_bytes_read)) { + if (!WriteDmUserPayload(total_bytes_read, header_response)) { return false; } SNAP_LOG(DEBUG) << "WriteDmUserPayload success total_bytes_read: " << total_bytes_read + << " header-response: " << header_response << " remaining_size: " << remaining_size; + header_response = false; remaining_size -= total_bytes_read; } } while (remaining_size > 0 && !io_error); @@ -485,6 +484,7 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { // to any COW ops. In that case, we just need to read from the base // device. bool merge_complete = false; + bool header_response = true; if (it == chunk_vec.end()) { if (chunk_vec.size() > 0) { // I/O request beyond the last mapped sector @@ -503,7 +503,7 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { --it; } } else { - return ReadAlignedSector(sector, size); + return ReadAlignedSector(sector, size, header_response); } loff_t requested_offset = sector << SECTOR_SHIFT; @@ -537,7 +537,7 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { if (ret < 0) { SNAP_LOG(ERROR) << "ReadUnalignedSector failed for sector: " << sector << " size: " << size << " it->sector: " << it->first; - return RespondIOError(); + return RespondIOError(header_response); } remaining_size -= ret; @@ -545,13 +545,14 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { sector += (ret >> SECTOR_SHIFT); // Send the data back - if (!WriteDmUserPayload(total_bytes_read)) { + if (!WriteDmUserPayload(total_bytes_read, header_response)) { return false; } + header_response = false; // If we still have pending data to be processed, this will be aligned I/O if (remaining_size) { - return ReadAlignedSector(sector, remaining_size); + return ReadAlignedSector(sector, remaining_size, header_response); } } else { // This is all about handling I/O request to be routed to base device @@ -565,21 +566,21 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { CHECK(diff_size <= BLOCK_SZ); if (remaining_size < diff_size) { if (!ReadDataFromBaseDevice(sector, remaining_size)) { - return RespondIOError(); + return RespondIOError(header_response); } total_bytes_read += remaining_size; - if (!WriteDmUserPayload(total_bytes_read)) { + if (!WriteDmUserPayload(total_bytes_read, header_response)) { return false; } } else { if (!ReadDataFromBaseDevice(sector, diff_size)) { - return RespondIOError(); + return RespondIOError(header_response); } total_bytes_read += diff_size; - if (!WriteDmUserPayload(total_bytes_read)) { + if (!WriteDmUserPayload(total_bytes_read, header_response)) { return false; } @@ -587,16 +588,17 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { size_t num_sectors_read = (diff_size >> SECTOR_SHIFT); sector += num_sectors_read; CHECK(IsBlockAligned(sector << SECTOR_SHIFT)); + header_response = false; // If we still have pending data to be processed, this will be aligned I/O - return ReadAlignedSector(sector, remaining_size); + return ReadAlignedSector(sector, remaining_size, header_response); } } return true; } -bool Worker::RespondIOError() { +bool Worker::RespondIOError(bool header_response) { struct dm_user_header* header = bufsink_.GetHeaderPtr(); header->type = DM_USER_RESP_ERROR; // This is an issue with the dm-user interface. There @@ -608,9 +610,9 @@ bool Worker::RespondIOError() { // this back to dm-user. // // TODO: Fix the interface - CHECK(header_response_); + CHECK(header_response); - if (!WriteDmUserPayload(0)) { + if (!WriteDmUserPayload(0, header_response)) { return false; } @@ -627,7 +629,7 @@ bool Worker::DmuserReadRequest() { return ReadUnalignedSector(header->sector, header->len); } - return ReadAlignedSector(header->sector, header->len); + return ReadAlignedSector(header->sector, header->len, true); } bool Worker::ProcessIORequest() { @@ -643,8 +645,6 @@ bool Worker::ProcessIORequest() { SNAP_LOG(DEBUG) << "Daemon: msg->type: " << std::dec << header->type; SNAP_LOG(DEBUG) << "Daemon: msg->flags: " << std::dec << header->flags; - header_response_ = true; - switch (header->type) { case DM_USER_REQ_MAP_READ: { if (!DmuserReadRequest()) { From 0e01ffa6924d7eae988dbf16a2e280c9065cac85 Mon Sep 17 00:00:00 2001 From: Jiakai Zhang Date: Fri, 23 Jun 2023 11:04:17 +0100 Subject: [PATCH 0143/1487] Make libfstab available to APEXes. The ART module needs this library to determine whether to put dexopt artifacts in dalvik-cache. Bug: 287958783 Test: m (cherry picked from https://android-review.googlesource.com/q/commit:cf16f4d794a7162e6f418d2308741c6b45806f01) Merged-In: Idf338702d4f54e9c40c0692ea29e7d83e91aca38 Change-Id: Idf338702d4f54e9c40c0692ea29e7d83e91aca38 --- fs_mgr/Android.bp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp index dd612720f26d..bbd068bacc19 100644 --- a/fs_mgr/Android.bp +++ b/fs_mgr/Android.bp @@ -181,6 +181,10 @@ cc_library_static { ramdisk_available: true, vendor_ramdisk_available: true, recovery_available: true, + apex_available: [ + "//apex_available:anyapex", + "//apex_available:platform", + ], host_supported: true, defaults: ["fs_mgr_defaults"], srcs: [ @@ -206,6 +210,7 @@ cc_library_static { "libbase_headers", "libgsi_headers", ], + min_sdk_version: "31", } cc_binary { From 3e04857a59db6b466465350f1b3bac01b4bce040 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Wed, 21 Jun 2023 15:21:06 -0700 Subject: [PATCH 0144/1487] Changing name of flash super layout OptimizedFlashSuper makes more sense and is more consistent with should-optimize-super Test: m fastboot Change-Id: I6ceb31144dce591e0a53faec68b932112d9cd360 --- fastboot/fastboot.cpp | 7 ++++--- fastboot/task.cpp | 24 ++++++++++++------------ fastboot/task.h | 12 ++++++------ 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 30eb7b5fcd5b..29980afd06f2 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1747,7 +1747,7 @@ std::vector> ParseFastbootInfo(const FlashingPlan* fp, } tasks.emplace_back(std::move(task)); } - if (auto flash_super_task = FlashSuperLayoutTask::InitializeFromTasks(fp, tasks)) { + if (auto flash_super_task = OptimizedFlashSuperTask::InitializeFromTasks(fp, tasks)) { auto it = tasks.begin(); for (size_t i = 0; i < tasks.size(); i++) { if (auto flash_task = tasks[i]->AsFlashTask()) { @@ -1849,7 +1849,7 @@ std::vector> FlashAllTool::CollectTasksFromImageList() { std::vector> tasks; AddFlashTasks(boot_images_, tasks); - if (auto flash_super_task = FlashSuperLayoutTask::Initialize(fp_, os_images_)) { + if (auto flash_super_task = OptimizedFlashSuperTask::Initialize(fp_, os_images_)) { tasks.emplace_back(std::move(flash_super_task)); } else { // Sync the super partition. This will reboot to userspace fastboot if needed. @@ -2205,8 +2205,9 @@ int FastBootTool::Main(int argc, char* argv[]) { {0, 0, 0, 0}}; serial = getenv("FASTBOOT_DEVICE"); - if (!serial) + if (!serial) { serial = getenv("ANDROID_SERIAL"); + } int c; while ((c = getopt_long(argc, argv, "a::hls:S:vw", longopts, &longindex)) != -1) { diff --git a/fastboot/task.cpp b/fastboot/task.cpp index c1b9a31a121d..bf64f0e1e42c 100644 --- a/fastboot/task.cpp +++ b/fastboot/task.cpp @@ -96,17 +96,17 @@ std::string RebootTask::ToString() { return "reboot " + reboot_target_; } -FlashSuperLayoutTask::FlashSuperLayoutTask(const std::string& super_name, - std::unique_ptr helper, - SparsePtr sparse_layout, uint64_t super_size, - const FlashingPlan* fp) +OptimizedFlashSuperTask::OptimizedFlashSuperTask(const std::string& super_name, + std::unique_ptr helper, + SparsePtr sparse_layout, uint64_t super_size, + const FlashingPlan* fp) : super_name_(super_name), helper_(std::move(helper)), sparse_layout_(std::move(sparse_layout)), super_size_(super_size), fp_(fp) {} -void FlashSuperLayoutTask::Run() { +void OptimizedFlashSuperTask::Run() { // Use the reported super partition size as the upper limit, rather than // sparse_file_len, which (1) can fail and (2) is kind of expensive, since // it will map in all of the embedded fds. @@ -120,11 +120,11 @@ void FlashSuperLayoutTask::Run() { // Send the data to the device. flash_partition_files(super_name_, files); } -std::string FlashSuperLayoutTask::ToString() { +std::string OptimizedFlashSuperTask::ToString() { return "optimized-flash-super"; } -std::unique_ptr FlashSuperLayoutTask::Initialize( +std::unique_ptr OptimizedFlashSuperTask::Initialize( const FlashingPlan* fp, std::vector& os_images) { if (!fp->should_optimize_flash_super) { LOG(INFO) << "super optimization is disabled"; @@ -188,11 +188,11 @@ std::unique_ptr FlashSuperLayoutTask::Initialize( }; os_images.erase(std::remove_if(os_images.begin(), os_images.end(), remove_if_callback), os_images.end()); - return std::make_unique(super_name, std::move(helper), std::move(s), - partition_size, fp); + return std::make_unique(super_name, std::move(helper), std::move(s), + partition_size, fp); } -std::unique_ptr FlashSuperLayoutTask::InitializeFromTasks( +std::unique_ptr OptimizedFlashSuperTask::InitializeFromTasks( const FlashingPlan* fp, std::vector>& tasks) { if (!fp->should_optimize_flash_super) { LOG(INFO) << "super optimization is disabled"; @@ -261,8 +261,8 @@ std::unique_ptr FlashSuperLayoutTask::InitializeFromTasks( }; tasks.erase(std::remove_if(tasks.begin(), tasks.end(), remove_if_callback), tasks.end()); - return std::make_unique(super_name, std::move(helper), std::move(s), - partition_size, fp); + return std::make_unique(super_name, std::move(helper), std::move(s), + partition_size, fp); } UpdateSuperTask::UpdateSuperTask(const FlashingPlan* fp) : fp_(fp) {} diff --git a/fastboot/task.h b/fastboot/task.h index 858f43a2e86d..f7c8801f9239 100644 --- a/fastboot/task.h +++ b/fastboot/task.h @@ -79,13 +79,13 @@ class RebootTask : public Task { const FlashingPlan* fp_; }; -class FlashSuperLayoutTask : public Task { +class OptimizedFlashSuperTask : public Task { public: - FlashSuperLayoutTask(const std::string& super_name, std::unique_ptr helper, - SparsePtr sparse_layout, uint64_t super_size, const FlashingPlan* fp); - static std::unique_ptr Initialize(const FlashingPlan* fp, - std::vector& os_images); - static std::unique_ptr InitializeFromTasks( + OptimizedFlashSuperTask(const std::string& super_name, std::unique_ptr helper, + SparsePtr sparse_layout, uint64_t super_size, const FlashingPlan* fp); + static std::unique_ptr Initialize(const FlashingPlan* fp, + std::vector& os_images); + static std::unique_ptr InitializeFromTasks( const FlashingPlan* fp, std::vector>& tasks); using ImageEntry = std::pair; void Run() override; From 786dac3d5068594735ef38f4a51bbb89e9a12003 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Thu, 15 Jun 2023 16:23:56 -0700 Subject: [PATCH 0145/1487] Update some fs_mgr/debuggerd to use getpagesize() instead of PAGE_SIZE Test: th Bug: 279808236 Change-Id: I9d30cfe19d2b1a7d624cc5425e4315dc6e3b2ad2 --- debuggerd/crasher/crasher.cpp | 2 +- debuggerd/debuggerd_test.cpp | 19 +------------------ debuggerd/handler/debuggerd_handler.cpp | 8 ++++---- debuggerd/libdebuggerd/scudo.cpp | 11 ++++++----- fs_mgr/fs_mgr.cpp | 7 ++++--- fs_mgr/fs_mgr_format.cpp | 10 +++++++++- fs_mgr/fs_mgr_overlayfs.cpp | 4 +++- 7 files changed, 28 insertions(+), 33 deletions(-) diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp index 6a19878827f6..12ba502ecf8b 100644 --- a/debuggerd/crasher/crasher.cpp +++ b/debuggerd/crasher/crasher.cpp @@ -148,7 +148,7 @@ noinline void abuse_heap() { noinline void leak() { while (true) { void* mapping = - mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + mmap(nullptr, getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); static_cast(mapping)[0] = 'a'; } } diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index 4cd619337167..52c1c255458d 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -300,24 +300,7 @@ void CrasherTest::AssertDeath(int signo) { } static void ConsumeFd(unique_fd fd, std::string* output) { - constexpr size_t read_length = PAGE_SIZE; - std::string result; - - while (true) { - size_t offset = result.size(); - result.resize(result.size() + PAGE_SIZE); - ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length)); - if (rc == -1) { - FAIL() << "read failed: " << strerror(errno); - } else if (rc == 0) { - result.resize(result.size() - PAGE_SIZE); - break; - } - - result.resize(result.size() - PAGE_SIZE + rc); - } - - *output = std::move(result); + ASSERT_TRUE(android::base::ReadFdToString(fd, output)); } class LogcatCollector { diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp index c6a535ad6d7f..1e5365d3cd53 100644 --- a/debuggerd/handler/debuggerd_handler.cpp +++ b/debuggerd/handler/debuggerd_handler.cpp @@ -721,19 +721,19 @@ void debuggerd_init(debuggerd_callbacks_t* callbacks) { } size_t thread_stack_pages = 8; - void* thread_stack_allocation = mmap(nullptr, PAGE_SIZE * (thread_stack_pages + 2), PROT_NONE, + void* thread_stack_allocation = mmap(nullptr, getpagesize() * (thread_stack_pages + 2), PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (thread_stack_allocation == MAP_FAILED) { fatal_errno("failed to allocate debuggerd thread stack"); } - char* stack = static_cast(thread_stack_allocation) + PAGE_SIZE; - if (mprotect(stack, PAGE_SIZE * thread_stack_pages, PROT_READ | PROT_WRITE) != 0) { + char* stack = static_cast(thread_stack_allocation) + getpagesize(); + if (mprotect(stack, getpagesize() * thread_stack_pages, PROT_READ | PROT_WRITE) != 0) { fatal_errno("failed to mprotect debuggerd thread stack"); } // Stack grows negatively, set it to the last byte in the page... - stack = (stack + thread_stack_pages * PAGE_SIZE - 1); + stack = (stack + thread_stack_pages * getpagesize() - 1); // and align it. stack -= 15; pseudothread_stack = stack; diff --git a/debuggerd/libdebuggerd/scudo.cpp b/debuggerd/libdebuggerd/scudo.cpp index 5a62fe1e762c..837f40612384 100644 --- a/debuggerd/libdebuggerd/scudo.cpp +++ b/debuggerd/libdebuggerd/scudo.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "tombstone.pb.h" @@ -54,21 +55,21 @@ ScudoCrashData::ScudoCrashData(unwindstack::Memory* process_memory, } untagged_fault_addr_ = process_info.untagged_fault_address; - uintptr_t fault_page = untagged_fault_addr_ & ~(PAGE_SIZE - 1); + uintptr_t fault_page = untagged_fault_addr_ & ~(getpagesize() - 1); - uintptr_t memory_begin = fault_page - PAGE_SIZE * 16; + uintptr_t memory_begin = fault_page - getpagesize() * 16; if (memory_begin > fault_page) { return; } - uintptr_t memory_end = fault_page + PAGE_SIZE * 16; + uintptr_t memory_end = fault_page + getpagesize() * 16; if (memory_end < fault_page) { return; } auto memory = std::make_unique(memory_end - memory_begin); - for (auto i = memory_begin; i != memory_end; i += PAGE_SIZE) { - process_memory->ReadFully(i, memory.get() + i - memory_begin, PAGE_SIZE); + for (auto i = memory_begin; i != memory_end; i += getpagesize()) { + process_memory->ReadFully(i, memory.get() + i - memory_begin, getpagesize()); } auto memory_tags = std::make_unique((memory_end - memory_begin) / kTagGranuleSize); diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 7f4959f7f1f8..e568a9bd6b7d 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -613,7 +613,6 @@ static void tune_metadata_csum(const std::string& blk_device, const FstabEntry& // Read the primary superblock from an f2fs filesystem. On failure return // false. If it's not an f2fs filesystem, also set FS_STAT_INVALID_MAGIC. -#define F2FS_BLKSIZE 4096 #define F2FS_SUPER_OFFSET 1024 static bool read_f2fs_superblock(const std::string& blk_device, int* fs_stat) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device.c_str(), O_RDONLY | O_CLOEXEC))); @@ -628,7 +627,9 @@ static bool read_f2fs_superblock(const std::string& blk_device, int* fs_stat) { PERROR << "Can't read '" << blk_device << "' superblock1"; return false; } - if (TEMP_FAILURE_RETRY(pread(fd, &sb2, sizeof(sb2), F2FS_BLKSIZE + F2FS_SUPER_OFFSET)) != + // F2FS only supports block_size=page_size case. So, it is safe to call + // `getpagesize()` and use that as size of super block. + if (TEMP_FAILURE_RETRY(pread(fd, &sb2, sizeof(sb2), getpagesize() + F2FS_SUPER_OFFSET)) != sizeof(sb2)) { PERROR << "Can't read '" << blk_device << "' superblock2"; return false; @@ -652,7 +653,7 @@ bool fs_mgr_is_f2fs(const std::string& blk_device) { return false; } if (sb == cpu_to_le32(F2FS_SUPER_MAGIC)) return true; - if (TEMP_FAILURE_RETRY(pread(fd, &sb, sizeof(sb), F2FS_BLKSIZE + F2FS_SUPER_OFFSET)) != + if (TEMP_FAILURE_RETRY(pread(fd, &sb, sizeof(sb), getpagesize() + F2FS_SUPER_OFFSET)) != sizeof(sb)) { return false; } diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp index 7385f796161a..622f18135dcd 100644 --- a/fs_mgr/fs_mgr_format.cpp +++ b/fs_mgr/fs_mgr_format.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "fs_mgr_priv.h" @@ -68,6 +69,13 @@ static int format_ext4(const std::string& fs_blkdev, const std::string& fs_mnt_p /* Format the partition using the calculated length */ + // EXT4 supports 4K block size on 16K page sizes. A 4K block + // size formatted EXT4 partition will mount fine on both 4K and 16K page + // size kernels. + // However, EXT4 does not support 16K block size on 4K systems. + // If we want the same userspace code to work on both 4k/16k kernels, + // using a hardcoded 4096 block size is a simple solution. Using + // getpagesize() here would work as well, but 4096 is simpler. std::string size_str = std::to_string(dev_sz / 4096); std::vector mke2fs_args = {"/system/bin/mke2fs", "-t", "ext4", "-b", "4096"}; @@ -127,7 +135,7 @@ static int format_f2fs(const std::string& fs_blkdev, uint64_t dev_sz, bool needs /* Format the partition using the calculated length */ - std::string size_str = std::to_string(dev_sz / 4096); + const auto size_str = std::to_string(dev_sz / getpagesize()); std::vector args = {"/system/bin/make_f2fs", "-g", "android"}; if (needs_projid) { diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index f04fc8d2f1b5..01827d6cc576 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -939,7 +939,9 @@ bool MakeScratchFilesystem(const std::string& scratch_device) { auto command = ""s; if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_filesystem_available("f2fs")) { fs_type = "f2fs"; - command = kMkF2fs + " -w 4096 -f -d1 -l" + android::base::Basename(kScratchMountPoint); + command = kMkF2fs + " -w "; + command += std::to_string(getpagesize()); + command += " -f -d1 -l" + android::base::Basename(kScratchMountPoint); } else if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_filesystem_available("ext4")) { fs_type = "ext4"; command = kMkExt4 + " -F -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint; From db15b6f93d828d0c4a9705e845b41d48be22b6f2 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Wed, 3 May 2023 15:28:39 -0700 Subject: [PATCH 0146/1487] Improve error message of libmodprobe Log path of module if that module is not found. Bug: 273752147 Test: th Change-Id: I428a116ee26f97455229df642acbdc1297098a32 --- libmodprobe/libmodprobe.cpp | 5 +++-- libmodprobe/libmodprobe_ext.cpp | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp index 858b9555f2e4..d20b6b10a368 100644 --- a/libmodprobe/libmodprobe.cpp +++ b/libmodprobe/libmodprobe.cpp @@ -230,7 +230,7 @@ void Modprobe::ParseCfg(const std::string& cfg, } std::vector lines = android::base::Split(cfg_contents, "\n"); - for (const std::string line : lines) { + for (const auto& line : lines) { if (line.empty() || line[0] == '#') { continue; } @@ -421,7 +421,8 @@ bool Modprobe::LoadWithAliases(const std::string& module_name, bool strict, } if (strict && !module_loaded) { - LOG(ERROR) << "LoadWithAliases was unable to load " << module_name; + LOG(ERROR) << "LoadWithAliases was unable to load " << module_name + << ", tried: " << android::base::Join(modules_to_load, ", "); return false; } return true; diff --git a/libmodprobe/libmodprobe_ext.cpp b/libmodprobe/libmodprobe_ext.cpp index 94a1dc4e97cd..c4519e3929af 100644 --- a/libmodprobe/libmodprobe_ext.cpp +++ b/libmodprobe/libmodprobe_ext.cpp @@ -84,7 +84,7 @@ bool Modprobe::Rmmod(const std::string& module_name) { } bool Modprobe::ModuleExists(const std::string& module_name) { - struct stat fileStat; + struct stat fileStat {}; if (blocklist_enabled && module_blocklist_.count(module_name)) { LOG(INFO) << "module " << module_name << " is blocklisted"; return false; @@ -95,7 +95,7 @@ bool Modprobe::ModuleExists(const std::string& module_name) { return false; } if (stat(deps.front().c_str(), &fileStat)) { - LOG(INFO) << "module " << module_name << " does not exist"; + PLOG(INFO) << "module " << module_name << " can't be loaded; can't access " << deps.front(); return false; } if (!S_ISREG(fileStat.st_mode)) { From aab4105ef617c9bc806d14a585e59ec7546ff25d Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Tue, 27 Jun 2023 16:06:35 -0700 Subject: [PATCH 0147/1487] Drop const assignment operator. Also, silence cert-oop54-cpp - self-assignment is already handled in VectorImpl class. Bug: 289151149 Test: it builds Change-Id: I8be7714ed53d1515df7cfdf6de6f3c90b3e5cc76 --- libutils/include/utils/Vector.h | 36 +++++++++++---------------------- 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/libutils/include/utils/Vector.h b/libutils/include/utils/Vector.h index be35ea2f04d2..d5db3cb482fe 100644 --- a/libutils/include/utils/Vector.h +++ b/libutils/include/utils/Vector.h @@ -67,13 +67,10 @@ class Vector : private VectorImpl virtual ~Vector(); /*! copy operator */ - const Vector& operator = (const Vector& rhs) const; - Vector& operator = (const Vector& rhs); + Vector& operator=(const Vector& rhs); // NOLINT(cert-oop54-cpp) + Vector& operator=(const SortedVector& rhs); // NOLINT(cert-oop54-cpp) - const Vector& operator = (const SortedVector& rhs) const; - Vector& operator = (const SortedVector& rhs); - - /* + /* * empty the vector */ @@ -248,27 +245,18 @@ Vector::~Vector() { finish_vector(); } -template inline -Vector& Vector::operator = (const Vector& rhs) { - VectorImpl::operator = (rhs); - return *this; -} - -template inline -const Vector& Vector::operator = (const Vector& rhs) const { - VectorImpl::operator = (static_cast(rhs)); - return *this; -} - -template inline -Vector& Vector::operator = (const SortedVector& rhs) { - VectorImpl::operator = (static_cast(rhs)); +template +inline Vector& Vector::operator=(const Vector& rhs) // NOLINT(cert-oop54-cpp) +{ + VectorImpl::operator=(rhs); return *this; } -template inline -const Vector& Vector::operator = (const SortedVector& rhs) const { - VectorImpl::operator = (rhs); +template +inline Vector& Vector::operator=( + const SortedVector& rhs) // NOLINT(cert-oop54-cpp) +{ + VectorImpl::operator=(static_cast(rhs)); return *this; } From d6d8c1f81c63ae95f4bd794060c07558e53dfd67 Mon Sep 17 00:00:00 2001 From: Daeho Jeong Date: Wed, 28 Jun 2023 14:35:30 -0700 Subject: [PATCH 0148/1487] init.rc: set f2fs seq_file_ra_mul to 128 Based on experiments, we fount out 128 (128 x global readahead window size = 16mb) is the optimal multiple to boost up read speeds for the sequentially accessed files with POSIX_FADV_SEQUENTIAL. Bug: 195311558 Test: check the /sys/fs/f2fs//seq_file_ra_mul value Change-Id: I7563ad6e47b9ab76ae7fe36978d0e5970a7490e8 Signed-off-by: Daeho Jeong --- rootdir/init.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 53443685263a..a8b78d5d8025 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -1129,7 +1129,7 @@ on boot write /dev/sys/fs/by-name/userdata/iostat_enable 1 # set readahead multiplier for POSIX_FADV_SEQUENTIAL files - write /dev/sys/fs/by-name/userdata/seq_file_ra_mul 16 + write /dev/sys/fs/by-name/userdata/seq_file_ra_mul 128 # limit discard size to 128MB in order to avoid long IO latency # for filesystem tuning first (dm or sda) From 0c44d8d68d56c7aecb828d8d87fba7dcb114f3d9 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Thu, 29 Jun 2023 09:26:09 -0700 Subject: [PATCH 0149/1487] Make atrace_*_body explicitly a part of API. Also, remove leftover atrace_set_debuggable(bool) symbol. Bug: 289151149 Test: it builds Change-Id: Id9fdf9451567d85b64971a6bb409336b12d3f535 --- libcutils/include/cutils/trace.h | 40 ++++++++++++++++++++++++-------- libcutils/trace-host.cpp | 1 - 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/libcutils/include/cutils/trace.h b/libcutils/include/cutils/trace.h index 3867f346911d..7f57637ec116 100644 --- a/libcutils/include/cutils/trace.h +++ b/libcutils/include/cutils/trace.h @@ -89,6 +89,36 @@ __BEGIN_DECLS #error ATRACE_TAG must be defined to be one of the tags defined in cutils/trace.h #endif +/** Internal implementation detail. Do not use. */ +void atrace_begin_body(const char*); + +/** Internal implementation detail. Do not use. */ +void atrace_end_body(); + +/** Internal implementation detail. Do not use. */ +void atrace_async_begin_body(const char*, int32_t); + +/** Internal implementation detail. Do not use. */ +void atrace_async_end_body(const char*, int32_t); + +/** Internal implementation detail. Do not use. */ +void atrace_async_for_track_begin_body(const char*, const char*, int32_t); + +/** Internal implementation detail. Do not use. */ +void atrace_async_for_track_end_body(const char*, int32_t); + +/** Internal implementation detail. Do not use. */ +void atrace_instant_body(const char*); + +/** Internal implementation detail. Do not use. */ +void atrace_instant_for_track_body(const char*, const char*); + +/** Internal implementation detail. Do not use. */ +void atrace_int_body(const char*, int32_t); + +/** Internal implementation detail. Do not use. */ +void atrace_int64_body(const char*, int64_t); + /** * Opens the trace file for writing and reads the property for initial tags. * The atrace.tags.enableflags property sets the tags to trace. @@ -159,7 +189,6 @@ static inline uint64_t atrace_is_tag_enabled(uint64_t tag) static inline void atrace_begin(uint64_t tag, const char* name) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - void atrace_begin_body(const char*); atrace_begin_body(name); } } @@ -172,7 +201,6 @@ static inline void atrace_begin(uint64_t tag, const char* name) static inline void atrace_end(uint64_t tag) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - void atrace_end_body(); atrace_end_body(); } } @@ -190,7 +218,6 @@ static inline void atrace_async_begin(uint64_t tag, const char* name, int32_t cookie) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - void atrace_async_begin_body(const char*, int32_t); atrace_async_begin_body(name, cookie); } } @@ -203,7 +230,6 @@ static inline void atrace_async_begin(uint64_t tag, const char* name, static inline void atrace_async_end(uint64_t tag, const char* name, int32_t cookie) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - void atrace_async_end_body(const char*, int32_t); atrace_async_end_body(name, cookie); } } @@ -221,7 +247,6 @@ static inline void atrace_async_end(uint64_t tag, const char* name, int32_t cook static inline void atrace_async_for_track_begin(uint64_t tag, const char* track_name, const char* name, int32_t cookie) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - void atrace_async_for_track_begin_body(const char*, const char*, int32_t); atrace_async_for_track_begin_body(track_name, name, cookie); } } @@ -235,7 +260,6 @@ static inline void atrace_async_for_track_begin(uint64_t tag, const char* track_ static inline void atrace_async_for_track_end(uint64_t tag, const char* track_name, int32_t cookie) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - void atrace_async_for_track_end_body(const char*, int32_t); atrace_async_for_track_end_body(track_name, cookie); } } @@ -252,7 +276,6 @@ static inline void atrace_async_for_track_end(uint64_t tag, const char* track_na #define ATRACE_INSTANT(name) atrace_instant(ATRACE_TAG, name) static inline void atrace_instant(uint64_t tag, const char* name) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - void atrace_instant_body(const char*); atrace_instant_body(name); } } @@ -269,7 +292,6 @@ static inline void atrace_instant(uint64_t tag, const char* name) { static inline void atrace_instant_for_track(uint64_t tag, const char* track_name, const char* name) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - void atrace_instant_for_track_body(const char*, const char*); atrace_instant_for_track_body(track_name, name); } } @@ -282,7 +304,6 @@ static inline void atrace_instant_for_track(uint64_t tag, const char* track_name static inline void atrace_int(uint64_t tag, const char* name, int32_t value) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - void atrace_int_body(const char*, int32_t); atrace_int_body(name, value); } } @@ -295,7 +316,6 @@ static inline void atrace_int(uint64_t tag, const char* name, int32_t value) static inline void atrace_int64(uint64_t tag, const char* name, int64_t value) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - void atrace_int64_body(const char*, int64_t); atrace_int64_body(name, value); } } diff --git a/libcutils/trace-host.cpp b/libcutils/trace-host.cpp index e9f58c356d00..2bf57ebbefb2 100644 --- a/libcutils/trace-host.cpp +++ b/libcutils/trace-host.cpp @@ -20,7 +20,6 @@ atomic_bool atrace_is_ready = ATOMIC_VAR_INIT(true); int atrace_marker_fd = -1; uint64_t atrace_enabled_tags = 0; -void atrace_set_debuggable(bool /*debuggable*/) {} void atrace_set_tracing_enabled(bool /*enabled*/) {} void atrace_update_tags() { } void atrace_setup() { } From 29ad6c2aa27384fbd44fbf520528e90ae9ce0c34 Mon Sep 17 00:00:00 2001 From: Jiakai Zhang Date: Wed, 28 Jun 2023 21:28:27 +0100 Subject: [PATCH 0150/1487] Add a variant of ReadFstabFromFile for /proc/mounts. The variant excludes the code that is not for /proc/mounts, and therefore saves code size when being called. Also, after this change, the call to `SkipMountingPartitions` is skipped for /proc/mounts because it is not needed. Bug: 287958783 Test: atest CtsFsMgrTestCases Change-Id: Ie243257fa2e87e666be7decf97ec36c806bc4524 --- fs_mgr/fs_mgr_fstab.cpp | 35 ++++++++++++++++++++---------- fs_mgr/include_fstab/fstab/fstab.h | 1 + 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index c3c10ba62701..c85e83116bde 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -51,6 +51,7 @@ namespace fs_mgr { namespace { constexpr char kDefaultAndroidDtDir[] = "/proc/device-tree/firmware/android"; +constexpr char kProcMountsPath[] = "/proc/mounts"; struct FlagList { const char *name; @@ -699,9 +700,7 @@ void EnableMandatoryFlags(Fstab* fstab) { } } -bool ReadFstabFromFile(const std::string& path, Fstab* fstab_out) { - const bool is_proc_mounts = (path == "/proc/mounts"); - +static bool ReadFstabFromFileCommon(const std::string& path, Fstab* fstab_out) { std::string fstab_str; if (!android::base::ReadFileToString(path, &fstab_str, /* follow_symlinks = */ true)) { PERROR << __FUNCTION__ << "(): failed to read file: '" << path << "'"; @@ -709,11 +708,22 @@ bool ReadFstabFromFile(const std::string& path, Fstab* fstab_out) { } Fstab fstab; - if (!ParseFstabFromString(fstab_str, is_proc_mounts, &fstab)) { + if (!ParseFstabFromString(fstab_str, path == kProcMountsPath, &fstab)) { LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'"; return false; } - if (!is_proc_mounts) { + + EnableMandatoryFlags(&fstab); + + *fstab_out = std::move(fstab); + return true; +} + +bool ReadFstabFromFile(const std::string& path, Fstab* fstab) { + if (!ReadFstabFromFileCommon(path, fstab)) { + return false; + } + if (path != kProcMountsPath) { if (!access(android::gsi::kGsiBootedIndicatorFile, F_OK)) { std::string dsu_slot; if (!android::gsi::GetActiveDsu(&dsu_slot)) { @@ -725,20 +735,23 @@ bool ReadFstabFromFile(const std::string& path, Fstab* fstab_out) { PERROR << __FUNCTION__ << "(): failed to read DSU LP names"; return false; } - TransformFstabForDsu(&fstab, dsu_slot, Split(lp_names, ",")); + TransformFstabForDsu(fstab, dsu_slot, Split(lp_names, ",")); } else if (errno != ENOENT) { PERROR << __FUNCTION__ << "(): failed to access() DSU booted indicator"; return false; } - } - - SkipMountingPartitions(&fstab, false /* verbose */); - EnableMandatoryFlags(&fstab); - *fstab_out = std::move(fstab); + SkipMountingPartitions(fstab, false /* verbose */); + } return true; } +bool ReadFstabFromProcMounts(Fstab* fstab) { + // Don't call `ReadFstabFromFile` because the code for `path != kProcMountsPath` has an extra + // code size cost, even if it's never executed. + return ReadFstabFromFileCommon(kProcMountsPath, fstab); +} + // Returns fstab entries parsed from the device tree if they exist bool ReadFstabFromDt(Fstab* fstab, bool verbose) { std::string fstab_buf = ReadFstabFromDt(); diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h index a914b53bb39c..9cb1546c5aaf 100644 --- a/fs_mgr/include_fstab/fstab/fstab.h +++ b/fs_mgr/include_fstab/fstab/fstab.h @@ -101,6 +101,7 @@ std::string GetFstabPath(); bool SkipMountWithConfig(const std::string& skip_config, Fstab* fstab, bool verbose); bool ReadFstabFromFile(const std::string& path, Fstab* fstab); +bool ReadFstabFromProcMounts(Fstab* fstab); bool ReadFstabFromDt(Fstab* fstab, bool verbose = true); bool ReadDefaultFstab(Fstab* fstab); bool SkipMountingPartitions(Fstab* fstab, bool verbose = false); From 25ec9c4db1345e0b338e333f661bd7ffafa36732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 29 Jun 2023 10:52:40 +0000 Subject: [PATCH 0151/1487] add 'nodad' support to ifc_add_address() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Bug: 242067762 Signed-off-by: Maciej Å»enczykowski Change-Id: I2c022f6af45eac7631213801a89aa270709d4a57 --- libnetutils/ifc_utils.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c index 5999e39ba0fa..7cca105c2817 100644 --- a/libnetutils/ifc_utils.c +++ b/libnetutils/ifc_utils.c @@ -362,14 +362,19 @@ int ifc_act_on_address(int action, const char* name, const char* address, int pr return err->error; } +// Pass bitwise complement of prefix length to disable DAD, ie. use ~64 instead of 64. // Returns zero on success and negative errno on failure. int ifc_add_address(const char *name, const char *address, int prefixlen) { - return ifc_act_on_address(RTM_NEWADDR, name, address, prefixlen, /*nodad*/ false); + bool nodad = (prefixlen < 0); + if (nodad) prefixlen = ~prefixlen; + return ifc_act_on_address(RTM_NEWADDR, name, address, prefixlen, nodad); } // Returns zero on success and negative errno on failure. int ifc_del_address(const char *name, const char * address, int prefixlen) { - return ifc_act_on_address(RTM_DELADDR, name, address, prefixlen, /*nodad*/ false); + bool nodad = (prefixlen < 0); + if (nodad) prefixlen = ~prefixlen; + return ifc_act_on_address(RTM_DELADDR, name, address, prefixlen, nodad); } /* From 379d5c83d58fa78d4d919a26488e83b26fd6639d Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Sat, 1 Jul 2023 00:27:23 +0000 Subject: [PATCH 0152/1487] libutils: rewrite Vector fuzzer It could never have gotten much coverage. Bug: 288741501 Test: libutils_fuzz_vector (2,000,000 iterations) (~60k-100k iterations/s) Change-Id: I6f442642b5a3246dd08784f735db5aad5fd4d398 --- libutils/Vector_fuzz.cpp | 250 ++++++++++++++++++++++++++++++--------- 1 file changed, 191 insertions(+), 59 deletions(-) diff --git a/libutils/Vector_fuzz.cpp b/libutils/Vector_fuzz.cpp index f6df05135a0b..6fd2baf17ca2 100644 --- a/libutils/Vector_fuzz.cpp +++ b/libutils/Vector_fuzz.cpp @@ -13,71 +13,203 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "fuzzer/FuzzedDataProvider.h" -#include "utils/Vector.h" -static constexpr uint16_t MAX_VEC_SIZE = 5000; +#include +#include +#include -void runVectorFuzz(const uint8_t* data, size_t size) { - FuzzedDataProvider dataProvider(data, size); - android::Vector vec = android::Vector(); - // We want to test handling of sizeof as well. - android::Vector vec32 = android::Vector(); +#include - // We're going to generate two vectors of this size - size_t vectorSize = dataProvider.ConsumeIntegralInRange(0, MAX_VEC_SIZE); - vec.setCapacity(vectorSize); - vec32.setCapacity(vectorSize); - for (size_t i = 0; i < vectorSize; i++) { - uint8_t count = dataProvider.ConsumeIntegralInRange(1, 5); - vec.insertAt((uint8_t)i, i, count); - vec32.insertAt((uint32_t)i, i, count); - vec.push_front(i); - vec32.push(i); - } +using android::Vector; - // Now we'll perform some test operations with any remaining data - // Index to perform operations at - size_t index = dataProvider.ConsumeIntegralInRange(0, vec.size()); - std::vector remainingVec = dataProvider.ConsumeRemainingBytes(); - // Insert an array and vector - vec.insertArrayAt(remainingVec.data(), index, remainingVec.size()); - android::Vector vecCopy = android::Vector(vec); - vec.insertVectorAt(vecCopy, index); - // Same thing for 32 bit vector - android::Vector vec32Copy = android::Vector(vec32); - vec32.insertArrayAt(vec32Copy.array(), index, vec32.size()); - vec32.insertVectorAt(vec32Copy, index); - // Replace single character - if (remainingVec.size() > 0) { - vec.replaceAt(remainingVec[0], index); - vec32.replaceAt(static_cast(remainingVec[0]), index); - } else { - vec.replaceAt(0, index); - vec32.replaceAt(0, index); - } - // Add any remaining bytes - for (uint8_t i : remainingVec) { - vec.add(i); - vec32.add(static_cast(i)); +static constexpr uint16_t MAX_VEC_SIZE = 100; +static constexpr bool kLog = false; + +struct NonTrivialDestructor { + NonTrivialDestructor() : mInit(1) {} + ~NonTrivialDestructor() { + LOG_ALWAYS_FATAL_IF(mInit != 1, "mInit should be 1, but it's: %d", mInit); + mInit--; + LOG_ALWAYS_FATAL_IF(mInit != 0, "mInit should be 0, but it's: %d", mInit); } - // Shrink capactiy - vec.setCapacity(remainingVec.size()); - vec32.setCapacity(remainingVec.size()); - // Iterate through each pointer - size_t sum = 0; - for (auto& it : vec) { - sum += it; + + private: + uint8_t mInit; +}; + +template +struct VectorFuzzerData { + Vector vector; + const std::vector&)>> funcs = { + [&](FuzzedDataProvider& provider, Vector& vector) { + (void)provider; + // operator= Vector, still needs for SortedVector + if (kLog) ALOGI("operator="); + vector = testVector(provider); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + (void)provider; + if (kLog) ALOGI("clear"); + vector.clear(); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + (void)provider; + if (kLog) ALOGI("size"); + vector.size(); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + (void)provider; + if (kLog) ALOGI("isEmpty"); + vector.isEmpty(); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + (void)provider; + if (kLog) ALOGI("capacity"); + vector.capacity(); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + size_t vectorSize = provider.ConsumeIntegralInRange(0, MAX_VEC_SIZE); + if (kLog) ALOGI("setCapacity"); + vector.setCapacity(vectorSize); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + size_t vectorSize = provider.ConsumeIntegralInRange(0, MAX_VEC_SIZE); + if (kLog) ALOGI("resize"); + vector.resize(vectorSize); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + (void)provider; + if (kLog) ALOGI("array"); + vector.array(); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + (void)provider; + if (kLog) ALOGI("editArray"); + vector.editArray(); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + if (vector.size() == 0) return; + size_t idx = provider.ConsumeIntegralInRange(0, vector.size() - 1); + if (kLog) ALOGI("operator[]"); + vector[idx]; // returns a const value for Vector + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + if (vector.size() == 0) return; + size_t idx = provider.ConsumeIntegralInRange(0, vector.size() - 1); + if (kLog) ALOGI("itemAt"); + vector.itemAt(idx); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + (void)provider; + if (vector.size() == 0) return; + if (kLog) ALOGI("top"); + vector.top(); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + if (vector.size() == 0) return; + size_t idx = provider.ConsumeIntegralInRange(0, vector.size() - 1); + if (kLog) ALOGI("editItemAt"); + vector.editItemAt(idx); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + (void)provider; + if (vector.size() == 0) return; + if (kLog) ALOGI("editTop"); + vector.editTop() = T{}; + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + uint8_t idx = provider.ConsumeIntegralInRange(0, vector.size()); + Vector vec2 = testVector(provider); + if (vec2.size() == 0) return; // TODO: maybe we should support this? + if (kLog) ALOGI("insertVectorAt %d of size %zu", idx, vec2.size()); + vector.insertVectorAt(vec2, idx); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + if (kLog) ALOGI("appendVector"); + vector.appendVector(testVector(provider)); + }, + // TODO: insertArrayAt + // TODO: appendArray + [&](FuzzedDataProvider& provider, Vector& vector) { + uint8_t idx = provider.ConsumeIntegralInRange(0, vector.size()); + uint8_t numItems = provider.ConsumeIntegralInRange(1, 100); + if (kLog) ALOGI("insertAt"); + vector.insertAt(idx, numItems); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + uint8_t idx = provider.ConsumeIntegralInRange(0, vector.size()); + uint8_t numItems = provider.ConsumeIntegralInRange(1, 100); + if (kLog) ALOGI("insertAt"); + vector.insertAt(T{}, idx, numItems); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + (void)provider; + if (vector.size() == 0) return; + if (kLog) ALOGI("pop"); + vector.pop(); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + (void)provider; + if (kLog) ALOGI("push"); + vector.push(); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + (void)provider; + if (kLog) ALOGI("add"); + vector.add(); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + (void)provider; + if (kLog) ALOGI("add"); + vector.add(T{}); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + uint8_t idx = provider.ConsumeIntegralInRange(0, vector.size() - 1); + if (kLog) ALOGI("replaceAt"); + vector.replaceAt(idx); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + uint8_t idx = provider.ConsumeIntegralInRange(0, vector.size() - 1); + if (kLog) ALOGI("replaceAt"); + vector.replaceAt(T{}, idx); + }, + [&](FuzzedDataProvider& provider, Vector& vector) { + if (vector.size() == 0) return; + uint8_t idx = provider.ConsumeIntegralInRange(0, vector.size() - 1); + if (kLog) ALOGI("remoteItemsAt"); + vector.removeItemsAt(idx); // TODO: different count + }, + // removeAt is alias for removeItemsAt + // TODO: sort + [&](FuzzedDataProvider& provider, Vector& vector) { + (void)provider; + if (kLog) ALOGI("getItemSize"); + vector.getItemSize(); + }, + // TODO: iterators + }; + + Vector testVector(FuzzedDataProvider& provider) { + Vector vec; + size_t vectorSize = provider.ConsumeIntegralInRange(0, MAX_VEC_SIZE); + return vec; } - for (auto& it : vec32) { - sum += it; + + void fuzz(FuzzedDataProvider&& provider) { + while (provider.remaining_bytes()) { + size_t funcIdx = provider.ConsumeIntegralInRange(0, funcs.size() - 1); + funcs[funcIdx](provider, vector); + } } - // Cleanup - vec.clear(); - vecCopy.clear(); - vec32.clear(); - vec32Copy.clear(); -} +}; + extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - runVectorFuzz(data, size); + FuzzedDataProvider provider(data, size); + + provider.PickValueInArray>({ + [&]() { VectorFuzzerData().fuzz(std::move(provider)); }, + [&]() { VectorFuzzerData().fuzz(std::move(provider)); }, + [&]() { VectorFuzzerData().fuzz(std::move(provider)); }, + })(); + return 0; } From 5d4c782b1fedfbf339e7e8a3b5547dd5b29a9526 Mon Sep 17 00:00:00 2001 From: Jiakai Zhang Date: Wed, 28 Jun 2023 21:28:27 +0100 Subject: [PATCH 0153/1487] Add a variant of ReadFstabFromFile for /proc/mounts. The variant excludes the code that is not for /proc/mounts, and therefore saves code size when being called. Also, after this change, the call to `SkipMountingPartitions` is skipped for /proc/mounts because it is not needed. Bug: 287958783 Test: atest CtsFsMgrTestCases (cherry picked from https://android-review.googlesource.com/q/commit:29ad6c2aa27384fbd44fbf520528e90ae9ce0c34) Merged-In: Ie243257fa2e87e666be7decf97ec36c806bc4524 Change-Id: Ie243257fa2e87e666be7decf97ec36c806bc4524 --- fs_mgr/fs_mgr_fstab.cpp | 35 ++++++++++++++++++++---------- fs_mgr/include_fstab/fstab/fstab.h | 1 + 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index 598a3d2ecb4d..da9e45f4e9a2 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -51,6 +51,7 @@ namespace fs_mgr { namespace { constexpr char kDefaultAndroidDtDir[] = "/proc/device-tree/firmware/android"; +constexpr char kProcMountsPath[] = "/proc/mounts"; struct FlagList { const char *name; @@ -697,9 +698,7 @@ void EnableMandatoryFlags(Fstab* fstab) { } } -bool ReadFstabFromFile(const std::string& path, Fstab* fstab_out) { - const bool is_proc_mounts = (path == "/proc/mounts"); - +static bool ReadFstabFromFileCommon(const std::string& path, Fstab* fstab_out) { std::string fstab_str; if (!android::base::ReadFileToString(path, &fstab_str, /* follow_symlinks = */ true)) { PERROR << __FUNCTION__ << "(): failed to read file: '" << path << "'"; @@ -707,11 +706,22 @@ bool ReadFstabFromFile(const std::string& path, Fstab* fstab_out) { } Fstab fstab; - if (!ParseFstabFromString(fstab_str, is_proc_mounts, &fstab)) { + if (!ParseFstabFromString(fstab_str, path == kProcMountsPath, &fstab)) { LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'"; return false; } - if (!is_proc_mounts) { + + EnableMandatoryFlags(&fstab); + + *fstab_out = std::move(fstab); + return true; +} + +bool ReadFstabFromFile(const std::string& path, Fstab* fstab) { + if (!ReadFstabFromFileCommon(path, fstab)) { + return false; + } + if (path != kProcMountsPath) { if (!access(android::gsi::kGsiBootedIndicatorFile, F_OK)) { std::string dsu_slot; if (!android::gsi::GetActiveDsu(&dsu_slot)) { @@ -723,20 +733,23 @@ bool ReadFstabFromFile(const std::string& path, Fstab* fstab_out) { PERROR << __FUNCTION__ << "(): failed to read DSU LP names"; return false; } - TransformFstabForDsu(&fstab, dsu_slot, Split(lp_names, ",")); + TransformFstabForDsu(fstab, dsu_slot, Split(lp_names, ",")); } else if (errno != ENOENT) { PERROR << __FUNCTION__ << "(): failed to access() DSU booted indicator"; return false; } - } - - SkipMountingPartitions(&fstab, false /* verbose */); - EnableMandatoryFlags(&fstab); - *fstab_out = std::move(fstab); + SkipMountingPartitions(fstab, false /* verbose */); + } return true; } +bool ReadFstabFromProcMounts(Fstab* fstab) { + // Don't call `ReadFstabFromFile` because the code for `path != kProcMountsPath` has an extra + // code size cost, even if it's never executed. + return ReadFstabFromFileCommon(kProcMountsPath, fstab); +} + // Returns fstab entries parsed from the device tree if they exist bool ReadFstabFromDt(Fstab* fstab, bool verbose) { std::string fstab_buf = ReadFstabFromDt(); diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h index a914b53bb39c..9cb1546c5aaf 100644 --- a/fs_mgr/include_fstab/fstab/fstab.h +++ b/fs_mgr/include_fstab/fstab/fstab.h @@ -101,6 +101,7 @@ std::string GetFstabPath(); bool SkipMountWithConfig(const std::string& skip_config, Fstab* fstab, bool verbose); bool ReadFstabFromFile(const std::string& path, Fstab* fstab); +bool ReadFstabFromProcMounts(Fstab* fstab); bool ReadFstabFromDt(Fstab* fstab, bool verbose = true); bool ReadDefaultFstab(Fstab* fstab); bool SkipMountingPartitions(Fstab* fstab, bool verbose = false); From 572692c04c618c9f0ee2ec8d2192004396ccfb89 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 21 Jun 2023 09:42:38 -0700 Subject: [PATCH 0154/1487] snapuserd: Make header_response a state variable. header_response is meant to only be true for the first call to WriteDmUserPayload. Codify this by making it a member variable and resetting it on each request. Bug: 288273605 Test: snapuserd_test Change-Id: Ic92f5932391a607b63345d579f379d12e78e8f6c --- .../user-space-merge/snapuserd_core.h | 7 +-- .../user-space-merge/snapuserd_dm_user.cpp | 46 +++++++++---------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index c16ad24a5c69..cf38875848f7 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -120,7 +120,7 @@ class Worker { // Functions interacting with dm-user bool ReadDmUserHeader(); - bool WriteDmUserPayload(size_t size, bool header_response); + bool WriteDmUserPayload(size_t size); bool DmuserReadRequest(); // IO Path @@ -130,11 +130,11 @@ class Worker { bool ReadDataFromBaseDevice(sector_t sector, size_t read_size); bool ReadFromSourceDevice(const CowOperation* cow_op); - bool ReadAlignedSector(sector_t sector, size_t sz, bool header_response); + bool ReadAlignedSector(sector_t sector, size_t sz); bool ReadUnalignedSector(sector_t sector, size_t size); int ReadUnalignedSector(sector_t sector, size_t size, std::vector>::iterator& it); - bool RespondIOError(bool header_response); + bool RespondIOError(); // Processing COW operations bool ProcessCowOp(const CowOperation* cow_op); @@ -176,6 +176,7 @@ class Worker { unique_fd backing_store_fd_; unique_fd base_path_merge_fd_; unique_fd ctrl_fd_; + bool header_response_ = false; std::unique_ptr cowop_iter_; size_t ra_block_index_ = 0; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp index 44b731912692..c505c32a15eb 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp @@ -306,10 +306,10 @@ bool Worker::ReadDmUserHeader() { } // Send the payload/data back to dm-user misc device. -bool Worker::WriteDmUserPayload(size_t size, bool header_response) { +bool Worker::WriteDmUserPayload(size_t size) { size_t payload_size = size; void* buf = bufsink_.GetPayloadBufPtr(); - if (header_response) { + if (header_response_) { payload_size += sizeof(struct dm_user_header); buf = bufsink_.GetBufPtr(); } @@ -319,6 +319,9 @@ bool Worker::WriteDmUserPayload(size_t size, bool header_response) { return false; } + // After the first header is sent in response to a request, we cannot + // send any additional headers. + header_response_ = false; return true; } @@ -341,7 +344,7 @@ bool Worker::ReadDataFromBaseDevice(sector_t sector, size_t read_size) { return true; } -bool Worker::ReadAlignedSector(sector_t sector, size_t sz, bool header_response) { +bool Worker::ReadAlignedSector(sector_t sector, size_t sz) { struct dm_user_header* header = bufsink_.GetHeaderPtr(); size_t remaining_size = sz; std::vector>& chunk_vec = snapuserd_->GetChunkVec(); @@ -389,7 +392,7 @@ bool Worker::ReadAlignedSector(sector_t sector, size_t sz, bool header_response) // Just return the header if it is an error if (header->type == DM_USER_RESP_ERROR) { - if (!RespondIOError(header_response)) { + if (!RespondIOError()) { return false; } @@ -404,14 +407,12 @@ bool Worker::ReadAlignedSector(sector_t sector, size_t sz, bool header_response) } if (!io_error) { - if (!WriteDmUserPayload(total_bytes_read, header_response)) { + if (!WriteDmUserPayload(total_bytes_read)) { return false; } SNAP_LOG(DEBUG) << "WriteDmUserPayload success total_bytes_read: " << total_bytes_read - << " header-response: " << header_response << " remaining_size: " << remaining_size; - header_response = false; remaining_size -= total_bytes_read; } } while (remaining_size > 0 && !io_error); @@ -484,7 +485,6 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { // to any COW ops. In that case, we just need to read from the base // device. bool merge_complete = false; - bool header_response = true; if (it == chunk_vec.end()) { if (chunk_vec.size() > 0) { // I/O request beyond the last mapped sector @@ -503,7 +503,7 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { --it; } } else { - return ReadAlignedSector(sector, size, header_response); + return ReadAlignedSector(sector, size); } loff_t requested_offset = sector << SECTOR_SHIFT; @@ -537,7 +537,7 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { if (ret < 0) { SNAP_LOG(ERROR) << "ReadUnalignedSector failed for sector: " << sector << " size: " << size << " it->sector: " << it->first; - return RespondIOError(header_response); + return RespondIOError(); } remaining_size -= ret; @@ -545,14 +545,13 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { sector += (ret >> SECTOR_SHIFT); // Send the data back - if (!WriteDmUserPayload(total_bytes_read, header_response)) { + if (!WriteDmUserPayload(total_bytes_read)) { return false; } - header_response = false; // If we still have pending data to be processed, this will be aligned I/O if (remaining_size) { - return ReadAlignedSector(sector, remaining_size, header_response); + return ReadAlignedSector(sector, remaining_size); } } else { // This is all about handling I/O request to be routed to base device @@ -566,21 +565,21 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { CHECK(diff_size <= BLOCK_SZ); if (remaining_size < diff_size) { if (!ReadDataFromBaseDevice(sector, remaining_size)) { - return RespondIOError(header_response); + return RespondIOError(); } total_bytes_read += remaining_size; - if (!WriteDmUserPayload(total_bytes_read, header_response)) { + if (!WriteDmUserPayload(total_bytes_read)) { return false; } } else { if (!ReadDataFromBaseDevice(sector, diff_size)) { - return RespondIOError(header_response); + return RespondIOError(); } total_bytes_read += diff_size; - if (!WriteDmUserPayload(total_bytes_read, header_response)) { + if (!WriteDmUserPayload(total_bytes_read)) { return false; } @@ -588,17 +587,16 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { size_t num_sectors_read = (diff_size >> SECTOR_SHIFT); sector += num_sectors_read; CHECK(IsBlockAligned(sector << SECTOR_SHIFT)); - header_response = false; // If we still have pending data to be processed, this will be aligned I/O - return ReadAlignedSector(sector, remaining_size, header_response); + return ReadAlignedSector(sector, remaining_size); } } return true; } -bool Worker::RespondIOError(bool header_response) { +bool Worker::RespondIOError() { struct dm_user_header* header = bufsink_.GetHeaderPtr(); header->type = DM_USER_RESP_ERROR; // This is an issue with the dm-user interface. There @@ -610,9 +608,9 @@ bool Worker::RespondIOError(bool header_response) { // this back to dm-user. // // TODO: Fix the interface - CHECK(header_response); + CHECK(header_response_); - if (!WriteDmUserPayload(0, header_response)) { + if (!WriteDmUserPayload(0)) { return false; } @@ -629,7 +627,7 @@ bool Worker::DmuserReadRequest() { return ReadUnalignedSector(header->sector, header->len); } - return ReadAlignedSector(header->sector, header->len, true); + return ReadAlignedSector(header->sector, header->len); } bool Worker::ProcessIORequest() { @@ -645,6 +643,8 @@ bool Worker::ProcessIORequest() { SNAP_LOG(DEBUG) << "Daemon: msg->type: " << std::dec << header->type; SNAP_LOG(DEBUG) << "Daemon: msg->flags: " << std::dec << header->flags; + header_response_ = true; + switch (header->type) { case DM_USER_REQ_MAP_READ: { if (!DmuserReadRequest()) { From b6df0138e5eb6052e16d2cd63045332c68b14cf0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 21 Jun 2023 12:40:12 -0700 Subject: [PATCH 0155/1487] snapuserd: Return void from RespondIOError. RespondIOError could return "true" which is not the correct value for its callers, usually. However since RespondIOError is not specifically needed anymore, we can also avoid calling it in most places. This also fixes a bug where ReadUnalignedSector's return value was implicitly converted to boolean. Bug: 288273605 Test: snapuserd_test Change-Id: I62140b2b05d0f9f53cb669c5c0d7e0ffc7f4c9a1 --- .../user-space-merge/snapuserd_core.h | 2 +- .../user-space-merge/snapuserd_dm_user.cpp | 23 ++++++------------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index cf38875848f7..7cffc1c4bf47 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -134,7 +134,7 @@ class Worker { bool ReadUnalignedSector(sector_t sector, size_t size); int ReadUnalignedSector(sector_t sector, size_t size, std::vector>::iterator& it); - bool RespondIOError(); + void RespondIOError(); // Processing COW operations bool ProcessCowOp(const CowOperation* cow_op); diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp index c505c32a15eb..0eb2a14fe620 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp @@ -392,10 +392,7 @@ bool Worker::ReadAlignedSector(sector_t sector, size_t sz) { // Just return the header if it is an error if (header->type == DM_USER_RESP_ERROR) { - if (!RespondIOError()) { - return false; - } - + RespondIOError(); io_error = true; break; } @@ -537,7 +534,7 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { if (ret < 0) { SNAP_LOG(ERROR) << "ReadUnalignedSector failed for sector: " << sector << " size: " << size << " it->sector: " << it->first; - return RespondIOError(); + return false; } remaining_size -= ret; @@ -565,7 +562,7 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { CHECK(diff_size <= BLOCK_SZ); if (remaining_size < diff_size) { if (!ReadDataFromBaseDevice(sector, remaining_size)) { - return RespondIOError(); + return false; } total_bytes_read += remaining_size; @@ -574,7 +571,7 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { } } else { if (!ReadDataFromBaseDevice(sector, diff_size)) { - return RespondIOError(); + return false; } total_bytes_read += diff_size; @@ -596,7 +593,7 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { return true; } -bool Worker::RespondIOError() { +void Worker::RespondIOError() { struct dm_user_header* header = bufsink_.GetHeaderPtr(); header->type = DM_USER_RESP_ERROR; // This is an issue with the dm-user interface. There @@ -610,13 +607,7 @@ bool Worker::RespondIOError() { // TODO: Fix the interface CHECK(header_response_); - if (!WriteDmUserPayload(0)) { - return false; - } - - // There is no need to process further as we have already seen - // an I/O error - return true; + WriteDmUserPayload(0); } bool Worker::DmuserReadRequest() { @@ -624,7 +615,7 @@ bool Worker::DmuserReadRequest() { // Unaligned I/O request if (!IsBlockAligned(header->sector << SECTOR_SHIFT)) { - return ReadUnalignedSector(header->sector, header->len); + return ReadUnalignedSector(header->sector, header->len) != -1; } return ReadAlignedSector(header->sector, header->len); From 80ebe8c35d7426f38fa2e951679ce2a765a6bcf2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 21 Jun 2023 12:00:09 -0700 Subject: [PATCH 0156/1487] snapuserd: Restrict where reads/writes to dm_user_header happen. Only write to dm_user_header in the functions which explicitly need to marshal it. This avoids leakage of dm-user specifics into core logic. This also simplifies the existing control flow by allowing us to set an error anywhere, or nowhere, as any "return false" from ProcessIORequest will automatically set an error header. Bug: 288273605 Test: snapuserd_test Change-Id: I85f67208197d7ecc49e348ab3013827a38e84761 --- .../user-space-merge/snapuserd_core.h | 1 - .../user-space-merge/snapuserd_dm_user.cpp | 84 ++++++++----------- 2 files changed, 34 insertions(+), 51 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index 7cffc1c4bf47..c984a61f89eb 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -119,7 +119,6 @@ class Worker { } // Functions interacting with dm-user - bool ReadDmUserHeader(); bool WriteDmUserPayload(size_t size); bool DmuserReadRequest(); diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp index 0eb2a14fe620..1b17698a3e1a 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp @@ -290,21 +290,6 @@ bool Worker::RunThread() { return true; } -// Read Header from dm-user misc device. This gives -// us the sector number for which IO is issued by dm-snapshot device -bool Worker::ReadDmUserHeader() { - if (!android::base::ReadFully(ctrl_fd_, bufsink_.GetBufPtr(), sizeof(struct dm_user_header))) { - if (errno != ENOTBLK) { - SNAP_PLOG(ERROR) << "Control-read failed"; - } - - SNAP_PLOG(DEBUG) << "ReadDmUserHeader failed...."; - return false; - } - - return true; -} - // Send the payload/data back to dm-user misc device. bool Worker::WriteDmUserPayload(size_t size) { size_t payload_size = size; @@ -345,19 +330,15 @@ bool Worker::ReadDataFromBaseDevice(sector_t sector, size_t read_size) { } bool Worker::ReadAlignedSector(sector_t sector, size_t sz) { - struct dm_user_header* header = bufsink_.GetHeaderPtr(); size_t remaining_size = sz; std::vector>& chunk_vec = snapuserd_->GetChunkVec(); - bool io_error = false; int ret = 0; do { // Process 1MB payload at a time size_t read_size = std::min(PAYLOAD_BUFFER_SZ, remaining_size); - header->type = DM_USER_RESP_SUCCESS; size_t total_bytes_read = 0; - io_error = false; bufsink_.ResetBufferOffset(); while (read_size) { @@ -375,7 +356,7 @@ bool Worker::ReadAlignedSector(sector_t sector, size_t sz) { // device. if (!ReadDataFromBaseDevice(sector, size)) { SNAP_LOG(ERROR) << "ReadDataFromBaseDevice failed"; - header->type = DM_USER_RESP_ERROR; + return false; } ret = size; @@ -384,35 +365,26 @@ bool Worker::ReadAlignedSector(sector_t sector, size_t sz) { // process it. if (!ProcessCowOp(it->second)) { SNAP_LOG(ERROR) << "ProcessCowOp failed"; - header->type = DM_USER_RESP_ERROR; + return false; } ret = BLOCK_SZ; } - // Just return the header if it is an error - if (header->type == DM_USER_RESP_ERROR) { - RespondIOError(); - io_error = true; - break; - } - read_size -= ret; total_bytes_read += ret; sector += (ret >> SECTOR_SHIFT); bufsink_.UpdateBufferOffset(ret); } - if (!io_error) { - if (!WriteDmUserPayload(total_bytes_read)) { - return false; - } - - SNAP_LOG(DEBUG) << "WriteDmUserPayload success total_bytes_read: " << total_bytes_read - << " remaining_size: " << remaining_size; - remaining_size -= total_bytes_read; + if (!WriteDmUserPayload(total_bytes_read)) { + return false; } - } while (remaining_size > 0 && !io_error); + + SNAP_LOG(DEBUG) << "WriteDmUserPayload success total_bytes_read: " << total_bytes_read + << " remaining_size: " << remaining_size; + remaining_size -= total_bytes_read; + } while (remaining_size > 0); return true; } @@ -453,8 +425,6 @@ int Worker::ReadUnalignedSector( } bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { - struct dm_user_header* header = bufsink_.GetHeaderPtr(); - header->type = DM_USER_RESP_SUCCESS; bufsink_.ResetBufferOffset(); std::vector>& chunk_vec = snapuserd_->GetChunkVec(); @@ -622,9 +592,15 @@ bool Worker::DmuserReadRequest() { } bool Worker::ProcessIORequest() { + // Read Header from dm-user misc device. This gives + // us the sector number for which IO is issued by dm-snapshot device struct dm_user_header* header = bufsink_.GetHeaderPtr(); + if (!android::base::ReadFully(ctrl_fd_, header, sizeof(*header))) { + if (errno != ENOTBLK) { + SNAP_PLOG(ERROR) << "Control-read failed"; + } - if (!ReadDmUserHeader()) { + SNAP_PLOG(DEBUG) << "ReadDmUserHeader failed...."; return false; } @@ -634,26 +610,34 @@ bool Worker::ProcessIORequest() { SNAP_LOG(DEBUG) << "Daemon: msg->type: " << std::dec << header->type; SNAP_LOG(DEBUG) << "Daemon: msg->flags: " << std::dec << header->flags; + // Use the same header buffer as the response header. + int request_type = header->type; + header->type = DM_USER_RESP_SUCCESS; header_response_ = true; - switch (header->type) { - case DM_USER_REQ_MAP_READ: { - if (!DmuserReadRequest()) { - return false; - } + bool ok; + switch (request_type) { + case DM_USER_REQ_MAP_READ: + ok = DmuserReadRequest(); break; - } - case DM_USER_REQ_MAP_WRITE: { + case DM_USER_REQ_MAP_WRITE: // TODO: We should not get any write request // to dm-user as we mount all partitions // as read-only. Need to verify how are TRIM commands // handled during mount. - return false; - } + ok = false; + break; + + default: + ok = false; + break; } - return true; + if (!ok && header->type != DM_USER_RESP_ERROR) { + RespondIOError(); + } + return ok; } } // namespace snapshot From 40e78443e93729c5f5571a4c29b25ad7c7b3cecb Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Wed, 5 Jul 2023 12:48:13 -0700 Subject: [PATCH 0157/1487] Replace usage of base::Callback with std::function base::Callback comes from libchrome which is undermaintained. Since C++11 there's standard library support for function objects. Migrate to a more well knowned solution for function objects. Test: th Change-Id: Id19bcd7e92691f57d97520f8f1f4909ca9c25b33 --- libbinderwrapper/Android.bp | 3 --- libbinderwrapper/binder_wrapper.cc | 2 +- .../include/binderwrapper/binder_test_base.h | 3 +-- .../include/binderwrapper/binder_wrapper.h | 7 +++--- .../binderwrapper/stub_binder_wrapper.h | 7 +++--- libbinderwrapper/real_binder_wrapper.cc | 24 +++++++++---------- libbinderwrapper/real_binder_wrapper.h | 5 ++-- libbinderwrapper/stub_binder_wrapper.cc | 11 ++++----- 8 files changed, 26 insertions(+), 36 deletions(-) diff --git a/libbinderwrapper/Android.bp b/libbinderwrapper/Android.bp index 75f43eeaabf7..87c55faadc32 100644 --- a/libbinderwrapper/Android.bp +++ b/libbinderwrapper/Android.bp @@ -26,13 +26,10 @@ cc_defaults { "-Werror", "-Wno-unused-parameter", - // for libchrome - "-Wno-sign-promo", ], export_include_dirs: ["include"], shared_libs: [ "libbinder", - "libchrome", "libutils", ], } diff --git a/libbinderwrapper/binder_wrapper.cc b/libbinderwrapper/binder_wrapper.cc index ca9c1dfd93cc..f5e7476f128e 100644 --- a/libbinderwrapper/binder_wrapper.cc +++ b/libbinderwrapper/binder_wrapper.cc @@ -16,7 +16,7 @@ #include -#include +#include #include "real_binder_wrapper.h" diff --git a/libbinderwrapper/include/binderwrapper/binder_test_base.h b/libbinderwrapper/include/binderwrapper/binder_test_base.h index 06543de6fba5..46eca3f15b8e 100644 --- a/libbinderwrapper/include/binderwrapper/binder_test_base.h +++ b/libbinderwrapper/include/binderwrapper/binder_test_base.h @@ -17,7 +17,6 @@ #ifndef SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_TEST_BASE_H_ #define SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_TEST_BASE_H_ -#include #include namespace android { @@ -37,7 +36,7 @@ class BinderTestBase : public ::testing::Test { StubBinderWrapper* binder_wrapper_; // Not owned. private: - DISALLOW_COPY_AND_ASSIGN(BinderTestBase); + BinderTestBase(const BinderTestBase&) = delete; }; } // namespace android diff --git a/libbinderwrapper/include/binderwrapper/binder_wrapper.h b/libbinderwrapper/include/binderwrapper/binder_wrapper.h index a104bff32306..fc5708b62881 100644 --- a/libbinderwrapper/include/binderwrapper/binder_wrapper.h +++ b/libbinderwrapper/include/binderwrapper/binder_wrapper.h @@ -19,9 +19,9 @@ #include +#include #include -#include #include namespace android { @@ -68,9 +68,8 @@ class BinderWrapper { // Registers |callback| to be invoked when |binder| dies. If another callback // is currently registered for |binder|, it will be replaced. - virtual bool RegisterForDeathNotifications( - const sp& binder, - const ::base::Closure& callback) = 0; + virtual bool RegisterForDeathNotifications(const sp& binder, + const std::function&) = 0; // Unregisters the callback, if any, for |binder|. virtual bool UnregisterForDeathNotifications(const sp& binder) = 0; diff --git a/libbinderwrapper/include/binderwrapper/stub_binder_wrapper.h b/libbinderwrapper/include/binderwrapper/stub_binder_wrapper.h index 9d4578eb39d4..2a7f77e7a3a9 100644 --- a/libbinderwrapper/include/binderwrapper/stub_binder_wrapper.h +++ b/libbinderwrapper/include/binderwrapper/stub_binder_wrapper.h @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -98,7 +97,7 @@ class StubBinderWrapper : public BinderWrapper { const sp& binder) override; sp CreateLocalBinder() override; bool RegisterForDeathNotifications(const sp& binder, - const ::base::Closure& callback) override; + const std::function& callback) override; bool UnregisterForDeathNotifications(const sp& binder) override; uid_t GetCallingUid() override; pid_t GetCallingPid() override; @@ -119,13 +118,13 @@ class StubBinderWrapper : public BinderWrapper { // Map from binder handle to the callback that should be invoked on binder // death. - std::map, ::base::Closure> death_callbacks_; + std::map, std::function> death_callbacks_; // Values to return from GetCallingUid() and GetCallingPid(); uid_t calling_uid_; pid_t calling_pid_; - DISALLOW_COPY_AND_ASSIGN(StubBinderWrapper); + StubBinderWrapper(const StubBinderWrapper&) = delete; }; } // namespace android diff --git a/libbinderwrapper/real_binder_wrapper.cc b/libbinderwrapper/real_binder_wrapper.cc index f93f1837dca8..d214ce31c10f 100644 --- a/libbinderwrapper/real_binder_wrapper.cc +++ b/libbinderwrapper/real_binder_wrapper.cc @@ -16,7 +16,8 @@ #include "real_binder_wrapper.h" -#include +#include + #include #include #include @@ -29,20 +30,18 @@ namespace android { // be awkward. class RealBinderWrapper::DeathRecipient : public IBinder::DeathRecipient { public: - explicit DeathRecipient(const ::base::Closure& callback) - : callback_(callback) {} - ~DeathRecipient() = default; + explicit DeathRecipient(const std::function& callback) + : callback_(std::move(callback)) {} + ~DeathRecipient() = default; - // IBinder::DeathRecipient: - void binderDied(const wp& who) override { - callback_.Run(); - } + // IBinder::DeathRecipient: + void binderDied(const wp& who) override { callback_(); } private: // Callback to run in response to binder death. - ::base::Closure callback_; + std::function callback_; - DISALLOW_COPY_AND_ASSIGN(DeathRecipient); + DISALLOW_COPY_AND_ASSIGN(DeathRecipient); }; RealBinderWrapper::RealBinderWrapper() = default; @@ -83,9 +82,8 @@ sp RealBinderWrapper::CreateLocalBinder() { return sp(new BBinder()); } -bool RealBinderWrapper::RegisterForDeathNotifications( - const sp& binder, - const ::base::Closure& callback) { +bool RealBinderWrapper::RegisterForDeathNotifications(const sp& binder, + const std::function& callback) { sp recipient(new DeathRecipient(callback)); if (binder->linkToDeath(recipient) != OK) { LOG(ERROR) << "Failed to register for death notifications on " diff --git a/libbinderwrapper/real_binder_wrapper.h b/libbinderwrapper/real_binder_wrapper.h index fa05383fbfcf..d0468f079018 100644 --- a/libbinderwrapper/real_binder_wrapper.h +++ b/libbinderwrapper/real_binder_wrapper.h @@ -19,7 +19,6 @@ #include -#include #include namespace android { @@ -38,7 +37,7 @@ class RealBinderWrapper : public BinderWrapper { const sp& binder) override; sp CreateLocalBinder() override; bool RegisterForDeathNotifications(const sp& binder, - const ::base::Closure& callback) override; + const std::function& callback) override; bool UnregisterForDeathNotifications(const sp& binder) override; uid_t GetCallingUid() override; pid_t GetCallingPid() override; @@ -50,7 +49,7 @@ class RealBinderWrapper : public BinderWrapper { // death. std::map, sp> death_recipients_; - DISALLOW_COPY_AND_ASSIGN(RealBinderWrapper); + RealBinderWrapper(const RealBinderWrapper&) = delete; }; } // namespace android diff --git a/libbinderwrapper/stub_binder_wrapper.cc b/libbinderwrapper/stub_binder_wrapper.cc index 8e75f6239e97..fabf1228a05c 100644 --- a/libbinderwrapper/stub_binder_wrapper.cc +++ b/libbinderwrapper/stub_binder_wrapper.cc @@ -16,7 +16,8 @@ #include -#include +#include + #include #include @@ -41,8 +42,7 @@ sp StubBinderWrapper::GetRegisteredService( void StubBinderWrapper::NotifyAboutBinderDeath(const sp& binder) { const auto it = death_callbacks_.find(binder); - if (it != death_callbacks_.end()) - it->second.Run(); + if (it != death_callbacks_.end()) it->second(); } sp StubBinderWrapper::GetService(const std::string& service_name) { @@ -62,9 +62,8 @@ sp StubBinderWrapper::CreateLocalBinder() { return binder; } -bool StubBinderWrapper::RegisterForDeathNotifications( - const sp& binder, - const ::base::Closure& callback) { +bool StubBinderWrapper::RegisterForDeathNotifications(const sp& binder, + const std::function& callback) { death_callbacks_[binder] = callback; return true; } From c97eeed5e4fc0266bc4f028ba7e6643e5a98eabe Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Wed, 21 Jun 2023 14:49:52 -0700 Subject: [PATCH 0158/1487] Adding parsing for fastboot-info Adding back the parsing for fastboot info Test: m fastboot, fastboot flashall Change-Id: I0075266bad5d45dcb99dbf91aa431008ca336216 --- fastboot/fastboot.cpp | 30 +++++++++++++++++++++++++++--- fastboot/fastboot.h | 5 +++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 29980afd06f2..6fc6f5ff742d 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -173,7 +173,7 @@ static std::vector images = { // clang-format on }; -static char* get_android_product_out() { +char* get_android_product_out() { char* dir = getenv("ANDROID_PRODUCT_OUT"); if (dir == nullptr || dir[0] == '\0') { return nullptr; @@ -1787,13 +1787,25 @@ void FlashAllTool::Flash() { CancelSnapshotIfNeeded(); - tasks_ = CollectTasksFromImageList(); + tasks_ = CollectTasks(); for (auto& task : tasks_) { task->Run(); } return; } +std::vector> FlashAllTool::CollectTasks() { + std::vector> tasks; + if (fp_->should_use_fastboot_info) { + tasks = CollectTasksFromFastbootInfo(); + + } else { + tasks = CollectTasksFromImageList(); + } + + return tasks; +} + void FlashAllTool::CheckRequirements() { std::vector contents; if (!fp_->source->ReadFile("android-info.txt", &contents)) { @@ -1848,7 +1860,6 @@ std::vector> FlashAllTool::CollectTasksFromImageList() { // or in bootloader fastboot. std::vector> tasks; AddFlashTasks(boot_images_, tasks); - if (auto flash_super_task = OptimizedFlashSuperTask::Initialize(fp_, os_images_)) { tasks.emplace_back(std::move(flash_super_task)); } else { @@ -1871,10 +1882,23 @@ std::vector> FlashAllTool::CollectTasksFromImageList() { tasks.emplace_back(std::make_unique(fp_, image->part_name, "0", slot)); } } + AddFlashTasks(os_images_, tasks); return tasks; } +std::vector> FlashAllTool::CollectTasksFromFastbootInfo() { + std::vector> tasks; + std::vector contents; + if (!fp_->source->ReadFile("fastboot-info.txt", &contents)) { + LOG(VERBOSE) << "Flashing from hardcoded images. fastboot-info.txt is empty or does not " + "exist"; + return CollectTasksFromImageList(); + } + tasks = ParseFastbootInfo(fp_, Split({contents.data(), contents.size()}, "\n")); + return tasks; +} + void FlashAllTool::AddFlashTasks(const std::vector>& images, std::vector>& tasks) { for (const auto& [image, slot] : images) { diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index 196bd67261ca..77430f05ad48 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -97,6 +97,7 @@ struct FlashingPlan { bool skip_secondary = false; bool force_flash = false; bool should_optimize_flash_super = true; + bool should_use_fastboot_info = false; uint64_t sparse_limit = 0; std::string slot_override; @@ -111,6 +112,7 @@ class FlashAllTool { FlashAllTool(FlashingPlan* fp); void Flash(); + std::vector> CollectTasks(); private: void CheckRequirements(); @@ -118,6 +120,8 @@ class FlashAllTool { void CollectImages(); void AddFlashTasks(const std::vector>& images, std::vector>& tasks); + + std::vector> CollectTasksFromFastbootInfo(); std::vector> CollectTasksFromImageList(); std::vector boot_images_; @@ -143,6 +147,7 @@ class LocalImageSource final : public ImageSource { unique_fd OpenFile(const std::string& name) const override; }; +char* get_android_product_out(); bool should_flash_in_userspace(const std::string& partition_name); bool is_userspace_fastboot(); void do_flash(const char* pname, const char* fname, const bool apply_vbmeta, From 57e3c32bcc18d169d8f44615cc3cc641add7409f Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Wed, 5 Jul 2023 16:07:05 -0700 Subject: [PATCH 0159/1487] Move libbinderwrapper to update_engine libbinderwrapper is only used by update_engine, it's better to move it inside update_engine repo Change-Id: Ia489f38a311b221744f7cf89c9da9c4f3682bb4c --- libbinderwrapper/Android.bp | 63 --------- libbinderwrapper/binder_test_base.cc | 33 ----- libbinderwrapper/binder_wrapper.cc | 60 -------- .../include/binderwrapper/binder_test_base.h | 44 ------ .../include/binderwrapper/binder_wrapper.h | 87 ------------ .../binderwrapper/stub_binder_wrapper.h | 132 ------------------ libbinderwrapper/real_binder_wrapper.cc | 121 ---------------- libbinderwrapper/real_binder_wrapper.h | 57 -------- libbinderwrapper/stub_binder_wrapper.cc | 85 ----------- 9 files changed, 682 deletions(-) delete mode 100644 libbinderwrapper/Android.bp delete mode 100644 libbinderwrapper/binder_test_base.cc delete mode 100644 libbinderwrapper/binder_wrapper.cc delete mode 100644 libbinderwrapper/include/binderwrapper/binder_test_base.h delete mode 100644 libbinderwrapper/include/binderwrapper/binder_wrapper.h delete mode 100644 libbinderwrapper/include/binderwrapper/stub_binder_wrapper.h delete mode 100644 libbinderwrapper/real_binder_wrapper.cc delete mode 100644 libbinderwrapper/real_binder_wrapper.h delete mode 100644 libbinderwrapper/stub_binder_wrapper.cc diff --git a/libbinderwrapper/Android.bp b/libbinderwrapper/Android.bp deleted file mode 100644 index 87c55faadc32..000000000000 --- a/libbinderwrapper/Android.bp +++ /dev/null @@ -1,63 +0,0 @@ -// -// Copyright (C) 2015 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. -// - -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -cc_defaults { - name: "libbinderwrapper_defaults", - - cflags: [ - "-Wall", - "-Werror", - "-Wno-unused-parameter", - - ], - export_include_dirs: ["include"], - shared_libs: [ - "libbinder", - "libutils", - ], -} - -// libbinderwrapper shared library -// ======================================================== -cc_library_shared { - name: "libbinderwrapper", - defaults: ["libbinderwrapper_defaults"], - vendor_available: true, - - srcs: [ - "binder_wrapper.cc", - "real_binder_wrapper.cc", - ], -} - -// libbinderwrapper_test_support static library -// ======================================================== -cc_library_static { - name: "libbinderwrapper_test_support", - defaults: ["libbinderwrapper_defaults"], - - static_libs: ["libgtest"], - shared_libs: ["libbinderwrapper"], - - srcs: [ - "binder_test_base.cc", - "stub_binder_wrapper.cc", - ], -} diff --git a/libbinderwrapper/binder_test_base.cc b/libbinderwrapper/binder_test_base.cc deleted file mode 100644 index af93a04d9520..000000000000 --- a/libbinderwrapper/binder_test_base.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2015 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 - -#include -#include - -namespace android { - -BinderTestBase::BinderTestBase() : binder_wrapper_(new StubBinderWrapper()) { - // Pass ownership. - BinderWrapper::InitForTesting(binder_wrapper_); -} - -BinderTestBase::~BinderTestBase() { - BinderWrapper::Destroy(); -} - -} // namespace android diff --git a/libbinderwrapper/binder_wrapper.cc b/libbinderwrapper/binder_wrapper.cc deleted file mode 100644 index f5e7476f128e..000000000000 --- a/libbinderwrapper/binder_wrapper.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2015 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 - -#include - -#include "real_binder_wrapper.h" - -namespace android { - -// Singleton instance. -BinderWrapper* BinderWrapper::instance_ = nullptr; - -// static -void BinderWrapper::Create() { - CHECK(!instance_) << "Already initialized; missing call to Destroy()?"; - instance_ = new RealBinderWrapper(); -} - -// static -void BinderWrapper::InitForTesting(BinderWrapper* wrapper) { - CHECK(!instance_) << "Already initialized; missing call to Destroy()?"; - instance_ = wrapper; -} - -// static -void BinderWrapper::Destroy() { - CHECK(instance_) << "Not initialized; missing call to Create()?"; - delete instance_; - instance_ = nullptr; -} - -// static -BinderWrapper* BinderWrapper::Get() { - CHECK(instance_) << "Not initialized; missing call to Create()?"; - return instance_; -} - -// static -BinderWrapper* BinderWrapper::GetOrCreateInstance() { - if (!instance_) - instance_ = new RealBinderWrapper(); - return instance_; -} - -} // namespace android diff --git a/libbinderwrapper/include/binderwrapper/binder_test_base.h b/libbinderwrapper/include/binderwrapper/binder_test_base.h deleted file mode 100644 index 46eca3f15b8e..000000000000 --- a/libbinderwrapper/include/binderwrapper/binder_test_base.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#ifndef SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_TEST_BASE_H_ -#define SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_TEST_BASE_H_ - -#include - -namespace android { - -class StubBinderWrapper; - -// Class that can be inherited from (or aliased via typedef/using) when writing -// tests that use StubBinderManager. -class BinderTestBase : public ::testing::Test { - public: - BinderTestBase(); - ~BinderTestBase() override; - - StubBinderWrapper* binder_wrapper() { return binder_wrapper_; } - - protected: - StubBinderWrapper* binder_wrapper_; // Not owned. - - private: - BinderTestBase(const BinderTestBase&) = delete; -}; - -} // namespace android - -#endif // SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_TEST_BASE_H_ diff --git a/libbinderwrapper/include/binderwrapper/binder_wrapper.h b/libbinderwrapper/include/binderwrapper/binder_wrapper.h deleted file mode 100644 index fc5708b62881..000000000000 --- a/libbinderwrapper/include/binderwrapper/binder_wrapper.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#ifndef SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_WRAPPER_H_ -#define SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_WRAPPER_H_ - -#include - -#include -#include - -#include - -namespace android { - -class BBinder; -class IBinder; - -// Wraps libbinder to make it testable. -// NOTE: Static methods of this class are not thread-safe. -class BinderWrapper { - public: - virtual ~BinderWrapper() {} - - // Creates and initializes the singleton (using a wrapper that communicates - // with the real binder system). - static void Create(); - - // Initializes |wrapper| as the singleton, taking ownership of it. Tests that - // want to inject their own wrappers should call this instead of Create(). - static void InitForTesting(BinderWrapper* wrapper); - - // Destroys the singleton. Must be called before calling Create() or - // InitForTesting() a second time. - static void Destroy(); - - // Returns the singleton instance previously created by Create() or set by - // InitForTesting(). - static BinderWrapper* Get(); - - // Returns the singleton instance if it was previously created by Create() or - // set by InitForTesting(), or creates a new one by calling Create(). - static BinderWrapper* GetOrCreateInstance(); - - // Gets the binder for communicating with the service identified by - // |service_name|, returning null immediately if it doesn't exist. - virtual sp GetService(const std::string& service_name) = 0; - - // Registers |binder| as |service_name| with the service manager. - virtual bool RegisterService(const std::string& service_name, - const sp& binder) = 0; - - // Creates a local binder object. - virtual sp CreateLocalBinder() = 0; - - // Registers |callback| to be invoked when |binder| dies. If another callback - // is currently registered for |binder|, it will be replaced. - virtual bool RegisterForDeathNotifications(const sp& binder, - const std::function&) = 0; - - // Unregisters the callback, if any, for |binder|. - virtual bool UnregisterForDeathNotifications(const sp& binder) = 0; - - // When called while in a transaction, returns the caller's UID or PID. - virtual uid_t GetCallingUid() = 0; - virtual pid_t GetCallingPid() = 0; - - private: - static BinderWrapper* instance_; -}; - -} // namespace android - -#endif // SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_WRAPPER_H_ diff --git a/libbinderwrapper/include/binderwrapper/stub_binder_wrapper.h b/libbinderwrapper/include/binderwrapper/stub_binder_wrapper.h deleted file mode 100644 index 2a7f77e7a3a9..000000000000 --- a/libbinderwrapper/include/binderwrapper/stub_binder_wrapper.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#ifndef SYSTEM_CORE_INCLUDE_BINDERWRAPPER_STUB_BINDER_WRAPPER_H_ -#define SYSTEM_CORE_INCLUDE_BINDERWRAPPER_STUB_BINDER_WRAPPER_H_ - -#include -#include -#include - -#include -#include -#include - -namespace android { - -// Stub implementation of BinderWrapper for testing. -// -// Example usage: -// -// First, assuming a base IFoo binder interface, create a stub class that -// derives from BnFoo to implement the receiver side of the communication: -// -// class StubFoo : public BnFoo { -// public: -// ... -// status_t doSomething(int arg) override { -// // e.g. save passed-in value for later inspection by tests. -// return OK; -// } -// }; -// -// Next, from your test code, inject a StubBinderManager either directly or by -// inheriting from the BinderTestBase class: -// -// StubBinderWrapper* wrapper = new StubBinderWrapper(); -// BinderWrapper::InitForTesting(wrapper); // Takes ownership. -// -// Also from your test, create a StubFoo and register it with the wrapper: -// -// StubFoo* foo = new StubFoo(); -// sp binder(foo); -// wrapper->SetBinderForService("foo", binder); -// -// The code being tested can now use the wrapper to get the stub and call it: -// -// sp binder = BinderWrapper::Get()->GetService("foo"); -// CHECK(binder.get()); -// sp foo = interface_cast(binder); -// CHECK_EQ(foo->doSomething(3), OK); -// -// To create a local BBinder object, production code can call -// CreateLocalBinder(). Then, a test can get the BBinder's address via -// local_binders() to check that they're passed as expected in binder calls. -// -class StubBinderWrapper : public BinderWrapper { - public: - StubBinderWrapper(); - ~StubBinderWrapper() override; - - const std::vector>& local_binders() const { - return local_binders_; - } - void clear_local_binders() { local_binders_.clear(); } - - void set_calling_uid(uid_t uid) { calling_uid_ = uid; } - void set_calling_pid(pid_t pid) { calling_pid_ = pid; } - - // Sets the binder to return when |service_name| is passed to GetService() or - // WaitForService(). - void SetBinderForService(const std::string& service_name, - const sp& binder); - - // Returns the binder previously registered for |service_name| via - // RegisterService(), or null if the service hasn't been registered. - sp GetRegisteredService(const std::string& service_name) const; - - // Run the calback in |death_callbacks_| corresponding to |binder|. - void NotifyAboutBinderDeath(const sp& binder); - - // BinderWrapper: - sp GetService(const std::string& service_name) override; - bool RegisterService(const std::string& service_name, - const sp& binder) override; - sp CreateLocalBinder() override; - bool RegisterForDeathNotifications(const sp& binder, - const std::function& callback) override; - bool UnregisterForDeathNotifications(const sp& binder) override; - uid_t GetCallingUid() override; - pid_t GetCallingPid() override; - - private: - using ServiceMap = std::map>; - - // Map from service name to associated binder handle. Used by GetService() and - // WaitForService(). - ServiceMap services_to_return_; - - // Map from service name to associated binder handle. Updated by - // RegisterService(). - ServiceMap registered_services_; - - // Local binders returned by CreateLocalBinder(). - std::vector> local_binders_; - - // Map from binder handle to the callback that should be invoked on binder - // death. - std::map, std::function> death_callbacks_; - - // Values to return from GetCallingUid() and GetCallingPid(); - uid_t calling_uid_; - pid_t calling_pid_; - - StubBinderWrapper(const StubBinderWrapper&) = delete; -}; - -} // namespace android - -#endif // SYSTEM_CORE_INCLUDE_BINDERWRAPPER_STUB_BINDER_WRAPPER_H_ diff --git a/libbinderwrapper/real_binder_wrapper.cc b/libbinderwrapper/real_binder_wrapper.cc deleted file mode 100644 index d214ce31c10f..000000000000 --- a/libbinderwrapper/real_binder_wrapper.cc +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2015 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 "real_binder_wrapper.h" - -#include - -#include -#include -#include -#include - -namespace android { - -// Class that handles binder death notifications. libbinder wants the recipient -// to be wrapped in sp<>, so registering RealBinderWrapper as a recipient would -// be awkward. -class RealBinderWrapper::DeathRecipient : public IBinder::DeathRecipient { - public: - explicit DeathRecipient(const std::function& callback) - : callback_(std::move(callback)) {} - ~DeathRecipient() = default; - - // IBinder::DeathRecipient: - void binderDied(const wp& who) override { callback_(); } - - private: - // Callback to run in response to binder death. - std::function callback_; - - DISALLOW_COPY_AND_ASSIGN(DeathRecipient); -}; - -RealBinderWrapper::RealBinderWrapper() = default; - -RealBinderWrapper::~RealBinderWrapper() = default; - -sp RealBinderWrapper::GetService(const std::string& service_name) { - sp service_manager = defaultServiceManager(); - if (!service_manager.get()) { - LOG(ERROR) << "Unable to get service manager"; - return sp(); - } - sp binder = - service_manager->checkService(String16(service_name.c_str())); - if (!binder.get()) - LOG(ERROR) << "Unable to get \"" << service_name << "\" service"; - return binder; -} - -bool RealBinderWrapper::RegisterService(const std::string& service_name, - const sp& binder) { - sp service_manager = defaultServiceManager(); - if (!service_manager.get()) { - LOG(ERROR) << "Unable to get service manager"; - return false; - } - status_t status = defaultServiceManager()->addService( - String16(service_name.c_str()), binder); - if (status != OK) { - LOG(ERROR) << "Failed to register \"" << service_name << "\" with service " - << "manager"; - return false; - } - return true; -} - -sp RealBinderWrapper::CreateLocalBinder() { - return sp(new BBinder()); -} - -bool RealBinderWrapper::RegisterForDeathNotifications(const sp& binder, - const std::function& callback) { - sp recipient(new DeathRecipient(callback)); - if (binder->linkToDeath(recipient) != OK) { - LOG(ERROR) << "Failed to register for death notifications on " - << binder.get(); - return false; - } - death_recipients_[binder] = recipient; - return true; -} - -bool RealBinderWrapper::UnregisterForDeathNotifications( - const sp& binder) { - auto it = death_recipients_.find(binder); - if (it == death_recipients_.end()) { - LOG(ERROR) << "Not registered for death notifications on " << binder.get(); - return false; - } - if (binder->unlinkToDeath(it->second) != OK) { - LOG(ERROR) << "Failed to unregister for death notifications on " - << binder.get(); - return false; - } - death_recipients_.erase(it); - return true; -} - -uid_t RealBinderWrapper::GetCallingUid() { - return IPCThreadState::self()->getCallingUid(); -} - -pid_t RealBinderWrapper::GetCallingPid() { - return IPCThreadState::self()->getCallingPid(); -} - -} // namespace android diff --git a/libbinderwrapper/real_binder_wrapper.h b/libbinderwrapper/real_binder_wrapper.h deleted file mode 100644 index d0468f079018..000000000000 --- a/libbinderwrapper/real_binder_wrapper.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#ifndef SYSTEM_CORE_LIBBINDERWRAPPER_REAL_BINDER_WRAPPER_H_ -#define SYSTEM_CORE_LIBBINDERWRAPPER_REAL_BINDER_WRAPPER_H_ - -#include - -#include - -namespace android { - -class IBinder; - -// Real implementation of BinderWrapper. -class RealBinderWrapper : public BinderWrapper { - public: - RealBinderWrapper(); - ~RealBinderWrapper() override; - - // BinderWrapper: - sp GetService(const std::string& service_name) override; - bool RegisterService(const std::string& service_name, - const sp& binder) override; - sp CreateLocalBinder() override; - bool RegisterForDeathNotifications(const sp& binder, - const std::function& callback) override; - bool UnregisterForDeathNotifications(const sp& binder) override; - uid_t GetCallingUid() override; - pid_t GetCallingPid() override; - - private: - class DeathRecipient; - - // Map from binder handle to object that should be notified of the binder's - // death. - std::map, sp> death_recipients_; - - RealBinderWrapper(const RealBinderWrapper&) = delete; -}; - -} // namespace android - -#endif // SYSTEM_CORE_LIBBINDER_WRAPPER_REAL_BINDER_WRAPPER_H_ diff --git a/libbinderwrapper/stub_binder_wrapper.cc b/libbinderwrapper/stub_binder_wrapper.cc deleted file mode 100644 index fabf1228a05c..000000000000 --- a/libbinderwrapper/stub_binder_wrapper.cc +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2015 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 - -#include - -#include -#include - -namespace android { - -StubBinderWrapper::StubBinderWrapper() - : calling_uid_(-1), - calling_pid_(-1) {} - -StubBinderWrapper::~StubBinderWrapper() = default; - -void StubBinderWrapper::SetBinderForService(const std::string& service_name, - const sp& binder) { - services_to_return_[service_name] = binder; -} - -sp StubBinderWrapper::GetRegisteredService( - const std::string& service_name) const { - const auto it = registered_services_.find(service_name); - return it != registered_services_.end() ? it->second : sp(); -} - -void StubBinderWrapper::NotifyAboutBinderDeath(const sp& binder) { - const auto it = death_callbacks_.find(binder); - if (it != death_callbacks_.end()) it->second(); -} - -sp StubBinderWrapper::GetService(const std::string& service_name) { - const auto it = services_to_return_.find(service_name); - return it != services_to_return_.end() ? it->second : sp(); -} - -bool StubBinderWrapper::RegisterService(const std::string& service_name, - const sp& binder) { - registered_services_[service_name] = binder; - return true; -} - -sp StubBinderWrapper::CreateLocalBinder() { - sp binder(new BBinder()); - local_binders_.push_back(binder); - return binder; -} - -bool StubBinderWrapper::RegisterForDeathNotifications(const sp& binder, - const std::function& callback) { - death_callbacks_[binder] = callback; - return true; -} - -bool StubBinderWrapper::UnregisterForDeathNotifications( - const sp& binder) { - death_callbacks_.erase(binder); - return true; -} - -uid_t StubBinderWrapper::GetCallingUid() { - return calling_uid_; -} - -pid_t StubBinderWrapper::GetCallingPid() { - return calling_pid_; -} - -} // namespace android From d7de52d72175c943667455dcc15c2d17869393d3 Mon Sep 17 00:00:00 2001 From: Daeho Jeong Date: Wed, 28 Jun 2023 14:35:30 -0700 Subject: [PATCH 0160/1487] init.rc: set f2fs seq_file_ra_mul to 128 Based on experiments, we fount out 128 (128 x global readahead window size = 16mb) is the optimal multiple to boost up read speeds for the sequentially accessed files with POSIX_FADV_SEQUENTIAL. Bug: 195311558 Test: check the /sys/fs/f2fs//seq_file_ra_mul value Merged-In: I7563ad6e47b9ab76ae7fe36978d0e5970a7490e8 Change-Id: I7563ad6e47b9ab76ae7fe36978d0e5970a7490e8 Signed-off-by: Daeho Jeong --- rootdir/init.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 1e6918d0022c..7da264611d94 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -1142,7 +1142,7 @@ on boot write /dev/sys/fs/by-name/userdata/iostat_enable 1 # set readahead multiplier for POSIX_FADV_SEQUENTIAL files - write /dev/sys/fs/by-name/userdata/seq_file_ra_mul 16 + write /dev/sys/fs/by-name/userdata/seq_file_ra_mul 128 # limit discard size to 128MB in order to avoid long IO latency # for filesystem tuning first (dm or sda) From 0b2c5cde1f7d380d4aa5f4f249049e6fccd5ba0e Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 5 Jul 2023 18:02:09 +0000 Subject: [PATCH 0161/1487] init: remove unfinished fsverity signature support for APEX sepolicy The APEX sepolicy feature has unfinished support for verifying the sepolicy file using fsverity with a builtin signature. However, this was never finished and doesn't really make sense, since the already-implemented scheme that uses a full-file hash combined with a userspace signature check is better suited to the problem. Therefore, remove this unfinished code. Bug: 290064770 Test: presubmit and booting Cuttlefish Change-Id: I3403a3303bcea32c7340642b843cd1541fe1fd2f --- init/Android.bp | 2 -- init/selinux.cpp | 46 ++-------------------------------------------- 2 files changed, 2 insertions(+), 46 deletions(-) diff --git a/init/Android.bp b/init/Android.bp index 1af398a9a0ae..4416b9dc2637 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -166,11 +166,9 @@ libinit_cc_defaults { "libbootloader_message", "libc++fs", "libcgrouprc_format", - "libfsverity_init", "liblmkd_utils", "liblz4", "libzstd", - "libmini_keyctl_static", "libmodprobe", "libprocinfo", "libprotobuf-cpp-lite", diff --git a/init/selinux.cpp b/init/selinux.cpp index e0ef4913c938..b6d483a47d6d 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -74,10 +74,8 @@ #include #include #include -#include #include #include -#include #include #include @@ -510,7 +508,6 @@ bool OpenMonolithicPolicy(PolicyFile* policy_file) { constexpr const char* kSigningCertRelease = "/system/etc/selinux/com.android.sepolicy.cert-release.der"; -constexpr const char* kFsVerityProcPath = "/proc/sys/fs/verity"; const std::string kSepolicyApexMetadataDir = "/metadata/sepolicy/"; const std::string kSepolicyApexSystemDir = "/system/etc/selinux/apex/"; const std::string kSepolicyZip = "SEPolicy.zip"; @@ -614,24 +611,6 @@ Result GetPolicyFromApex(const std::string& dir) { return {}; } -Result LoadSepolicyApexCerts() { - key_serial_t keyring_id = android::GetKeyringId(".fs-verity"); - if (keyring_id < 0) { - return Error() << "Failed to find .fs-verity keyring id"; - } - - // TODO(b/199914227) the release key should always exist. Once it's checked in, start - // throwing an error here if it doesn't exist. - if (access(kSigningCertRelease, F_OK) == 0) { - LoadKeyFromFile(keyring_id, "fsv_sepolicy_apex_release", kSigningCertRelease); - } - return {}; -} - -Result SepolicyFsVerityCheck() { - return Error() << "TODO implement support for fsverity SEPolicy."; -} - Result SepolicyCheckSignature(const std::string& dir) { std::string signature; if (!android::base::ReadFileToString(dir + kSepolicySignature, &signature)) { @@ -654,18 +633,7 @@ Result SepolicyCheckSignature(const std::string& dir) { return verifySignature(sepolicyStr, signature, *releaseKey); } -Result SepolicyVerify(const std::string& dir, bool supportsFsVerity) { - if (supportsFsVerity) { - auto fsVerityCheck = SepolicyFsVerityCheck(); - if (fsVerityCheck.ok()) { - return fsVerityCheck; - } - // TODO(b/199914227) If the device supports fsverity, but we fail here, we should fail to - // boot and not carry on. For now, fallback to a signature checkuntil the fsverity - // logic is implemented. - LOG(INFO) << "Falling back to standard signature check. " << fsVerityCheck.error(); - } - +Result SepolicyVerify(const std::string& dir) { auto sepolicySignature = SepolicyCheckSignature(dir); if (!sepolicySignature.ok()) { return Error() << "Apex SEPolicy failed signature check"; @@ -698,23 +666,13 @@ void CleanupApexSepolicy() { // 6. Sets selinux into enforcing mode and continues normal booting. // void PrepareApexSepolicy() { - bool supportsFsVerity = access(kFsVerityProcPath, F_OK) == 0; - if (supportsFsVerity) { - auto loadSepolicyApexCerts = LoadSepolicyApexCerts(); - if (!loadSepolicyApexCerts.ok()) { - // TODO(b/199914227) If the device supports fsverity, but we fail here, we should fail - // to boot and not carry on. For now, fallback to a signature checkuntil the fsverity - // logic is implemented. - LOG(INFO) << loadSepolicyApexCerts.error(); - } - } // If apex sepolicy zip exists in /metadata/sepolicy, use that, otherwise use version on // /system. auto dir = (access((kSepolicyApexMetadataDir + kSepolicyZip).c_str(), F_OK) == 0) ? kSepolicyApexMetadataDir : kSepolicyApexSystemDir; - auto sepolicyVerify = SepolicyVerify(dir, supportsFsVerity); + auto sepolicyVerify = SepolicyVerify(dir); if (!sepolicyVerify.ok()) { LOG(INFO) << "Error: " << sepolicyVerify.error(); // If signature verification fails, fall back to version on /system. From 79a67391bde590704c199a8567661ad130c4d90e Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 6 Jul 2023 17:27:46 +0000 Subject: [PATCH 0162/1487] init.rc: stop using fsverity_init --lock Remove the code that "locked" the .fs-verity keyring at a certain point in the boot. It probably was thought that this achieved some useful security property, which is a bit questionable. Regardless, Android no longer uses fsverity builtin signatures. The only code that is still being kept around is enough to access existing files on old kernels, and for this "locking" the keyring is definitely not essential. Bug: 290064770 Test: presubmit and booting Cuttlefish Change-Id: Ide5729aeac5772658b2a3f0abe835988b8842b02 --- rootdir/init.rc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index a8b78d5d8025..3d45df249db9 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -1021,13 +1021,9 @@ on post-fs-data # Must start after 'derive_classpath' to have *CLASSPATH variables set. start odsign - # Before we can lock keys and proceed to the next boot stage, wait for - # odsign to be done with the key + # Wait for odsign to be done with the key. wait_for_prop odsign.key.done 1 - # Lock the fs-verity keyring, so no more keys can be added - exec -- /system/bin/fsverity_init --lock - # Bump the boot level to 1000000000; this prevents further on-device signing. # This is a special value that shuts down the thread which listens for # further updates. From f17079ff5890cfea529cb996891b2fe45a8ae63a Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Tue, 4 Jul 2023 01:29:26 +0100 Subject: [PATCH 0163/1487] Small refactoring in first_stage_mount The existing approach in first_stage_init/first_stage_mount makes it harder to add conditional logic that should only be applied for Microdroid. Additionally, it forces the FirstStageMount object to be created twice. This change refactors the control flow to make first_stage_init take the ownership of the FirstStageMount object. It will help with the follow up change (which will add logic to conditionally mount /vendor partition while booting Microdroid). As a nice side effect, this refactoring also fixes the problem of the FirstStageMount being created twice. This change also merges the FirstStageMount and FirstStageMountVBootV2 in a single class, since nobody actually uses FirstStageMount. Bug: 285855433 Test: device boots Test: atest MicrodroidTestApp Change-Id: I38a72c0f20e7c1ac70031498aeeca22b091fa827 --- init/first_stage_init.cpp | 40 +++++++++++-- init/first_stage_mount.cpp | 116 +++++++++++-------------------------- init/first_stage_mount.h | 21 ++++++- 3 files changed, 88 insertions(+), 89 deletions(-) diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index bff80c5c731f..e1d383a0c16c 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -257,6 +257,16 @@ static BootMode GetBootMode(const std::string& cmdline, const std::string& bootc return BootMode::NORMAL_MODE; } +static std::unique_ptr CreateFirstStageMount() { + auto ret = FirstStageMount::Create(); + if (ret.ok()) { + return std::move(*ret); + } else { + LOG(ERROR) << "Failed to create FirstStageMount : " << ret.error(); + return nullptr; + } +} + int FirstStageMain(int argc, char** argv) { if (REBOOT_BOOTLOADER_ON_PANIC) { InstallRebootSignalHandlers(); @@ -381,12 +391,17 @@ int FirstStageMain(int argc, char** argv) { << module_elapse_time.count() << " ms"; } + std::unique_ptr fsm; + bool created_devices = false; if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) { if (!IsRecoveryMode()) { - created_devices = DoCreateDevices(); - if (!created_devices) { - LOG(ERROR) << "Failed to create device nodes early"; + fsm = CreateFirstStageMount(); + if (fsm) { + created_devices = fsm->DoCreateDevices(); + if (!created_devices) { + LOG(ERROR) << "Failed to create device nodes early"; + } } } StartConsole(cmdline); @@ -437,8 +452,23 @@ int FirstStageMain(int argc, char** argv) { SwitchRoot("/first_stage_ramdisk"); } - if (!DoFirstStageMount(!created_devices)) { - LOG(FATAL) << "Failed to mount required partitions early ..."; + if (IsRecoveryMode()) { + LOG(INFO) << "First stage mount skipped (recovery mode)"; + } else { + if (!fsm) { + fsm = CreateFirstStageMount(); + } + if (!fsm) { + LOG(FATAL) << "FirstStageMount not available"; + } + + if (!created_devices && !fsm->DoCreateDevices()) { + LOG(FATAL) << "Failed to create devices required for first stage mount"; + } + + if (!fsm->DoFirstStageMount()) { + LOG(FATAL) << "Failed to mount required partitions early ..."; + } } struct stat new_root_info; diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp index 07ce4588d039..4961f6a63ed6 100644 --- a/init/first_stage_mount.cpp +++ b/init/first_stage_mount.cpp @@ -76,21 +76,21 @@ namespace init { // Class Declarations // ------------------ -class FirstStageMount { +class FirstStageMountVBootV2 : public FirstStageMount { public: - FirstStageMount(Fstab fstab); - virtual ~FirstStageMount() = default; + friend void SetInitAvbVersionInRecovery(); - // The factory method to create a FirstStageMountVBootV2 instance. - static Result> Create(); - bool DoCreateDevices(); // Creates devices and logical partitions from storage devices - bool DoFirstStageMount(); // Mounts fstab entries read from device tree. - bool InitDevices(); + FirstStageMountVBootV2(Fstab fstab); + virtual ~FirstStageMountVBootV2() = default; + + bool DoCreateDevices() override; + bool DoFirstStageMount() override; - protected: + private: + bool InitDevices(); bool InitRequiredDevices(std::set devices); bool CreateLogicalPartitions(); - bool CreateSnapshotPartitions(android::snapshot::SnapshotManager* sm); + bool CreateSnapshotPartitions(SnapshotManager* sm); bool MountPartition(const Fstab::iterator& begin, bool erase_same_mounts, Fstab::iterator* end = nullptr); @@ -106,9 +106,10 @@ class FirstStageMount { // revocation check by DSU installation service. void CopyDsuAvbKeys(); - // Pure virtual functions. - virtual bool GetDmVerityDevices(std::set* devices) = 0; - virtual bool SetUpDmVerity(FstabEntry* fstab_entry) = 0; + bool GetDmVerityDevices(std::set* devices); + bool SetUpDmVerity(FstabEntry* fstab_entry); + + bool InitAvbHandle(); bool need_dm_verity_; bool dsu_not_on_userdata_ = false; @@ -122,19 +123,6 @@ class FirstStageMount { // Reads all AVB keys before chroot into /system, as they might be used // later when mounting other partitions, e.g., /vendor and /product. std::map> preload_avb_key_blobs_; -}; - -class FirstStageMountVBootV2 : public FirstStageMount { - public: - friend void SetInitAvbVersionInRecovery(); - - FirstStageMountVBootV2(Fstab fstab); - ~FirstStageMountVBootV2() override = default; - - protected: - bool GetDmVerityDevices(std::set* devices) override; - bool SetUpDmVerity(FstabEntry* fstab_entry) override; - bool InitAvbHandle(); std::vector vbmeta_partitions_; AvbUniquePtr avb_handle_; @@ -220,10 +208,6 @@ static bool IsStandaloneImageRollback(const AvbHandle& builtin_vbmeta, // Class Definitions // ----------------- -FirstStageMount::FirstStageMount(Fstab fstab) : need_dm_verity_(false), fstab_(std::move(fstab)) { - super_partition_name_ = fs_mgr_get_super_partition_name(); -} - Result> FirstStageMount::Create() { auto fstab = ReadFirstStageFstab(); if (!fstab.ok()) { @@ -233,7 +217,7 @@ Result> FirstStageMount::Create() { return std::make_unique(std::move(*fstab)); } -bool FirstStageMount::DoCreateDevices() { +bool FirstStageMountVBootV2::DoCreateDevices() { if (!InitDevices()) return false; // Mount /metadata before creating logical partitions, since we need to @@ -255,7 +239,7 @@ bool FirstStageMount::DoCreateDevices() { return true; } -bool FirstStageMount::DoFirstStageMount() { +bool FirstStageMountVBootV2::DoFirstStageMount() { if (!IsDmLinearEnabled() && fstab_.empty()) { // Nothing to mount. LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)"; @@ -267,7 +251,7 @@ bool FirstStageMount::DoFirstStageMount() { return true; } -bool FirstStageMount::InitDevices() { +bool FirstStageMountVBootV2::InitDevices() { std::set devices; GetSuperDeviceName(&devices); @@ -288,14 +272,14 @@ bool FirstStageMount::InitDevices() { return true; } -bool FirstStageMount::IsDmLinearEnabled() { +bool FirstStageMountVBootV2::IsDmLinearEnabled() { for (const auto& entry : fstab_) { if (entry.fs_mgr_flags.logical) return true; } return false; } -void FirstStageMount::GetSuperDeviceName(std::set* devices) { +void FirstStageMountVBootV2::GetSuperDeviceName(std::set* devices) { // Add any additional devices required for dm-linear mappings. if (!IsDmLinearEnabled()) { return; @@ -307,7 +291,7 @@ void FirstStageMount::GetSuperDeviceName(std::set* devices) { // Creates devices with uevent->partition_name matching ones in the given set. // Found partitions will then be removed from it for the subsequent member // function to check which devices are NOT created. -bool FirstStageMount::InitRequiredDevices(std::set devices) { +bool FirstStageMountVBootV2::InitRequiredDevices(std::set devices) { if (!block_dev_init_.InitDeviceMapper()) { return false; } @@ -317,7 +301,8 @@ bool FirstStageMount::InitRequiredDevices(std::set devices) { return block_dev_init_.InitDevices(std::move(devices)); } -bool FirstStageMount::InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata) { +bool FirstStageMountVBootV2::InitDmLinearBackingDevices( + const android::fs_mgr::LpMetadata& metadata) { std::set devices; auto partition_names = android::fs_mgr::GetBlockDevicePartitionNames(metadata); @@ -334,7 +319,7 @@ bool FirstStageMount::InitDmLinearBackingDevices(const android::fs_mgr::LpMetada return InitRequiredDevices(std::move(devices)); } -bool FirstStageMount::CreateLogicalPartitions() { +bool FirstStageMountVBootV2::CreateLogicalPartitions() { if (!IsDmLinearEnabled()) { return true; } @@ -365,7 +350,7 @@ bool FirstStageMount::CreateLogicalPartitions() { return android::fs_mgr::CreateLogicalPartitions(*metadata.get(), super_path_); } -bool FirstStageMount::CreateSnapshotPartitions(SnapshotManager* sm) { +bool FirstStageMountVBootV2::CreateSnapshotPartitions(SnapshotManager* sm) { // When COW images are present for snapshots, they are stored on // the data partition. if (!InitRequiredDevices({"userdata"})) { @@ -400,8 +385,8 @@ bool FirstStageMount::CreateSnapshotPartitions(SnapshotManager* sm) { return true; } -bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts, - Fstab::iterator* end) { +bool FirstStageMountVBootV2::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts, + Fstab::iterator* end) { // Sets end to begin + 1, so we can just return on failure below. if (end) { *end = begin + 1; @@ -445,7 +430,7 @@ bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_sa return mounted; } -void FirstStageMount::PreloadAvbKeys() { +void FirstStageMountVBootV2::PreloadAvbKeys() { for (const auto& entry : fstab_) { // No need to cache the key content if it's empty, or is already cached. if (entry.avb_keys.empty() || preload_avb_key_blobs_.count(entry.avb_keys)) { @@ -492,7 +477,7 @@ void FirstStageMount::PreloadAvbKeys() { // If system is in the fstab then we're not a system-as-root device, and in // this case, we mount system first then pivot to it. From that point on, // we are effectively identical to a system-as-root device. -bool FirstStageMount::TrySwitchSystemAsRoot() { +bool FirstStageMountVBootV2::TrySwitchSystemAsRoot() { UseDsuIfPresent(); // Preloading all AVB keys from the ramdisk before switching root to /system. PreloadAvbKeys(); @@ -521,7 +506,7 @@ bool FirstStageMount::TrySwitchSystemAsRoot() { return true; } -bool FirstStageMount::MountPartitions() { +bool FirstStageMountVBootV2::MountPartitions() { if (!TrySwitchSystemAsRoot()) return false; if (!SkipMountingPartitions(&fstab_, true /* verbose */)) return false; @@ -604,7 +589,7 @@ bool FirstStageMount::MountPartitions() { // copy files to /metadata is NOT fatal, because it is auxiliary to perform // public key matching before booting into DSU images on next boot. The actual // public key matching will still be done on next boot to DSU. -void FirstStageMount::CopyDsuAvbKeys() { +void FirstStageMountVBootV2::CopyDsuAvbKeys() { std::error_code ec; // Removing existing keys in gsi::kDsuAvbKeyDir as they might be stale. std::filesystem::remove_all(gsi::kDsuAvbKeyDir, ec); @@ -620,7 +605,7 @@ void FirstStageMount::CopyDsuAvbKeys() { } } -void FirstStageMount::UseDsuIfPresent() { +void FirstStageMountVBootV2::UseDsuIfPresent() { std::string error; if (!android::gsi::CanBootIntoGsi(&error)) { @@ -657,10 +642,10 @@ void FirstStageMount::UseDsuIfPresent() { TransformFstabForDsu(&fstab_, active_dsu, dsu_partitions); } -// First retrieve any vbmeta partitions from device tree (legacy) then read through the fstab -// for any further vbmeta partitions. FirstStageMountVBootV2::FirstStageMountVBootV2(Fstab fstab) - : FirstStageMount(std::move(fstab)), avb_handle_(nullptr) { + : need_dm_verity_(false), fstab_(std::move(fstab)), avb_handle_(nullptr) { + super_partition_name_ = fs_mgr_get_super_partition_name(); + std::string device_tree_vbmeta_parts; read_android_dt_file("vbmeta/parts", &device_tree_vbmeta_parts); @@ -793,39 +778,6 @@ bool FirstStageMountVBootV2::InitAvbHandle() { return true; } -// Public functions -// ---------------- -// Creates devices and logical partitions from storage devices -bool DoCreateDevices() { - auto fsm = FirstStageMount::Create(); - if (!fsm.ok()) { - LOG(ERROR) << "Failed to create FirstStageMount: " << fsm.error(); - return false; - } - return (*fsm)->DoCreateDevices(); -} - -// Mounts partitions specified by fstab in device tree. -bool DoFirstStageMount(bool create_devices) { - // Skips first stage mount if we're in recovery mode. - if (IsRecoveryMode()) { - LOG(INFO) << "First stage mount skipped (recovery mode)"; - return true; - } - - auto fsm = FirstStageMount::Create(); - if (!fsm.ok()) { - LOG(ERROR) << "Failed to create FirstStageMount " << fsm.error(); - return false; - } - - if (create_devices) { - if (!(*fsm)->DoCreateDevices()) return false; - } - - return (*fsm)->DoFirstStageMount(); -} - void SetInitAvbVersionInRecovery() { if (!IsRecoveryMode()) { LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not in recovery mode)"; diff --git a/init/first_stage_mount.h b/init/first_stage_mount.h index 2f4e663825bf..ab14966c67b5 100644 --- a/init/first_stage_mount.h +++ b/init/first_stage_mount.h @@ -16,11 +16,28 @@ #pragma once +#include + +#include "result.h" + namespace android { namespace init { -bool DoCreateDevices(); -bool DoFirstStageMount(bool create_devices); +class FirstStageMount { + public: + virtual ~FirstStageMount() = default; + + // The factory method to create a FirstStageMount instance. + static Result> Create(); + // Creates devices and logical partitions from storage devices + virtual bool DoCreateDevices() = 0; + // Mounts fstab entries read from device tree. + virtual bool DoFirstStageMount() = 0; + + protected: + FirstStageMount() = default; +}; + void SetInitAvbVersionInRecovery(); } // namespace init From 440354afa08a60d396d24024cf8f87774cab88ee Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Tue, 4 Jul 2023 15:17:36 +0100 Subject: [PATCH 0164/1487] Support for conditionally mounting /vendor partition in Microdroid first_stage_init will only mount the /vendor partition in Microdroid if the androidboot.microdroid.mount_vendor=1 is provided in the kernel cmdline. Bug: 285855433 Test: atest MicrodroidTestApp Change-Id: I5b840b5474bc52ec2696a0ba6ead0476acddfb1a --- init/first_stage_init.cpp | 8 ++++---- init/first_stage_mount.cpp | 33 +++++++++++++++++++++++++++------ init/first_stage_mount.h | 2 +- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index e1d383a0c16c..e871da20b824 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -257,8 +257,8 @@ static BootMode GetBootMode(const std::string& cmdline, const std::string& bootc return BootMode::NORMAL_MODE; } -static std::unique_ptr CreateFirstStageMount() { - auto ret = FirstStageMount::Create(); +static std::unique_ptr CreateFirstStageMount(const std::string& cmdline) { + auto ret = FirstStageMount::Create(cmdline); if (ret.ok()) { return std::move(*ret); } else { @@ -396,7 +396,7 @@ int FirstStageMain(int argc, char** argv) { bool created_devices = false; if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) { if (!IsRecoveryMode()) { - fsm = CreateFirstStageMount(); + fsm = CreateFirstStageMount(cmdline); if (fsm) { created_devices = fsm->DoCreateDevices(); if (!created_devices) { @@ -456,7 +456,7 @@ int FirstStageMain(int argc, char** argv) { LOG(INFO) << "First stage mount skipped (recovery mode)"; } else { if (!fsm) { - fsm = CreateFirstStageMount(); + fsm = CreateFirstStageMount(cmdline); } if (!fsm) { LOG(FATAL) << "FirstStageMount not available"; diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp index 4961f6a63ed6..d0f68a80c26b 100644 --- a/init/first_stage_mount.cpp +++ b/init/first_stage_mount.cpp @@ -138,7 +138,7 @@ static inline bool IsDtVbmetaCompatible(const Fstab& fstab) { return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta"); } -static Result ReadFirstStageFstab() { +static Result ReadFirstStageFstabAndroid() { Fstab fstab; if (!ReadFstabFromDt(&fstab)) { if (ReadDefaultFstab(&fstab)) { @@ -154,6 +154,24 @@ static Result ReadFirstStageFstab() { return fstab; } +// Note: this is a temporary solution to avoid blocking devs that depend on /vendor partition in +// Microdroid. For the proper solution the /vendor fstab should probably be defined in the DT. +// TODO(b/285855430): refactor this +// TODO(b/285855436): verify key microdroid-vendor was signed with. +// TODO(b/285855436): should be mounted on top of dm-verity device. +static Result ReadFirstStageFstabMicrodroid(const std::string& cmdline) { + Fstab fstab; + if (!ReadDefaultFstab(&fstab)) { + return Error() << "failed to read fstab"; + } + if (cmdline.find("androidboot.microdroid.mount_vendor=1") == std::string::npos) { + // We weren't asked to mount /vendor partition, filter it out from the fstab. + auto predicate = [](const auto& entry) { return entry.mount_point == "/vendor"; }; + fstab.erase(std::remove_if(fstab.begin(), fstab.end(), predicate), fstab.end()); + } + return fstab; +} + static bool GetRootEntry(FstabEntry* root_entry) { Fstab proc_mounts; if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) { @@ -206,10 +224,13 @@ static bool IsStandaloneImageRollback(const AvbHandle& builtin_vbmeta, return rollbacked; } -// Class Definitions -// ----------------- -Result> FirstStageMount::Create() { - auto fstab = ReadFirstStageFstab(); +Result> FirstStageMount::Create(const std::string& cmdline) { + Result fstab; + if (IsMicrodroid()) { + fstab = ReadFirstStageFstabMicrodroid(cmdline); + } else { + fstab = ReadFirstStageFstabAndroid(); + } if (!fstab.ok()) { return fstab.error(); } @@ -784,7 +805,7 @@ void SetInitAvbVersionInRecovery() { return; } - auto fstab = ReadFirstStageFstab(); + auto fstab = ReadFirstStageFstabAndroid(); if (!fstab.ok()) { LOG(ERROR) << fstab.error(); return; diff --git a/init/first_stage_mount.h b/init/first_stage_mount.h index ab14966c67b5..54501d8df6f5 100644 --- a/init/first_stage_mount.h +++ b/init/first_stage_mount.h @@ -28,7 +28,7 @@ class FirstStageMount { virtual ~FirstStageMount() = default; // The factory method to create a FirstStageMount instance. - static Result> Create(); + static Result> Create(const std::string& cmdline); // Creates devices and logical partitions from storage devices virtual bool DoCreateDevices() = 0; // Mounts fstab entries read from device tree. From df0e96e962af40df7d6a89f61642e75ff0b6284c Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Tue, 4 Jul 2023 17:18:02 +0100 Subject: [PATCH 0165/1487] Only allow debuggable Microdroid VMs to mount /vendor Until the verification of the /vendor partition we restrict the usage of the feature to only debuggable VMs. If a non-debuggable Microdroid VM is requested to mount /vendor, first_stage_init will crash and the VM won't boot. Bug: 285855436 Test: vm run-microdroid --debug none --vendor test_vendor.img Change-Id: I9d44ad5c1d971bac1a9173c291ce61b628f2f8e9 --- init/first_stage_init.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index e871da20b824..7fabbac517a2 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -357,6 +357,18 @@ int FirstStageMain(int argc, char** argv) { LOG(INFO) << "init first stage started!"; + // We only allow /vendor partition in debuggable Microdrod until it is verified during boot. + // TODO(b/285855436): remove this check. + if (IsMicrodroid()) { + bool mount_vendor = + cmdline.find("androidboot.microdroid.mount_vendor=1") != std::string::npos; + bool debuggable = + bootconfig.find("androidboot.microdroid.debuggable = \"1\"") != std::string::npos; + if (mount_vendor && !debuggable) { + LOG(FATAL) << "Attempted to mount /vendor partition for non-debuggable Microdroid VM"; + } + } + auto old_root_dir = std::unique_ptr{opendir("/"), closedir}; if (!old_root_dir) { PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk"; From 9fbd1683d4d64a250d379df75ca151eb5c37b257 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Mon, 10 Jul 2023 14:56:20 +0100 Subject: [PATCH 0166/1487] Add safety comments. These will soon be required by a lint. Bug: 290018030 Test: m vm virtmgr Change-Id: Id628b2a88f1cb0235fbccc748c52514e64561fe5 --- debuggerd/rust/tombstoned_client/src/lib.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/debuggerd/rust/tombstoned_client/src/lib.rs b/debuggerd/rust/tombstoned_client/src/lib.rs index 5c8abef2cdb8..d1b5e696e481 100644 --- a/debuggerd/rust/tombstoned_client/src/lib.rs +++ b/debuggerd/rust/tombstoned_client/src/lib.rs @@ -39,20 +39,26 @@ pub struct TombstonedConnection { } impl TombstonedConnection { + /// # Safety + /// + /// The file descriptors must be valid and open. unsafe fn from_raw_fds( tombstoned_socket: RawFd, text_output_fd: RawFd, proto_output_fd: RawFd, ) -> Self { Self { - tombstoned_socket: File::from_raw_fd(tombstoned_socket), + // SAFETY: The caller guarantees that the file descriptor is valid and open. + tombstoned_socket: unsafe { File::from_raw_fd(tombstoned_socket) }, text_output: if text_output_fd >= 0 { - Some(File::from_raw_fd(text_output_fd)) + // SAFETY: The caller guarantees that the file descriptor is valid and open. + Some(unsafe { File::from_raw_fd(text_output_fd) }) } else { None }, proto_output: if proto_output_fd >= 0 { - Some(File::from_raw_fd(proto_output_fd)) + // SAFETY: The caller guarantees that the file descriptor is valid and open. + Some(unsafe { File::from_raw_fd(proto_output_fd) }) } else { None }, @@ -71,6 +77,8 @@ impl TombstonedConnection { &mut proto_output_fd, dump_type, ) { + // SAFETY: If tombstoned_connect_files returns successfully then they file descriptors + // are valid and open. Ok(unsafe { Self::from_raw_fds(tombstoned_socket, text_output_fd, proto_output_fd) }) } else { Err(Error) @@ -146,8 +154,6 @@ mod tests { .write_all(b"test data") .expect("Failed to write to text output FD."); - connection - .notify_completion() - .expect("Failed to notify completion."); + connection.notify_completion().expect("Failed to notify completion."); } } From ab74dbb197df58609babd43b3acfb11a58fd9992 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 10 Jul 2023 17:58:33 +0000 Subject: [PATCH 0167/1487] init: simplify queue_fs_event() Combine some cases that are handled identically, and remove the 'userdata_remount' parameter which is unused. No change in behavior. Test: presubmit Change-Id: I0567e47d02942af7865c155dab76e6d0e9d71a1f --- init/builtins.cpp | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/init/builtins.cpp b/init/builtins.cpp index 585eca25da88..2176233aab96 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -577,7 +577,7 @@ static void import_late(const std::vector& rc_paths) { * * return code is processed based on input code */ -static Result queue_fs_event(int code, bool userdata_remount) { +static Result queue_fs_event(int code) { if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) { SetProperty("ro.crypto.state", "unsupported"); ActionManager::GetInstance().QueueEventTrigger("nonencrypted"); @@ -591,27 +591,9 @@ static Result queue_fs_event(int code, bool userdata_remount) { const std::vector options = {"--wipe_data", "--reason=fs_mgr_mount_all" }; return reboot_into_recovery(options); /* If reboot worked, there is no return. */ - } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) { - if (!FscryptInstallKeyring()) { - return Error() << "FscryptInstallKeyring() failed"; - } - SetProperty("ro.crypto.state", "encrypted"); - - // Although encrypted, we have device key, so we do not need to - // do anything different from the nonencrypted case. - ActionManager::GetInstance().QueueEventTrigger("nonencrypted"); - return {}; - } else if (code == FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED) { - if (!FscryptInstallKeyring()) { - return Error() << "FscryptInstallKeyring() failed"; - } - SetProperty("ro.crypto.state", "encrypted"); - - // Although encrypted, vold has already set the device up, so we do not need to - // do anything different from the nonencrypted case. - ActionManager::GetInstance().QueueEventTrigger("nonencrypted"); - return {}; - } else if (code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) { + } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED || + code == FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED || + code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) { if (!FscryptInstallKeyring()) { return Error() << "FscryptInstallKeyring() failed"; } @@ -683,7 +665,7 @@ static Result do_mount_all(const BuiltinArguments& args) { if (queue_event) { /* queue_fs_event will queue event based on mount_fstab return code * and return processed return code*/ - auto queue_fs_result = queue_fs_event(mount_fstab_result.code, false); + auto queue_fs_result = queue_fs_event(mount_fstab_result.code); if (!queue_fs_result.ok()) { return Error() << "queue_fs_event() failed: " << queue_fs_result.error(); } @@ -1217,7 +1199,7 @@ static Result do_remount_userdata(const BuiltinArguments& args) { "/metadata/userspacereboot/mount_info.txt"); trigger_shutdown("reboot,mount_userdata_failed"); } - if (auto result = queue_fs_event(initial_mount_fstab_return_code, true); !result.ok()) { + if (auto result = queue_fs_event(initial_mount_fstab_return_code); !result.ok()) { return Error() << "queue_fs_event() failed: " << result.error(); } return {}; From 8bb751dc8a1499f24add9e0831ab347feb2c3878 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 17 Feb 2023 01:20:52 -0800 Subject: [PATCH 0168/1487] snapuserd: Split the server into two classes. This splits server into two classes: one that handles the IPC requests, and one that managers snapshot handlers. This will allow embedding of the snapshot handling code, without booting up a server. It'll also make testing much easier. The handler code has been further placed behind a virtual interface, though this is likely unnecessary unless we start testing the server logic itself (or attempt to unify the S and T+ versions of snapuserd). Bug: 269361087 Test: ota Ignore-AOSP-First: cherry-pick from aosp Change-Id: I3ca3ad9c8c1fb910a1c7bf9f44165e2f44c930c9 Merged-In: I3ca3ad9c8c1fb910a1c7bf9f44165e2f44c930c9 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 1 + .../snapuserd/snapuserd_daemon.cpp | 2 +- .../user-space-merge/handler_manager.cpp | 371 ++++++++++++++++++ .../user-space-merge/handler_manager.h | 131 +++++++ .../user-space-merge/snapuserd_server.cpp | 338 +--------------- .../user-space-merge/snapuserd_server.h | 58 +-- 6 files changed, 526 insertions(+), 375 deletions(-) create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index dd11a33daf28..65f3d6d297ed 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -62,6 +62,7 @@ cc_library_static { "dm-snapshot-merge/snapuserd_worker.cpp", "dm-snapshot-merge/snapuserd_readahead.cpp", "snapuserd_buffer.cpp", + "user-space-merge/handler_manager.cpp", "user-space-merge/snapuserd_core.cpp", "user-space-merge/snapuserd_dm_user.cpp", "user-space-merge/snapuserd_merge.cpp", diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp index ae20e1fa479e..36dad3343d3e 100644 --- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp +++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp @@ -114,7 +114,7 @@ bool Daemon::StartServerForUserspaceSnapshots(int arg_start, int argc, char** ar return false; } auto handler = user_server_.AddHandler(parts[0], parts[1], parts[2], parts[3]); - if (!handler || !user_server_.StartHandler(handler)) { + if (!handler || !user_server_.StartHandler(parts[0])) { return false; } } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp new file mode 100644 index 000000000000..c5150c411d02 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp @@ -0,0 +1,371 @@ +// Copyright (C) 2023 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 "handler_manager.h" + +#include + +#include + +#include "snapuserd_core.h" + +namespace android { +namespace snapshot { + +static constexpr uint8_t kMaxMergeThreads = 2; + +void HandlerThread::FreeResources() { + // Each worker thread holds a reference to snapuserd. + // Clear them so that all the resources + // held by snapuserd is released + if (snapuserd_) { + snapuserd_->FreeResources(); + snapuserd_ = nullptr; + } +} + +SnapshotHandlerManager::SnapshotHandlerManager() { + monitor_merge_event_fd_.reset(eventfd(0, EFD_CLOEXEC)); + if (monitor_merge_event_fd_ == -1) { + PLOG(FATAL) << "monitor_merge_event_fd_: failed to create eventfd"; + } +} + +std::shared_ptr SnapshotHandlerManager::AddHandler( + const std::string& misc_name, const std::string& cow_device_path, + const std::string& backing_device, const std::string& base_path_merge, + int num_worker_threads, bool use_iouring, bool perform_verification) { + auto snapuserd = std::make_shared(misc_name, cow_device_path, backing_device, + base_path_merge, num_worker_threads, + use_iouring, perform_verification); + if (!snapuserd->InitCowDevice()) { + LOG(ERROR) << "Failed to initialize Snapuserd"; + return nullptr; + } + + if (!snapuserd->InitializeWorkers()) { + LOG(ERROR) << "Failed to initialize workers"; + return nullptr; + } + + auto handler = std::make_shared(snapuserd); + { + std::lock_guard lock(lock_); + if (FindHandler(&lock, misc_name) != dm_users_.end()) { + LOG(ERROR) << "Handler already exists: " << misc_name; + return nullptr; + } + dm_users_.push_back(handler); + } + return handler; +} + +bool SnapshotHandlerManager::StartHandler(const std::string& misc_name) { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + LOG(ERROR) << "Could not find handler: " << misc_name; + return false; + } + if (!(*iter)->snapuserd() || (*iter)->snapuserd()->IsAttached()) { + LOG(ERROR) << "Tried to re-attach control device: " << misc_name; + return false; + } + if (!StartHandler(*iter)) { + return false; + } + return true; +} + +bool SnapshotHandlerManager::StartHandler(const std::shared_ptr& handler) { + if (handler->snapuserd()->IsAttached()) { + LOG(ERROR) << "Handler already attached"; + return false; + } + + handler->snapuserd()->AttachControlDevice(); + + handler->thread() = std::thread(std::bind(&SnapshotHandlerManager::RunThread, this, handler)); + return true; +} + +bool SnapshotHandlerManager::DeleteHandler(const std::string& misc_name) { + { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + // After merge is completed, we swap dm-user table with + // the underlying dm-linear base device. Hence, worker + // threads would have terminted and was removed from + // the list. + LOG(DEBUG) << "Could not find handler: " << misc_name; + return true; + } + + if (!(*iter)->ThreadTerminated()) { + (*iter)->snapuserd()->NotifyIOTerminated(); + } + } + if (!RemoveAndJoinHandler(misc_name)) { + return false; + } + return true; +} + +void SnapshotHandlerManager::RunThread(std::shared_ptr handler) { + LOG(INFO) << "Entering thread for handler: " << handler->misc_name(); + + if (!handler->snapuserd()->Start()) { + LOG(ERROR) << " Failed to launch all worker threads"; + } + + handler->snapuserd()->CloseFds(); + bool merge_completed = handler->snapuserd()->CheckMergeCompletionStatus(); + handler->snapuserd()->UnmapBufferRegion(); + + auto misc_name = handler->misc_name(); + LOG(INFO) << "Handler thread about to exit: " << misc_name; + + { + std::lock_guard lock(lock_); + if (merge_completed) { + num_partitions_merge_complete_ += 1; + active_merge_threads_ -= 1; + WakeupMonitorMergeThread(); + } + handler->SetThreadTerminated(); + auto iter = FindHandler(&lock, handler->misc_name()); + if (iter == dm_users_.end()) { + // RemoveAndJoinHandler() already removed us from the list, and is + // now waiting on a join(), so just return. Additionally, release + // all the resources held by snapuserd object which are shared + // by worker threads. This should be done when the last reference + // of "handler" is released; but we will explicitly release here + // to make sure snapuserd object is freed as it is the biggest + // consumer of memory in the daemon. + handler->FreeResources(); + LOG(INFO) << "Exiting handler thread to allow for join: " << misc_name; + return; + } + + LOG(INFO) << "Exiting handler thread and freeing resources: " << misc_name; + + if (handler->snapuserd()->IsAttached()) { + handler->thread().detach(); + } + + // Important: free resources within the lock. This ensures that if + // WaitForDelete() is called, the handler is either in the list, or + // it's not and its resources are guaranteed to be freed. + handler->FreeResources(); + dm_users_.erase(iter); + } +} + +bool SnapshotHandlerManager::InitiateMerge(const std::string& misc_name) { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + LOG(ERROR) << "Could not find handler: " << misc_name; + return false; + } + + return StartMerge(&lock, *iter); +} + +bool SnapshotHandlerManager::StartMerge(std::lock_guard* proof_of_lock, + const std::shared_ptr& handler) { + CHECK(proof_of_lock); + + if (!handler->snapuserd()->IsAttached()) { + LOG(ERROR) << "Handler not attached to dm-user - Merge thread cannot be started"; + return false; + } + + handler->snapuserd()->MonitorMerge(); + + if (!is_merge_monitor_started_) { + std::thread(&SnapshotHandlerManager::MonitorMerge, this).detach(); + is_merge_monitor_started_ = true; + } + + merge_handlers_.push(handler); + WakeupMonitorMergeThread(); + return true; +} + +void SnapshotHandlerManager::WakeupMonitorMergeThread() { + uint64_t notify = 1; + ssize_t rc = TEMP_FAILURE_RETRY(write(monitor_merge_event_fd_.get(), ¬ify, sizeof(notify))); + if (rc < 0) { + PLOG(FATAL) << "failed to notify monitor merge thread"; + } +} + +void SnapshotHandlerManager::MonitorMerge() { + while (!stop_monitor_merge_thread_) { + uint64_t testVal; + ssize_t ret = + TEMP_FAILURE_RETRY(read(monitor_merge_event_fd_.get(), &testVal, sizeof(testVal))); + if (ret == -1) { + PLOG(FATAL) << "Failed to read from eventfd"; + } else if (ret == 0) { + LOG(FATAL) << "Hit EOF on eventfd"; + } + + LOG(INFO) << "MonitorMerge: active-merge-threads: " << active_merge_threads_; + { + std::lock_guard lock(lock_); + while (active_merge_threads_ < kMaxMergeThreads && merge_handlers_.size() > 0) { + auto handler = merge_handlers_.front(); + merge_handlers_.pop(); + + if (!handler->snapuserd()) { + LOG(INFO) << "MonitorMerge: skipping deleted handler: " << handler->misc_name(); + continue; + } + + LOG(INFO) << "Starting merge for partition: " + << handler->snapuserd()->GetMiscName(); + handler->snapuserd()->InitiateMerge(); + active_merge_threads_ += 1; + } + } + } + + LOG(INFO) << "Exiting MonitorMerge: size: " << merge_handlers_.size(); +} + +std::string SnapshotHandlerManager::GetMergeStatus(const std::string& misc_name) { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + LOG(ERROR) << "Could not find handler: " << misc_name; + return {}; + } + + return (*iter)->snapuserd()->GetMergeStatus(); +} + +double SnapshotHandlerManager::GetMergePercentage() { + std::lock_guard lock(lock_); + + double percentage = 0.0; + int n = 0; + + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + auto& th = (*iter)->thread(); + if (th.joinable()) { + // Merge percentage by individual partitions wherein merge is still + // in-progress + percentage += (*iter)->snapuserd()->GetMergePercentage(); + n += 1; + } + } + + // Calculate final merge including those partitions where merge was already + // completed - num_partitions_merge_complete_ will track them when each + // thread exists in RunThread. + int total_partitions = n + num_partitions_merge_complete_; + + if (total_partitions) { + percentage = ((num_partitions_merge_complete_ * 100.0) + percentage) / total_partitions; + } + + LOG(DEBUG) << "Merge %: " << percentage + << " num_partitions_merge_complete_: " << num_partitions_merge_complete_ + << " total_partitions: " << total_partitions << " n: " << n; + return percentage; +} + +bool SnapshotHandlerManager::GetVerificationStatus() { + std::lock_guard lock(lock_); + + bool status = true; + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + auto& th = (*iter)->thread(); + if (th.joinable() && status) { + status = (*iter)->snapuserd()->CheckPartitionVerification() && status; + } else { + // return immediately if there is a failure + return false; + } + } + + return status; +} + +bool SnapshotHandlerManager::RemoveAndJoinHandler(const std::string& misc_name) { + std::shared_ptr handler; + { + std::lock_guard lock(lock_); + + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + // Client already deleted. + return true; + } + handler = std::move(*iter); + dm_users_.erase(iter); + } + + auto& th = handler->thread(); + if (th.joinable()) { + th.join(); + } + return true; +} + +void SnapshotHandlerManager::TerminateMergeThreads() { + std::lock_guard guard(lock_); + + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + if (!(*iter)->ThreadTerminated()) { + (*iter)->snapuserd()->NotifyIOTerminated(); + } + } +} + +void SnapshotHandlerManager::JoinAllThreads() { + // Acquire the thread list within the lock. + std::vector> dm_users; + { + std::lock_guard guard(lock_); + dm_users = std::move(dm_users_); + } + + for (auto& client : dm_users) { + auto& th = client->thread(); + + if (th.joinable()) th.join(); + } + + stop_monitor_merge_thread_ = true; + WakeupMonitorMergeThread(); +} + +auto SnapshotHandlerManager::FindHandler(std::lock_guard* proof_of_lock, + const std::string& misc_name) -> HandlerList::iterator { + CHECK(proof_of_lock); + + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + if ((*iter)->misc_name() == misc_name) { + return iter; + } + } + return dm_users_.end(); +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h new file mode 100644 index 000000000000..b7ddac19f28a --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h @@ -0,0 +1,131 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace android { +namespace snapshot { + +class SnapshotHandler; + +class HandlerThread { + public: + explicit HandlerThread(std::shared_ptr snapuserd); + + void FreeResources(); + const std::shared_ptr& snapuserd() const { return snapuserd_; } + std::thread& thread() { return thread_; } + + const std::string& misc_name() const { return misc_name_; } + bool ThreadTerminated() { return thread_terminated_; } + void SetThreadTerminated() { thread_terminated_ = true; } + + private: + std::thread thread_; + std::shared_ptr snapuserd_; + std::string misc_name_; + bool thread_terminated_ = false; +}; + +class ISnapshotHandlerManager { + public: + virtual ~ISnapshotHandlerManager() {} + + // Add a new snapshot handler but do not start serving requests yet. + virtual std::shared_ptr AddHandler(const std::string& misc_name, + const std::string& cow_device_path, + const std::string& backing_device, + const std::string& base_path_merge, + int num_worker_threads, bool use_iouring, + bool perform_verification) = 0; + + // Start serving requests on a snapshot handler. + virtual bool StartHandler(const std::string& misc_name) = 0; + + // Stop serving requests on a snapshot handler and remove it. + virtual bool DeleteHandler(const std::string& misc_name) = 0; + + // Begin merging blocks on the given snapshot handler. + virtual bool InitiateMerge(const std::string& misc_name) = 0; + + // Return a string containing a status code indicating the merge status + // on the handler. Returns empty on error. + virtual std::string GetMergeStatus(const std::string& misc_name) = 0; + + // Wait until all handlers have terminated. + virtual void JoinAllThreads() = 0; + + // Stop any in-progress merge threads. + virtual void TerminateMergeThreads() = 0; + + // Returns the merge progress across all merging snapshot handlers. + virtual double GetMergePercentage() = 0; + + // Returns whether all snapshots have verified. + virtual bool GetVerificationStatus() = 0; +}; + +class SnapshotHandlerManager final : public ISnapshotHandlerManager { + public: + SnapshotHandlerManager(); + std::shared_ptr AddHandler(const std::string& misc_name, + const std::string& cow_device_path, + const std::string& backing_device, + const std::string& base_path_merge, + int num_worker_threads, bool use_iouring, + bool perform_verification) override; + bool StartHandler(const std::string& misc_name) override; + bool DeleteHandler(const std::string& misc_name) override; + bool InitiateMerge(const std::string& misc_name) override; + std::string GetMergeStatus(const std::string& misc_name) override; + void JoinAllThreads() override; + void TerminateMergeThreads() override; + double GetMergePercentage() override; + bool GetVerificationStatus() override; + + private: + bool StartHandler(const std::shared_ptr& handler); + void RunThread(std::shared_ptr handler); + bool StartMerge(std::lock_guard* proof_of_lock, + const std::shared_ptr& handler); + void MonitorMerge(); + void WakeupMonitorMergeThread(); + bool RemoveAndJoinHandler(const std::string& misc_name); + + // Find a HandlerThread within a lock. + using HandlerList = std::vector>; + HandlerList::iterator FindHandler(std::lock_guard* proof_of_lock, + const std::string& misc_name); + + std::mutex lock_; + HandlerList dm_users_; + + bool is_merge_monitor_started_ = false; + bool stop_monitor_merge_thread_ = false; + int active_merge_threads_ = 0; + int num_partitions_merge_complete_ = 0; + std::queue> merge_handlers_; + android::base::unique_fd monitor_merge_event_fd_; +}; + +} // namespace snapshot +} // namespace android 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 b7ce2109adfe..cc8115f5f800 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp @@ -62,11 +62,8 @@ DaemonOps UserSnapshotServer::Resolveop(std::string& input) { } UserSnapshotServer::UserSnapshotServer() { - monitor_merge_event_fd_.reset(eventfd(0, EFD_CLOEXEC)); - if (monitor_merge_event_fd_ == -1) { - PLOG(FATAL) << "monitor_merge_event_fd_: failed to create eventfd"; - } terminating_ = false; + handlers_ = std::make_unique(); } UserSnapshotServer::~UserSnapshotServer() { @@ -99,7 +96,7 @@ void UserSnapshotServer::Parsemsg(std::string const& msg, const char delim, void UserSnapshotServer::ShutdownThreads() { terminating_ = true; - JoinAllThreads(); + handlers_->JoinAllThreads(); } HandlerThread::HandlerThread(std::shared_ptr snapuserd) @@ -166,17 +163,7 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st return Sendmsg(fd, "fail"); } - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - LOG(ERROR) << "Could not find handler: " << out[1]; - return Sendmsg(fd, "fail"); - } - if (!(*iter)->snapuserd() || (*iter)->snapuserd()->IsAttached()) { - LOG(ERROR) << "Tried to re-attach control device: " << out[1]; - return Sendmsg(fd, "fail"); - } - if (!StartHandler(*iter)) { + if (!handlers_->StartHandler(out[1])) { return Sendmsg(fd, "fail"); } return Sendmsg(fd, "success"); @@ -209,30 +196,13 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; return Sendmsg(fd, "fail"); } - { - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - // After merge is completed, we swap dm-user table with - // the underlying dm-linear base device. Hence, worker - // threads would have terminted and was removed from - // the list. - LOG(DEBUG) << "Could not find handler: " << out[1]; - return Sendmsg(fd, "success"); - } - - if (!(*iter)->ThreadTerminated()) { - (*iter)->snapuserd()->NotifyIOTerminated(); - } - } - if (!RemoveAndJoinHandler(out[1])) { + if (!handlers_->DeleteHandler(out[1])) { return Sendmsg(fd, "fail"); } return Sendmsg(fd, "success"); } case DaemonOps::DETACH: { - std::lock_guard lock(lock_); - TerminateMergeThreads(&lock); + handlers_->TerminateMergeThreads(); terminating_ = true; return true; } @@ -252,24 +222,15 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st return Sendmsg(fd, "fail"); } if (out[0] == "initiate_merge") { - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - LOG(ERROR) << "Could not find handler: " << out[1]; + if (!handlers_->InitiateMerge(out[1])) { return Sendmsg(fd, "fail"); } - - if (!StartMerge(&lock, *iter)) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); } return Sendmsg(fd, "fail"); } case DaemonOps::PERCENTAGE: { - std::lock_guard lock(lock_); - double percentage = GetMergePercentage(&lock); + double percentage = handlers_->GetMergePercentage(); return Sendmsg(fd, std::to_string(percentage)); } @@ -280,24 +241,16 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; return Sendmsg(fd, "snapshot-merge-failed"); } - { - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - LOG(ERROR) << "Could not find handler: " << out[1]; - return Sendmsg(fd, "snapshot-merge-failed"); - } - - std::string merge_status = GetMergeStatus(*iter); - return Sendmsg(fd, merge_status); + auto status = handlers_->GetMergeStatus(out[1]); + if (status.empty()) { + return Sendmsg(fd, "snapshot-merge-failed"); } + return Sendmsg(fd, status); } case DaemonOps::UPDATE_VERIFY: { - std::lock_guard lock(lock_); - if (!UpdateVerification(&lock)) { + if (!handlers_->GetVerificationStatus()) { return Sendmsg(fd, "fail"); } - return Sendmsg(fd, "success"); } default: { @@ -308,56 +261,6 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st } } -void UserSnapshotServer::RunThread(std::shared_ptr handler) { - LOG(INFO) << "Entering thread for handler: " << handler->misc_name(); - - if (!handler->snapuserd()->Start()) { - LOG(ERROR) << " Failed to launch all worker threads"; - } - - handler->snapuserd()->CloseFds(); - bool merge_completed = handler->snapuserd()->CheckMergeCompletionStatus(); - handler->snapuserd()->UnmapBufferRegion(); - - auto misc_name = handler->misc_name(); - LOG(INFO) << "Handler thread about to exit: " << misc_name; - - { - std::lock_guard lock(lock_); - if (merge_completed) { - num_partitions_merge_complete_ += 1; - active_merge_threads_ -= 1; - WakeupMonitorMergeThread(); - } - handler->SetThreadTerminated(); - auto iter = FindHandler(&lock, handler->misc_name()); - if (iter == dm_users_.end()) { - // RemoveAndJoinHandler() already removed us from the list, and is - // now waiting on a join(), so just return. Additionally, release - // all the resources held by snapuserd object which are shared - // by worker threads. This should be done when the last reference - // of "handler" is released; but we will explicitly release here - // to make sure snapuserd object is freed as it is the biggest - // consumer of memory in the daemon. - handler->FreeResources(); - LOG(INFO) << "Exiting handler thread to allow for join: " << misc_name; - return; - } - - LOG(INFO) << "Exiting handler thread and freeing resources: " << misc_name; - - if (handler->snapuserd()->IsAttached()) { - handler->thread().detach(); - } - - // Important: free resources within the lock. This ensures that if - // WaitForDelete() is called, the handler is either in the list, or - // it's not and its resources are guaranteed to be freed. - handler->FreeResources(); - dm_users_.erase(iter); - } -} - bool UserSnapshotServer::Start(const std::string& socketname) { bool start_listening = true; @@ -423,28 +326,10 @@ bool UserSnapshotServer::Run() { } } - JoinAllThreads(); + handlers_->JoinAllThreads(); return true; } -void UserSnapshotServer::JoinAllThreads() { - // Acquire the thread list within the lock. - std::vector> dm_users; - { - std::lock_guard guard(lock_); - dm_users = std::move(dm_users_); - } - - for (auto& client : dm_users) { - auto& th = client->thread(); - - if (th.joinable()) th.join(); - } - - stop_monitor_merge_thread_ = true; - WakeupMonitorMergeThread(); -} - void UserSnapshotServer::AddWatchedFd(android::base::borrowed_fd fd, int events) { struct pollfd p = {}; p.fd = fd.get(); @@ -506,185 +391,13 @@ std::shared_ptr UserSnapshotServer::AddHandler(const std::string& perform_verification = false; } - auto snapuserd = std::make_shared(misc_name, cow_device_path, backing_device, - base_path_merge, num_worker_threads, - io_uring_enabled_, perform_verification); - if (!snapuserd->InitCowDevice()) { - LOG(ERROR) << "Failed to initialize Snapuserd"; - return nullptr; - } - - if (!snapuserd->InitializeWorkers()) { - LOG(ERROR) << "Failed to initialize workers"; - return nullptr; - } - - auto handler = std::make_shared(snapuserd); - { - std::lock_guard lock(lock_); - if (FindHandler(&lock, misc_name) != dm_users_.end()) { - LOG(ERROR) << "Handler already exists: " << misc_name; - return nullptr; - } - dm_users_.push_back(handler); - } - return handler; -} - -bool UserSnapshotServer::StartHandler(const std::shared_ptr& handler) { - if (handler->snapuserd()->IsAttached()) { - LOG(ERROR) << "Handler already attached"; - return false; - } - - handler->snapuserd()->AttachControlDevice(); - - handler->thread() = std::thread(std::bind(&UserSnapshotServer::RunThread, this, handler)); - return true; -} - -bool UserSnapshotServer::StartMerge(std::lock_guard* proof_of_lock, - const std::shared_ptr& handler) { - CHECK(proof_of_lock); - - if (!handler->snapuserd()->IsAttached()) { - LOG(ERROR) << "Handler not attached to dm-user - Merge thread cannot be started"; - return false; - } - - handler->snapuserd()->MonitorMerge(); - - if (!is_merge_monitor_started_.has_value()) { - std::thread(&UserSnapshotServer::MonitorMerge, this).detach(); - is_merge_monitor_started_ = true; - } - - merge_handlers_.push(handler); - WakeupMonitorMergeThread(); - return true; -} - -auto UserSnapshotServer::FindHandler(std::lock_guard* proof_of_lock, - const std::string& misc_name) -> HandlerList::iterator { - CHECK(proof_of_lock); - - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - if ((*iter)->misc_name() == misc_name) { - return iter; - } - } - return dm_users_.end(); -} - -void UserSnapshotServer::TerminateMergeThreads(std::lock_guard* proof_of_lock) { - CHECK(proof_of_lock); - - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - if (!(*iter)->ThreadTerminated()) { - (*iter)->snapuserd()->NotifyIOTerminated(); - } - } -} - -std::string UserSnapshotServer::GetMergeStatus(const std::shared_ptr& handler) { - return handler->snapuserd()->GetMergeStatus(); -} - -double UserSnapshotServer::GetMergePercentage(std::lock_guard* proof_of_lock) { - CHECK(proof_of_lock); - double percentage = 0.0; - int n = 0; - - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - auto& th = (*iter)->thread(); - if (th.joinable()) { - // Merge percentage by individual partitions wherein merge is still - // in-progress - percentage += (*iter)->snapuserd()->GetMergePercentage(); - n += 1; - } - } - - // Calculate final merge including those partitions where merge was already - // completed - num_partitions_merge_complete_ will track them when each - // thread exists in RunThread. - int total_partitions = n + num_partitions_merge_complete_; - - if (total_partitions) { - percentage = ((num_partitions_merge_complete_ * 100.0) + percentage) / total_partitions; - } - - LOG(DEBUG) << "Merge %: " << percentage - << " num_partitions_merge_complete_: " << num_partitions_merge_complete_ - << " total_partitions: " << total_partitions << " n: " << n; - return percentage; -} - -bool UserSnapshotServer::RemoveAndJoinHandler(const std::string& misc_name) { - std::shared_ptr handler; - { - std::lock_guard lock(lock_); - - auto iter = FindHandler(&lock, misc_name); - if (iter == dm_users_.end()) { - // Client already deleted. - return true; - } - handler = std::move(*iter); - dm_users_.erase(iter); - } - - auto& th = handler->thread(); - if (th.joinable()) { - th.join(); - } - return true; -} - -void UserSnapshotServer::WakeupMonitorMergeThread() { - uint64_t notify = 1; - ssize_t rc = TEMP_FAILURE_RETRY(write(monitor_merge_event_fd_.get(), ¬ify, sizeof(notify))); - if (rc < 0) { - PLOG(FATAL) << "failed to notify monitor merge thread"; - } -} - -void UserSnapshotServer::MonitorMerge() { - while (!stop_monitor_merge_thread_) { - uint64_t testVal; - ssize_t ret = - TEMP_FAILURE_RETRY(read(monitor_merge_event_fd_.get(), &testVal, sizeof(testVal))); - if (ret == -1) { - PLOG(FATAL) << "Failed to read from eventfd"; - } else if (ret == 0) { - LOG(FATAL) << "Hit EOF on eventfd"; - } - - LOG(INFO) << "MonitorMerge: active-merge-threads: " << active_merge_threads_; - { - std::lock_guard lock(lock_); - while (active_merge_threads_ < kMaxMergeThreads && merge_handlers_.size() > 0) { - auto handler = merge_handlers_.front(); - merge_handlers_.pop(); - - if (!handler->snapuserd()) { - LOG(INFO) << "MonitorMerge: skipping deleted handler: " << handler->misc_name(); - continue; - } - - LOG(INFO) << "Starting merge for partition: " - << handler->snapuserd()->GetMiscName(); - handler->snapuserd()->InitiateMerge(); - active_merge_threads_ += 1; - } - } - } - - LOG(INFO) << "Exiting MonitorMerge: size: " << merge_handlers_.size(); + return handlers_->AddHandler(misc_name, cow_device_path, backing_device, base_path_merge, + num_worker_threads, io_uring_enabled_, perform_verification); } bool UserSnapshotServer::WaitForSocket() { - auto scope_guard = android::base::make_scope_guard([this]() -> void { JoinAllThreads(); }); + auto scope_guard = + android::base::make_scope_guard([this]() -> void { handlers_->JoinAllThreads(); }); auto socket_path = ANDROID_SOCKET_DIR "/"s + kSnapuserdSocketProxy; @@ -781,21 +494,8 @@ bool UserSnapshotServer::RunForSocketHandoff() { return true; } -bool UserSnapshotServer::UpdateVerification(std::lock_guard* proof_of_lock) { - CHECK(proof_of_lock); - - bool status = true; - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - auto& th = (*iter)->thread(); - if (th.joinable() && status) { - status = (*iter)->snapuserd()->CheckPartitionVerification() && status; - } else { - // return immediately if there is a failure - return false; - } - } - - return status; +bool UserSnapshotServer::StartHandler(const std::string& misc_name) { + return handlers_->StartHandler(misc_name); } } // namespace snapshot diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h index 12c3903c495c..ae5190391dfa 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h @@ -31,6 +31,7 @@ #include #include +#include "handler_manager.h" #include "snapuserd_core.h" namespace android { @@ -54,33 +55,6 @@ enum class DaemonOps { INVALID, }; -class HandlerThread { - public: - explicit HandlerThread(std::shared_ptr snapuserd); - - void FreeResources() { - // Each worker thread holds a reference to snapuserd. - // Clear them so that all the resources - // held by snapuserd is released - if (snapuserd_) { - snapuserd_->FreeResources(); - snapuserd_ = nullptr; - } - } - const std::shared_ptr& snapuserd() const { return snapuserd_; } - std::thread& thread() { return thread_; } - - const std::string& misc_name() const { return misc_name_; } - bool ThreadTerminated() { return thread_terminated_; } - void SetThreadTerminated() { thread_terminated_ = true; } - - private: - std::thread thread_; - std::shared_ptr snapuserd_; - std::string misc_name_; - bool thread_terminated_ = false; -}; - class UserSnapshotServer { private: android::base::unique_fd sockfd_; @@ -88,21 +62,12 @@ class UserSnapshotServer { volatile bool received_socket_signal_ = false; std::vector watched_fds_; bool is_socket_present_ = false; - int num_partitions_merge_complete_ = 0; - int active_merge_threads_ = 0; - bool stop_monitor_merge_thread_ = false; bool is_server_running_ = false; bool io_uring_enabled_ = false; - std::optional is_merge_monitor_started_; - - android::base::unique_fd monitor_merge_event_fd_; + std::unique_ptr handlers_; std::mutex lock_; - using HandlerList = std::vector>; - HandlerList dm_users_; - std::queue> merge_handlers_; - void AddWatchedFd(android::base::borrowed_fd fd, int events); void AcceptClient(); bool HandleClient(android::base::borrowed_fd fd, int revents); @@ -111,28 +76,15 @@ class UserSnapshotServer { bool Receivemsg(android::base::borrowed_fd fd, const std::string& str); void ShutdownThreads(); - bool RemoveAndJoinHandler(const std::string& control_device); DaemonOps Resolveop(std::string& input); std::string GetDaemonStatus(); void Parsemsg(std::string const& msg, const char delim, std::vector& out); bool IsTerminating() { return terminating_; } - void RunThread(std::shared_ptr handler); - void MonitorMerge(); - void JoinAllThreads(); bool StartWithSocket(bool start_listening); - // Find a HandlerThread within a lock. - HandlerList::iterator FindHandler(std::lock_guard* proof_of_lock, - const std::string& misc_name); - - double GetMergePercentage(std::lock_guard* proof_of_lock); - void TerminateMergeThreads(std::lock_guard* proof_of_lock); - - bool UpdateVerification(std::lock_guard* proof_of_lock); - public: UserSnapshotServer(); ~UserSnapshotServer(); @@ -147,12 +99,8 @@ class UserSnapshotServer { const std::string& cow_device_path, const std::string& backing_device, const std::string& base_path_merge); - bool StartHandler(const std::shared_ptr& handler); - bool StartMerge(std::lock_guard* proof_of_lock, - const std::shared_ptr& handler); - std::string GetMergeStatus(const std::shared_ptr& handler); + bool StartHandler(const std::string& misc_name); - void WakeupMonitorMergeThread(); void SetTerminating() { terminating_ = true; } void ReceivedSocketSignal() { received_socket_signal_ = true; } void SetServerRunning() { is_server_running_ = true; } From f84f9c319e5a05fa6bfed9730ea6b9d28407a84b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 14 Mar 2023 09:09:48 -0700 Subject: [PATCH 0169/1487] snapuserd: Remove DaemonOps. These are only used for a single switch statement. Just compare the input strings instead. Bug: 269361087 Test: builds, ota applies Ignore-AOSP-First: cherry-pick from aosp Change-Id: Ib90ae55309ea99c181585c64ed2ac814e5ed6c72 Merged-In: Ib90ae55309ea99c181585c64ed2ac814e5ed6c72 --- .../user-space-merge/snapuserd_server.cpp | 218 ++++++++---------- .../user-space-merge/snapuserd_server.h | 16 -- 2 files changed, 94 insertions(+), 140 deletions(-) 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 cc8115f5f800..d87990aca2a8 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp @@ -45,22 +45,6 @@ using namespace std::string_literals; using android::base::borrowed_fd; using android::base::unique_fd; -DaemonOps UserSnapshotServer::Resolveop(std::string& input) { - if (input == "init") return DaemonOps::INIT; - if (input == "start") return DaemonOps::START; - if (input == "stop") return DaemonOps::STOP; - if (input == "query") return DaemonOps::QUERY; - if (input == "delete") return DaemonOps::DELETE; - if (input == "detach") return DaemonOps::DETACH; - if (input == "supports") return DaemonOps::SUPPORTS; - if (input == "initiate_merge") return DaemonOps::INITIATE; - if (input == "merge_percent") return DaemonOps::PERCENTAGE; - if (input == "getstatus") return DaemonOps::GETSTATUS; - if (input == "update-verify") return DaemonOps::UPDATE_VERIFY; - - return DaemonOps::INVALID; -} - UserSnapshotServer::UserSnapshotServer() { terminating_ = false; handlers_ = std::make_unique(); @@ -132,132 +116,118 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st std::vector out; Parsemsg(str, delim, out); - DaemonOps op = Resolveop(out[0]); - - switch (op) { - case DaemonOps::INIT: { - // Message format: - // init,,,, - // - // Reads the metadata and send the number of sectors - if (out.size() != 5) { - LOG(ERROR) << "Malformed init message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - auto handler = AddHandler(out[1], out[2], out[3], out[4]); - if (!handler) { - return Sendmsg(fd, "fail"); - } - - auto retval = "success," + std::to_string(handler->snapuserd()->GetNumSectors()); - return Sendmsg(fd, retval); + const auto& cmd = out[0]; + if (cmd == "init") { + // Message format: + // init,,,, + // + // Reads the metadata and send the number of sectors + if (out.size() != 5) { + LOG(ERROR) << "Malformed init message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::START: { - // Message format: - // start, - // - // Start the new thread which binds to dm-user misc device - if (out.size() != 2) { - LOG(ERROR) << "Malformed start message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (!handlers_->StartHandler(out[1])) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); - } - case DaemonOps::STOP: { - // Message format: stop - // - // Stop all the threads gracefully and then shutdown the - // main thread - SetTerminating(); - ShutdownThreads(); - return true; + auto handler = AddHandler(out[1], out[2], out[3], out[4]); + if (!handler) { + return Sendmsg(fd, "fail"); } - case DaemonOps::QUERY: { - // Message format: query - // - // As part of transition, Second stage daemon will be - // created before terminating the first stage daemon. Hence, - // for a brief period client may have to distiguish between - // first stage daemon and second stage daemon. - // - // Second stage daemon is marked as active and hence will - // be ready to receive control message. - return Sendmsg(fd, GetDaemonStatus()); + + auto retval = "success," + std::to_string(handler->snapuserd()->GetNumSectors()); + return Sendmsg(fd, retval); + } else if (cmd == "start") { + // Message format: + // start, + // + // Start the new thread which binds to dm-user misc device + if (out.size() != 2) { + LOG(ERROR) << "Malformed start message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::DELETE: { - // Message format: - // delete, - if (out.size() != 2) { - LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (!handlers_->DeleteHandler(out[1])) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); + + if (!handlers_->StartHandler(out[1])) { + return Sendmsg(fd, "fail"); } - case DaemonOps::DETACH: { - handlers_->TerminateMergeThreads(); - terminating_ = true; - return true; + return Sendmsg(fd, "success"); + } else if (cmd == "stop") { + // Message format: stop + // + // Stop all the threads gracefully and then shutdown the + // main thread + SetTerminating(); + ShutdownThreads(); + return true; + } else if (cmd == "query") { + // Message format: query + // + // As part of transition, Second stage daemon will be + // created before terminating the first stage daemon. Hence, + // for a brief period client may have to distiguish between + // first stage daemon and second stage daemon. + // + // Second stage daemon is marked as active and hence will + // be ready to receive control message. + return Sendmsg(fd, GetDaemonStatus()); + } else if (cmd == "delete") { + // Message format: + // delete, + if (out.size() != 2) { + LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::SUPPORTS: { - if (out.size() != 2) { - LOG(ERROR) << "Malformed supports message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (out[1] == "second_stage_socket_handoff") { - return Sendmsg(fd, "success"); - } + if (!handlers_->DeleteHandler(out[1])) { return Sendmsg(fd, "fail"); } - case DaemonOps::INITIATE: { - if (out.size() != 2) { - LOG(ERROR) << "Malformed initiate-merge message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (out[0] == "initiate_merge") { - if (!handlers_->InitiateMerge(out[1])) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); - } + return Sendmsg(fd, "success"); + } else if (cmd == "detach") { + handlers_->TerminateMergeThreads(); + terminating_ = true; + return true; + } else if (cmd == "supports") { + if (out.size() != 2) { + LOG(ERROR) << "Malformed supports message, " << out.size() << " parts"; return Sendmsg(fd, "fail"); } - case DaemonOps::PERCENTAGE: { - double percentage = handlers_->GetMergePercentage(); - - return Sendmsg(fd, std::to_string(percentage)); + if (out[1] == "second_stage_socket_handoff") { + return Sendmsg(fd, "success"); } - case DaemonOps::GETSTATUS: { - // Message format: - // getstatus, - if (out.size() != 2) { - LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; - return Sendmsg(fd, "snapshot-merge-failed"); - } - auto status = handlers_->GetMergeStatus(out[1]); - if (status.empty()) { - return Sendmsg(fd, "snapshot-merge-failed"); - } - return Sendmsg(fd, status); + return Sendmsg(fd, "fail"); + } else if (cmd == "initiate_merge") { + if (out.size() != 2) { + LOG(ERROR) << "Malformed initiate-merge message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::UPDATE_VERIFY: { - if (!handlers_->GetVerificationStatus()) { + if (out[0] == "initiate_merge") { + if (!handlers_->InitiateMerge(out[1])) { return Sendmsg(fd, "fail"); } return Sendmsg(fd, "success"); } - default: { - LOG(ERROR) << "Received unknown message type from client"; - Sendmsg(fd, "fail"); - return false; + return Sendmsg(fd, "fail"); + } else if (cmd == "merge_percent") { + double percentage = handlers_->GetMergePercentage(); + return Sendmsg(fd, std::to_string(percentage)); + } else if (cmd == "getstatus") { + // Message format: + // getstatus, + if (out.size() != 2) { + LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; + return Sendmsg(fd, "snapshot-merge-failed"); + } + auto status = handlers_->GetMergeStatus(out[1]); + if (status.empty()) { + return Sendmsg(fd, "snapshot-merge-failed"); } + return Sendmsg(fd, status); + } else if (cmd == "update-verify") { + if (!handlers_->GetVerificationStatus()) { + return Sendmsg(fd, "fail"); + } + return Sendmsg(fd, "success"); + } else { + LOG(ERROR) << "Received unknown message type from client"; + Sendmsg(fd, "fail"); + return false; } } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h index ae5190391dfa..988c01a99ba3 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h @@ -40,21 +40,6 @@ namespace snapshot { static constexpr uint32_t kMaxPacketSize = 512; static constexpr uint8_t kMaxMergeThreads = 2; -enum class DaemonOps { - INIT, - START, - QUERY, - STOP, - DELETE, - DETACH, - SUPPORTS, - INITIATE, - PERCENTAGE, - GETSTATUS, - UPDATE_VERIFY, - INVALID, -}; - class UserSnapshotServer { private: android::base::unique_fd sockfd_; @@ -76,7 +61,6 @@ class UserSnapshotServer { bool Receivemsg(android::base::borrowed_fd fd, const std::string& str); void ShutdownThreads(); - DaemonOps Resolveop(std::string& input); std::string GetDaemonStatus(); void Parsemsg(std::string const& msg, const char delim, std::vector& out); From 269e99f9558ae332e10329451fc51dc6698375a0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 14 Mar 2023 10:57:47 -0700 Subject: [PATCH 0170/1487] snapuserd: Run snapuserd threads in-process. This removes the temporary daemon and socket and instead directly embeds SnapshotHandlerManager. We can also remove the test flags for io_uring as with this they're no longer necessary. Bug: 269361087 Test: snapuserd_test Ignore-AOSP-First: cherry-pick from aosp Change-Id: I728186d9bc90c98fabd76d3f86569840488ada96 Merged-In: I728186d9bc90c98fabd76d3f86569840488ada96 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 15 ++-- .../user-space-merge/handler_manager.cpp | 3 + .../user-space-merge/snapuserd_core.cpp | 5 -- .../user-space-merge/snapuserd_server.cpp | 3 - .../user-space-merge/snapuserd_test.cpp | 75 ++++++------------- 5 files changed, 33 insertions(+), 68 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 65f3d6d297ed..9fe567acbc7e 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -165,7 +165,7 @@ cc_binary { } cc_test { - name: "cow_snapuserd_test", + name: "snapuserd_test_legacy", defaults: [ "fs_mgr_defaults", "libsnapshot_cow_defaults", @@ -217,16 +217,17 @@ cc_test { ], static_libs: [ "libbrotli", - "libgtest", - "libsnapshot_cow", - "libsnapshot_snapuserd", "libcutils_sockets", - "libz", - "libfs_mgr", "libdm", "libext4_utils", - "liburing", + "libfs_mgr", "libgflags", + "libgtest", + "libsnapshot_cow", + "libsnapshot_snapuserd", + "libsnapuserd", + "liburing", + "libz", ], include_dirs: ["bionic/libc/kernel"], header_libs: [ 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 c5150c411d02..bdba5c0cc3ab 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 @@ namespace snapshot { static constexpr uint8_t kMaxMergeThreads = 2; +HandlerThread::HandlerThread(std::shared_ptr 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 c8a5cc584a28..8e1212b7b3ce 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -421,11 +421,6 @@ bool SnapshotHandler::IsIouringSupported() { 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 d87990aca2a8..c953f1a053bd 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 @@ void UserSnapshotServer::ShutdownThreads() { handlers_->JoinAllThreads(); } -HandlerThread::HandlerThread(std::shared_ptr 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 ef3689f61f6b..efe0c1443215 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 #include #include -#include #include +#include "handler_manager.h" #include "snapuserd_core.h" DEFINE_string(force_config, "", "Force testing mode with iouring disabled"); @@ -54,8 +54,6 @@ using namespace std::chrono_literals; 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 @@ class Tempdevice { } ~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_; } @@ -139,7 +137,6 @@ class SnapuserdTest : public ::testing::Test { void SetDeviceControlName(); void InitDaemon(); void CreateDmUserDevice(); - void StartSnapuserdDaemon(); unique_ptr base_loop_; unique_ptr dmuser_dev_; @@ -149,9 +146,9 @@ class SnapuserdTest : public ::testing::Test { unique_fd base_fd_; std::unique_ptr cow_system_; - std::unique_ptr client_; std::unique_ptr orig_buffer_; std::unique_ptr merged_buffer_; + SnapshotHandlerManager handlers_; bool setup_ok_ = false; bool merge_ok_ = false; size_t size_ = 100_MiB; @@ -181,9 +178,9 @@ void SnapuserdTest::Shutdown() { 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() { @@ -218,8 +215,6 @@ bool SnapuserdTest::SetupCopyOverlap_2() { bool SnapuserdTest::SetupDaemon() { SetDeviceControlName(); - StartSnapuserdDaemon(); - CreateDmUserDevice(); InitCowDevice(); InitDaemon(); @@ -229,20 +224,6 @@ bool SnapuserdTest::SetupDaemon() { 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; @@ -591,9 +572,17 @@ void SnapuserdTest::CreateCowDevice() { } 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() { @@ -631,13 +620,12 @@ void SnapuserdTest::CreateDmUserDevice() { } 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; } @@ -652,8 +640,6 @@ void SnapuserdTest::SetupImpl() { SetDeviceControlName(); - StartSnapuserdDaemon(); - CreateDmUserDevice(); InitCowDevice(); InitDaemon(); @@ -669,8 +655,7 @@ bool SnapuserdTest::Merge() { } 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() { @@ -684,7 +669,6 @@ void SnapuserdTest::SimulateDaemonRestart() { Shutdown(); std::this_thread::sleep_for(500ms); SetDeviceControlName(); - StartSnapuserdDaemon(); CreateDmUserDevice(); InitCowDevice(); InitDaemon(); @@ -844,20 +828,5 @@ int main(int argc, char** argv) { 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(); } From 15632504107b40e0c15c1c9efb0f1d19e991a02a Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 10 Jul 2023 22:03:11 +0000 Subject: [PATCH 0171/1487] NetlinkEvent: trivial simplification. free(NULL) is defined as a no-op. Don't overcomplicate things. Bug: http://b/287138549 Test: treehugger Change-Id: I9ae532a71f986d9468f191972a9b7acf6e709d13 --- libsysutils/src/NetlinkEvent.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp index cd9db54fa6f4..55bbe46e1a85 100644 --- a/libsysutils/src/NetlinkEvent.cpp +++ b/libsysutils/src/NetlinkEvent.cpp @@ -150,15 +150,10 @@ NetlinkEvent::NetlinkEvent() { } NetlinkEvent::~NetlinkEvent() { - int i; - if (mPath) - free(mPath); - if (mSubsystem) - free(mSubsystem); - for (i = 0; i < NL_PARAMS_MAX; i++) { - if (!mParams[i]) - break; - free(mParams[i]); + free(mPath); + free(mSubsystem); + for (auto param : mParams) { + free(param); } } From fac2b18fffee638018b6175c98e99f78dac8f183 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 10 Jul 2023 23:13:44 +0000 Subject: [PATCH 0172/1487] init.rc: merge the zygote-start actions The three actions for "zygote-start" are identical except for their property triggers. This seems to have been left over from when Android supported both File Based Encryption (FBE) and Full Disk Encryption (FDE), causing there to be four possible encryption states: - ro.crypto.state=unsupported (No encryption configured) - ro.crypto.state=encrypted && ro.crypto.type=file (FBE enabled) - ro.crypto.state=unencrypted (FDE supported but disabled) - ro.crypto.state=encrypted && ro.crypto.type=block (FDE enabled) It seems that the reason the zygote-start action was duplicated three times was to exclude the "FDE enabled" case, which could only be done by explicitly listing the other three cases. However, now that FDE is no longer supported, only the first two cases are possible. Therefore, zygote-start can just be the whole trigger. Bug: 208476087 Test: presubmit Change-Id: Icd6e4b0d2fb3f9f20595c0af4e2e35350564da8d --- rootdir/init.rc | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index a8b78d5d8025..4f3959f7cdca 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -533,7 +533,7 @@ on late-init # Should be before netd, but after apex, properties and logging is available. trigger load_bpf_programs - # Now we can start zygote for devices with file based encryption + # Now we can start zygote. trigger zygote-start # Remove a file to wake up anything waiting for firmware. @@ -1056,25 +1056,7 @@ on post-fs-data # It is recommended to put unnecessary data/ initialization from post-fs-data # to start-zygote in device's init.rc to unblock zygote start. -on zygote-start && property:ro.crypto.state=unencrypted - wait_for_prop odsign.verification.done 1 - # A/B update verifier that marks a successful boot. - exec_start update_verifier_nonencrypted - start statsd - start netd - start zygote - start zygote_secondary - -on zygote-start && property:ro.crypto.state=unsupported - wait_for_prop odsign.verification.done 1 - # A/B update verifier that marks a successful boot. - exec_start update_verifier_nonencrypted - start statsd - start netd - start zygote - start zygote_secondary - -on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file +on zygote-start wait_for_prop odsign.verification.done 1 # A/B update verifier that marks a successful boot. exec_start update_verifier_nonencrypted From 6e8e8ac71fbc3bf09289bbf2aaee0bc12634578e Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 10 Jul 2023 23:48:38 +0000 Subject: [PATCH 0173/1487] init.rc: start update_verifier instead of update_verifier_nonencrypted The "update_verifier_nonencrypted" service is being replaced with simply "update_verifier", so update init.rc accordingly. Bug: 208476087 Test: presubmit Change-Id: I58f3fb25167ff7d3679c72e5e9c012f02fa5b516 --- rootdir/init.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 4f3959f7cdca..cdf67b9c06d6 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -1059,7 +1059,7 @@ on post-fs-data on zygote-start wait_for_prop odsign.verification.done 1 # A/B update verifier that marks a successful boot. - exec_start update_verifier_nonencrypted + exec_start update_verifier start statsd start netd start zygote From a0d2401d23b231d4b48e9ec6ee0e58fded421e13 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Mon, 10 Jul 2023 16:45:54 -0700 Subject: [PATCH 0174/1487] Mocking get_uint_var() Changing implementation to have mock fastboot driver return a the sparse_limit rather than modifying the variable inside of flashing plan Test: fastboot_test Change-Id: I850ccd5bd09b6a8479ccc8cf7bf1d227abb87e3a --- fastboot/fastboot.cpp | 23 +++++++++++++---------- fastboot/fastboot_driver.h | 2 +- fastboot/fastboot_driver_interface.h | 4 ++++ fastboot/fastboot_driver_mock.h | 7 ++++--- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 6fc6f5ff742d..eee0e93d031e 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -76,6 +76,7 @@ #include "constants.h" #include "diagnose_usb.h" #include "fastboot_driver.h" +#include "fastboot_driver_interface.h" #include "fs.h" #include "storage.h" #include "super_flash_helper.h" @@ -996,7 +997,7 @@ static std::vector load_sparse_files(int fd, int64_t max_size) { return resparse_file(s.get(), max_size); } -static uint64_t get_uint_var(const char* var_name) { +static uint64_t get_uint_var(const char* var_name, fastboot::IFastBootDriver* fb) { std::string value_str; if (fb->GetVar(var_name, &value_str) != fastboot::SUCCESS || value_str.empty()) { verbose("target didn't report %s", var_name); @@ -1021,7 +1022,7 @@ int64_t get_sparse_limit(int64_t size, const FlashingPlan* fp) { // Unlimited, so see what the target device's limit is. // TODO: shouldn't we apply this limit even if you've used -S? if (target_sparse_limit == -1) { - target_sparse_limit = static_cast(get_uint_var("max-download-size")); + target_sparse_limit = static_cast(get_uint_var("max-download-size", fp->fb)); } if (target_sparse_limit > 0) { limit = target_sparse_limit; @@ -1420,8 +1421,9 @@ bool is_retrofit_device() { // Fetch a partition from the device to a given fd. This is a wrapper over FetchToFd to fetch // the full image. -static uint64_t fetch_partition(const std::string& partition, borrowed_fd fd) { - uint64_t fetch_size = get_uint_var(FB_VAR_MAX_FETCH_SIZE); +static uint64_t fetch_partition(const std::string& partition, borrowed_fd fd, + fastboot::IFastBootDriver* fb) { + uint64_t fetch_size = get_uint_var(FB_VAR_MAX_FETCH_SIZE, fb); if (fetch_size == 0) { die("Unable to get %s. Device does not support fetch command.", FB_VAR_MAX_FETCH_SIZE); } @@ -1443,17 +1445,18 @@ static uint64_t fetch_partition(const std::string& partition, borrowed_fd fd) { } static void do_fetch(const std::string& partition, const std::string& slot_override, - const std::string& outfile) { + const std::string& outfile, fastboot::IFastBootDriver* fb) { unique_fd fd(TEMP_FAILURE_RETRY( open(outfile.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY, 0644))); - auto fetch = std::bind(fetch_partition, _1, borrowed_fd(fd)); + auto fetch = std::bind(fetch_partition, _1, borrowed_fd(fd), fb); do_for_partitions(partition, slot_override, fetch, false /* force slot */); } // Return immediately if not flashing a vendor boot image. If flashing a vendor boot image, // repack vendor_boot image with an updated ramdisk. After execution, buf is set // to the new image to flash, and return value is the real partition name to flash. -static std::string repack_ramdisk(const char* pname, struct fastboot_buffer* buf) { +static std::string repack_ramdisk(const char* pname, struct fastboot_buffer* buf, + fastboot::IFastBootDriver* fb) { std::string_view pname_sv{pname}; if (!android::base::StartsWith(pname_sv, "vendor_boot:") && @@ -1471,7 +1474,7 @@ static std::string repack_ramdisk(const char* pname, struct fastboot_buffer* buf std::string ramdisk(pname_sv.substr(pname_sv.find(':') + 1)); unique_fd vendor_boot(make_temporary_fd("vendor boot repack")); - uint64_t vendor_boot_size = fetch_partition(partition, vendor_boot); + uint64_t vendor_boot_size = fetch_partition(partition, vendor_boot, fb); auto repack_res = replace_vendor_ramdisk(vendor_boot, vendor_boot_size, ramdisk, buf->fd, static_cast(buf->sz)); if (!repack_res.ok()) { @@ -1508,7 +1511,7 @@ void do_flash(const char* pname, const char* fname, const bool apply_vbmeta, if (is_logical(pname)) { fb->ResizePartition(pname, std::to_string(buf.image_size)); } - std::string flash_pname = repack_ramdisk(pname, &buf); + std::string flash_pname = repack_ramdisk(pname, &buf, fp->fb); flash_buf(flash_pname, &buf, apply_vbmeta); } @@ -2576,7 +2579,7 @@ int FastBootTool::Main(int argc, char* argv[]) { } else if (command == FB_CMD_FETCH) { std::string partition = next_arg(&args); std::string outfile = next_arg(&args); - do_fetch(partition, fp->slot_override, outfile); + do_fetch(partition, fp->slot_override, outfile, fp->fb); } else { syntax_error("unknown command %s", command.c_str()); } diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h index 6ac26ce31f13..8774eadc6a6f 100644 --- a/fastboot/fastboot_driver.h +++ b/fastboot/fastboot_driver.h @@ -105,7 +105,7 @@ class FastBootDriver : public IFastBootDriver { std::vector* info = nullptr); RetCode FetchToFd(const std::string& partition, android::base::borrowed_fd fd, int64_t offset = -1, int64_t size = -1, std::string* response = nullptr, - std::vector* info = nullptr); + std::vector* info = nullptr) override; /* HIGHER LEVEL COMMANDS -- Composed of the commands above */ RetCode FlashPartition(const std::string& partition, const std::vector& data); diff --git a/fastboot/fastboot_driver_interface.h b/fastboot/fastboot_driver_interface.h index 795938fb41f7..7cb8a6b6acdf 100644 --- a/fastboot/fastboot_driver_interface.h +++ b/fastboot/fastboot_driver_interface.h @@ -45,6 +45,10 @@ class IFastBootDriver { std::vector* info = nullptr) = 0; RetCode virtual GetVar(const std::string& key, std::string* val, std::vector* info = nullptr) = 0; + RetCode virtual FetchToFd(const std::string& partition, android::base::borrowed_fd fd, + int64_t offset = -1, int64_t size = -1, + std::string* response = nullptr, + std::vector* info = nullptr) = 0; RetCode virtual Download(const std::string& name, android::base::borrowed_fd fd, size_t size, std::string* response = nullptr, std::vector* info = nullptr) = 0; diff --git a/fastboot/fastboot_driver_mock.h b/fastboot/fastboot_driver_mock.h index d2a123b199c5..7c41d78a1839 100644 --- a/fastboot/fastboot_driver_mock.h +++ b/fastboot/fastboot_driver_mock.h @@ -28,15 +28,16 @@ class MockFastbootDriver : public IFastBootDriver { MOCK_METHOD(RetCode, Reboot, (std::string*, std::vector*), (override)); MOCK_METHOD(RetCode, RebootTo, (std::string, std::string*, std::vector*), (override)); - MOCK_METHOD(RetCode, GetVar, (const std::string&, std::string*, std::vector*), (override)); - + MOCK_METHOD(RetCode, FetchToFd, + (const std::string&, android::base::borrowed_fd, int64_t offset, int64_t size, + std::string*, std::vector*), + (override)); MOCK_METHOD(RetCode, Download, (const std::string&, android::base::borrowed_fd, size_t, std::string*, std::vector*), (override)); - MOCK_METHOD(RetCode, RawCommand, (const std::string&, const std::string&, std::string*, std::vector*, int*), From 59589d47dbdd3a648f2d9496c13206e795115c54 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Mon, 10 Jul 2023 16:51:30 -0700 Subject: [PATCH 0175/1487] Asserting flashing plan is used in do_flash Adding check to ensure flashing plan is used in do_flash. FlashingPlan should never be null Test: fastboot flashall -w Change-Id: I8e69326c59b31c7b54d6d2e04c8ce5c0f12693a7 --- fastboot/fastboot.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index eee0e93d031e..79c71692a8bb 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1489,10 +1489,13 @@ static std::string repack_ramdisk(const char* pname, struct fastboot_buffer* buf void do_flash(const char* pname, const char* fname, const bool apply_vbmeta, const FlashingPlan* fp) { + if (!fp) { + die("do flash was called without a valid flashing plan"); + } verbose("Do flash %s %s", pname, fname); struct fastboot_buffer buf; - if (fp && fp->source) { + if (fp->source) { unique_fd fd = fp->source->OpenFile(fname); if (fd < 0 || !load_buf_fd(std::move(fd), &buf, fp)) { die("could not load '%s': %s", fname, strerror(errno)); From eabfe272c3829cc1b0cd26dbc1aea800e7325901 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Wed, 21 Jun 2023 14:51:54 -0700 Subject: [PATCH 0176/1487] Fastboot-info testing adding test to compare task list formed from fastboot-info vs list formed from image list. To test, we need to set sparse_limit in flashing plan and turn off update-super-optimization. The list of partitions to be flashed by parsing fastboot-info should be a superset of the partitions flashed by the hardcoded list. Changing is_retrofit_device() to also take in a fastboot driver so we can pass in a mock Test: fastboot_test Bug: 194686221 Change-Id: Ib860c24c85779de1fbaa6bec8778e1f5ebb9475a --- fastboot/fastboot.cpp | 4 +-- fastboot/fastboot.h | 2 +- fastboot/task_test.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 79c71692a8bb..294121696c64 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1411,7 +1411,7 @@ void do_for_partitions(const std::string& part, const std::string& slot, } } -bool is_retrofit_device() { +bool is_retrofit_device(fastboot::IFastBootDriver* fb) { std::string value; if (fb->GetVar("super-partition-name", &value) != fastboot::SUCCESS) { return false; @@ -1878,7 +1878,7 @@ std::vector> FlashAllTool::CollectTasksFromImageList() { // On these devices, secondary slots must be flashed as physical // partitions (otherwise they would not mount on first boot). To enforce // this, we delete any logical partitions for the "other" slot. - if (is_retrofit_device()) { + if (is_retrofit_device(fp_->fb)) { std::string partition_name = image->part_name + "_"s + slot; if (image->IsSecondary() && should_flash_in_userspace(partition_name)) { fp_->fb->DeletePartition(partition_name); diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index 77430f05ad48..50db25db027e 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -187,7 +187,7 @@ void flash_partition_files(const std::string& partition, const std::vector resparse_file(sparse_file* s, int64_t max_size); -bool is_retrofit_device(); +bool is_retrofit_device(fastboot::IFastBootDriver* fb); bool is_logical(const std::string& partition); void fb_perform_format(const std::string& partition, int skip_if_not_supported, const std::string& type_override, const std::string& size_override, diff --git a/fastboot/task_test.cpp b/fastboot/task_test.cpp index b4e139b8dd03..1ba3f4ae426e 100644 --- a/fastboot/task_test.cpp +++ b/fastboot/task_test.cpp @@ -24,6 +24,7 @@ #include #include #include "android-base/strings.h" + using android::base::Split; using testing::_; @@ -60,6 +61,33 @@ std::unique_ptr ParseCommand(FlashingPlan* fp, std::string command) { return ParseFastbootInfoLine(fp, vec_command); } +// tests if tasks_a is a superset of tasks_b. Used for checking to ensure all partitions flashed +// from hardcoded image list is also flashed in new fastboot-info.txt +static bool compareTaskList(std::vector>& tasks_a, + std::vector>& tasks_b) { + std::set list; + for (auto& task : tasks_a) { + list.insert(task->ToString()); + } + for (auto& task : tasks_b) { + if (list.find(task->ToString()) == list.end()) { + std::cout << "ERROR: " << task->ToString() + << " not found in task list created by fastboot-info.txt"; + return false; + } + } + return true; +} + +static std::string tasksToString(std::vector>& tasks) { + std::string output; + for (auto& task : tasks) { + output.append(task->ToString()); + output.append("\n"); + } + return output; +} + TEST_F(ParseTest, CorrectFlashTaskFormed) { std::vector commands = {"flash dtbo", "flash --slot-other system system_other.img", "flash system", "flash --apply-vbmeta vbmeta"}; @@ -159,3 +187,51 @@ TEST_F(ParseTest, CorrectDriverCalls) { task->Run(); } } + +TEST_F(ParseTest, CorrectTaskLists) { + if (!get_android_product_out()) { + GTEST_SKIP(); + } + + LocalImageSource s; + fp->source = &s; + fp->sparse_limit = std::numeric_limits::max(); + + fastboot::MockFastbootDriver fb; + fp->fb = &fb; + fp->should_optimize_flash_super = false; + + ON_CALL(fb, GetVar("super-partition-name", _, _)) + .WillByDefault(testing::Return(fastboot::BAD_ARG)); + + FlashAllTool tool(fp.get()); + + fp->should_use_fastboot_info = false; + auto hardcoded_tasks = tool.CollectTasks(); + fp->should_use_fastboot_info = true; + auto fastboot_info_tasks = tool.CollectTasks(); + + auto is_non_flash_task = [](const auto& task) -> bool { + return task->AsFlashTask() == nullptr; + }; + + // remove non flash tasks for testing purposes + hardcoded_tasks.erase( + std::remove_if(hardcoded_tasks.begin(), hardcoded_tasks.end(), is_non_flash_task), + hardcoded_tasks.end()); + fastboot_info_tasks.erase(std::remove_if(fastboot_info_tasks.begin(), fastboot_info_tasks.end(), + is_non_flash_task), + fastboot_info_tasks.end()); + + if (!compareTaskList(fastboot_info_tasks, hardcoded_tasks)) { + std::cout << "\n\n---Hardcoded Task List---\n" + << tasksToString(hardcoded_tasks) << "\n---Fastboot-Info Task List---\n" + << tasksToString(fastboot_info_tasks); + } + + ASSERT_TRUE(compareTaskList(fastboot_info_tasks, hardcoded_tasks)); + + ASSERT_TRUE(fastboot_info_tasks.size() >= hardcoded_tasks.size()) + << "size of fastboot-info task list: " << fastboot_info_tasks.size() + << " size of hardcoded task list: " << hardcoded_tasks.size(); +} From 63dfeaae7acc9fcefdab93b71f1c691cb09887ae Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Mon, 3 Jul 2023 14:01:57 -0700 Subject: [PATCH 0177/1487] Adding flag to disable fastboot_info Adding flag to override fastboot_info for a quick fix in case fastboot_info format is wrong Test: fastboot flashall Change-Id: I1f41646f14d747ce7ac7636ca9ced7279e13f7b0 --- fastboot/fastboot.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 294121696c64..61c7204daacd 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -2213,6 +2213,7 @@ int FastBootTool::Main(int argc, char* argv[]) { {"disable-verification", no_argument, 0, 0}, {"disable-verity", no_argument, 0, 0}, {"disable-super-optimization", no_argument, 0, 0}, + {"disable-fastboot-info", no_argument, 0, 0}, {"force", no_argument, 0, 0}, {"fs-options", required_argument, 0, 0}, {"header-version", required_argument, 0, 0}, @@ -2253,6 +2254,8 @@ int FastBootTool::Main(int argc, char* argv[]) { g_disable_verity = true; } else if (name == "disable-super-optimization") { fp->should_optimize_flash_super = false; + } else if (name == "disable-fastboot-info") { + fp->should_use_fastboot_info = false; } else if (name == "force") { fp->force_flash = true; } else if (name == "fs-options") { From 6acfe9bcd01fa51b45726a306cbb2ae1c91ebac7 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Wed, 5 Jul 2023 10:23:37 -0700 Subject: [PATCH 0178/1487] Turning on fastboot-info turning on fastboot-info by default again Test: fastboot flashall Change-Id: I6b8bb0d145af37d437419a5e6cee70158ed553ae --- fastboot/fastboot.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index 50db25db027e..f6ffb641fc69 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -97,7 +97,7 @@ struct FlashingPlan { bool skip_secondary = false; bool force_flash = false; bool should_optimize_flash_super = true; - bool should_use_fastboot_info = false; + bool should_use_fastboot_info = true; uint64_t sparse_limit = 0; std::string slot_override; From 3196be61fcf0e0303cf819630876b9c812b9474e Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Tue, 11 Jul 2023 09:05:11 -0700 Subject: [PATCH 0179/1487] Revert "Fix deadlock caused by two-threaded property controls" This reverts commit 606afc7b7451aba90e3634076d9b59a5ef08186b. These fixes for b/262208935 introduced a race condition. We believe the race is fixed by ag/23879563, but at this point in the release feel that reverting the fixes and refixing in main is the better solution Test: Builds, boots Bug: 283202477 Bug: 288991737 Ignore-AOSP-First: Reverting CL only in internal Change-Id: I9ae6863b0ea5e064c59d9d34c03d33fa1da12fdc --- init/property_service.cpp | 50 ++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/init/property_service.cpp b/init/property_service.cpp index 4242912ed0af..2d084db46d2a 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -117,6 +117,7 @@ static bool accept_messages = false; static std::mutex accept_messages_lock; static std::thread property_service_thread; static std::thread property_service_for_system_thread; +static std::mutex set_property_lock; static std::unique_ptr persist_write_thread; @@ -394,37 +395,32 @@ static std::optional PropertySet(const std::string& name, const std::s return {PROP_ERROR_INVALID_VALUE}; } - if (name == "sys.powerctl") { - // No action here - NotifyPropertyChange will trigger the appropriate action, and since this - // can come to the second thread, we mustn't call out to the __system_property_* functions - // which support multiple readers but only one mutator. - } else { - prop_info* pi = (prop_info*)__system_property_find(name.c_str()); - if (pi != nullptr) { - // ro.* properties are actually "write-once". - if (StartsWith(name, "ro.")) { - *error = "Read-only property was already set"; - return {PROP_ERROR_READ_ONLY_PROPERTY}; - } + auto lock = std::lock_guard{set_property_lock}; + prop_info* pi = (prop_info*)__system_property_find(name.c_str()); + if (pi != nullptr) { + // ro.* properties are actually "write-once". + if (StartsWith(name, "ro.")) { + *error = "Read-only property was already set"; + return {PROP_ERROR_READ_ONLY_PROPERTY}; + } - __system_property_update(pi, value.c_str(), valuelen); - } else { - int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen); - if (rc < 0) { - *error = "__system_property_add failed"; - return {PROP_ERROR_SET_FAILED}; - } + __system_property_update(pi, value.c_str(), valuelen); + } else { + int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen); + if (rc < 0) { + *error = "__system_property_add failed"; + return {PROP_ERROR_SET_FAILED}; } + } - // Don't write properties to disk until after we have read all default - // properties to prevent them from being overwritten by default values. - if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) { - if (persist_write_thread) { - persist_write_thread->Write(name, value, std::move(*socket)); - return {}; - } - WritePersistentProperty(name, value); + // Don't write properties to disk until after we have read all default + // properties to prevent them from being overwritten by default values. + if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) { + if (persist_write_thread) { + persist_write_thread->Write(name, value, std::move(*socket)); + return {}; } + WritePersistentProperty(name, value); } NotifyPropertyChange(name, value); From be392fc69318d376f18eed7c8ef5ded0d1dc8648 Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Tue, 11 Jul 2023 09:05:27 -0700 Subject: [PATCH 0180/1487] Revert "Listen on property_service_for_system socket" This reverts commit 90879edeea0b2fd1e766428693d736163f39c511. These fixes for b/262208935 introduced a race condition. We believe the race is fixed by ag/23879563, but at this point in the release feel that reverting the fixes and refixing in main is the better solution Test: Builds, boots Bug: 283202477 Bug: 288991737 Ignore-AOSP-First: Reverting CL only in internal Change-Id: I28491e90847f6aa0c9767b27e1d99190637048b9 --- init/property_service.cpp | 53 ++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/init/property_service.cpp b/init/property_service.cpp index 2d084db46d2a..8da69822ccb9 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -57,12 +57,12 @@ #include #include #include -#include #include #include #include #include #include + #include "debug_ramdisk.h" #include "epoll.h" #include "init.h" @@ -111,13 +111,12 @@ constexpr auto API_LEVEL_CURRENT = 10000; static bool persistent_properties_loaded = false; +static int property_set_fd = -1; static int from_init_socket = -1; static int init_socket = -1; static bool accept_messages = false; static std::mutex accept_messages_lock; static std::thread property_service_thread; -static std::thread property_service_for_system_thread; -static std::mutex set_property_lock; static std::unique_ptr persist_write_thread; @@ -395,7 +394,6 @@ static std::optional PropertySet(const std::string& name, const std::s return {PROP_ERROR_INVALID_VALUE}; } - auto lock = std::lock_guard{set_property_lock}; prop_info* pi = (prop_info*)__system_property_find(name.c_str()); if (pi != nullptr) { // ro.* properties are actually "write-once". @@ -581,10 +579,10 @@ uint32_t HandlePropertySetNoSocket(const std::string& name, const std::string& v return *ret; } -static void handle_property_set_fd(int fd) { +static void handle_property_set_fd() { static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */ - int s = accept4(fd, nullptr, nullptr, SOCK_CLOEXEC); + int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC); if (s == -1) { return; } @@ -1421,21 +1419,19 @@ static void HandleInitSocket() { } } -static void PropertyServiceThread(int fd, bool listen_init) { +static void PropertyServiceThread() { Epoll epoll; if (auto result = epoll.Open(); !result.ok()) { LOG(FATAL) << result.error(); } - if (auto result = epoll.RegisterHandler(fd, std::bind(handle_property_set_fd, fd)); + if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd); !result.ok()) { LOG(FATAL) << result.error(); } - if (listen_init) { - if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) { - LOG(FATAL) << result.error(); - } + if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) { + LOG(FATAL) << result.error(); } while (true) { @@ -1486,23 +1482,6 @@ void PersistWriteThread::Write(std::string name, std::string value, SocketConnec cv_.notify_all(); } -void StartThread(const char* name, int mode, int gid, std::thread& t, bool listen_init) { - int fd = -1; - if (auto result = CreateSocket(name, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - /*passcred=*/false, /*should_listen=*/false, mode, /*uid=*/0, - /*gid=*/gid, /*socketcon=*/{}); - result.ok()) { - fd = *result; - } else { - LOG(FATAL) << "start_property_service socket creation failed: " << result.error(); - } - - listen(fd, 8); - - auto new_thread = std::thread(PropertyServiceThread, fd, listen_init); - t.swap(new_thread); -} - void StartPropertyService(int* epoll_socket) { InitPropertySet("ro.property_service.version", "2"); @@ -1514,9 +1493,19 @@ void StartPropertyService(int* epoll_socket) { init_socket = sockets[1]; StartSendingMessages(); - StartThread(PROP_SERVICE_FOR_SYSTEM_NAME, 0660, AID_SYSTEM, property_service_for_system_thread, - true); - StartThread(PROP_SERVICE_NAME, 0666, 0, property_service_thread, false); + if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + /*passcred=*/false, /*should_listen=*/false, 0666, /*uid=*/0, + /*gid=*/0, /*socketcon=*/{}); + result.ok()) { + property_set_fd = *result; + } else { + LOG(FATAL) << "start_property_service socket creation failed: " << result.error(); + } + + listen(property_set_fd, 8); + + auto new_thread = std::thread{PropertyServiceThread}; + property_service_thread.swap(new_thread); auto async_persist_writes = android::base::GetBoolProperty("ro.property_service.async_persist_writes", false); From 0de2195738cf608c2e051c7912ca4c97d4400734 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Thu, 29 Jun 2023 15:05:44 -0700 Subject: [PATCH 0181/1487] Migrate gettid to GetThreadId Bug: 289414897 Test: it builds Change-Id: If1214a181d4e9a193adf1bac0d35e7e3ac6c27db --- libstats/push_compat/Android.bp | 2 +- .../push_compat/{statsd_writer.c => statsd_writer.cpp} | 8 ++++---- libstats/push_compat/statsd_writer.h | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) rename libstats/push_compat/{statsd_writer.c => statsd_writer.cpp} (98%) diff --git a/libstats/push_compat/Android.bp b/libstats/push_compat/Android.bp index 819066eb4f1e..c5c1934956c4 100644 --- a/libstats/push_compat/Android.bp +++ b/libstats/push_compat/Android.bp @@ -26,7 +26,7 @@ package { cc_defaults { name: "libstatspush_compat_defaults", srcs: [ - "statsd_writer.c", + "statsd_writer.cpp", "stats_event_list.c", "StatsEventCompat.cpp" ], diff --git a/libstats/push_compat/statsd_writer.c b/libstats/push_compat/statsd_writer.cpp similarity index 98% rename from libstats/push_compat/statsd_writer.c rename to libstats/push_compat/statsd_writer.cpp index 4818d1112ec1..a3600f322fce 100644 --- a/libstats/push_compat/statsd_writer.c +++ b/libstats/push_compat/statsd_writer.cpp @@ -15,9 +15,9 @@ */ #include "statsd_writer.h" +#include #include #include -#include #include #include #include @@ -108,7 +108,7 @@ static int statsdOpen() { case -ECONNREFUSED: case -ENOENT: i = atomic_exchange(&statsdLoggerWrite.sock, ret); - /* FALLTHRU */ + break; default: break; } @@ -188,7 +188,7 @@ static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) { * }; */ - header.tid = gettid(); + header.tid = android::base::GetThreadId(); header.realtime.tv_sec = ts->tv_sec; header.realtime.tv_nsec = ts->tv_nsec; @@ -272,7 +272,7 @@ static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) { if (ret < 0) { ret = -errno; } - /* FALLTHRU */ + break; default: break; } diff --git a/libstats/push_compat/statsd_writer.h b/libstats/push_compat/statsd_writer.h index fe2d37cbc7d8..f030b96c7b5a 100644 --- a/libstats/push_compat/statsd_writer.h +++ b/libstats/push_compat/statsd_writer.h @@ -21,6 +21,8 @@ #include #include +__BEGIN_DECLS + /** * Internal lock should not be exposed. This is bad design. * TODO: rewrite it in c++ code and encapsulate the functionality in a @@ -42,4 +44,6 @@ struct android_log_transport_write { void (*noteDrop)(int error, int tag); }; +__END_DECLS + #endif // ANDROID_STATS_LOG_STATS_WRITER_H From 9c8c748c1161ffdb213336425dc1e99632fce03c Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Wed, 12 Jul 2023 18:18:42 +0000 Subject: [PATCH 0182/1487] libprocessgroup: Remove isolated UID cgroup directories Global UID level cgroup removal was eliminated because of a race between app launch and app killing using the same directory name. [1] However isolated app UIDs are assigned sequentially, and are basically never reused until we wrap around the large range of isolated UIDs. This leaves thousands of isolated cgroup directories unused, which consumes kernel memory and increases memory reclaim overhead. Remove this subset of UID level cgroup directories when killing process groups. [1] https://android.googlesource.com/platform/system/core/+/d0464b0c0180b8b98fe6a65b7188d45612b2d546 Test: 50 cycle ACT leaves 1000 fewer empty isolated cgroups Bug: 290953668 Change-Id: If7d2a7b8eec14561a72208049b74ff785ca961bd --- libprocessgroup/processgroup.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index 1f2904000866..06d386f363e7 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -223,6 +223,13 @@ static int RemoveProcessGroup(const char* cgroup, uid_t uid, int pid, unsigned i std::this_thread::sleep_for(5ms); } + if (!ret && uid >= AID_ISOLATED_START && uid <= AID_ISOLATED_END) { + // Isolated UIDs are unlikely to be reused soon after removal, + // so free up the kernel resources for the UID level cgroup. + const auto uid_path = ConvertUidToPath(cgroup, uid); + ret = rmdir(uid_path.c_str()); + } + return ret; } From cb199b47955623746a021bdb91a04478b3bd3a7e Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Wed, 30 Nov 2022 16:05:49 -0800 Subject: [PATCH 0183/1487] libutils: Improve performance of utf8_to_utf16/utf16_to_utf8 This CL improves the performance of below functions in helping with conversion between utf8/utf16 with libutils: - utf8_to_utf16_length - utf8_to_utf16 - utf16_to_utf8_length - utf16_to_utf The basic idea is to keep the loop as tight as possible for the most common cases, e.g. in UTF16-->UTF8 case, the most common case is when the character is < 0x80 (ASCII), next is when it's < 0x0800 ( most Latin), and so on. This version of implementation reduces the number of instructions needed for every incoming utf-8 bytes in the original implementation where: 1) calculating how many bytes needed given a leading UTF-8 byte in utf8_codepoint_len(), it's a very clever way but involves multiple instructions to calculate regardless 2) and an intermediate conversion to utf32, and then to utf16 utf8_to_utf32_codepoint() The end result is about ~1.5x throughput improvement. Benchmark results on redfin (64bit) before the change: utf8_to_utf16_length: bytes_per_second=307.556M/s utf8_to_utf16: bytes_per_second=246.664M/s utf16_to_utf8_length: bytes_per_second=482.241M/s utf16_to_utf8: bytes_per_second=351.376M/s After the change: utf8_to_utf16_length: bytes_per_second=544.022M/s utf8_to_utf16: bytes_per_second=471.135M/s utf16_to_utf8_length: bytes_per_second=685.381M/s utf16_to_utf8: bytes_per_second=580.004M/s Ideas for future improvement could include alignment handling and loop unrolling to increase throughput more. This CL also fixes issues below: 1. utf16_to_utf8_length() should return 0 when the source string has length of 0, the original code returns -1 as below: ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len) { if (src == nullptr || src_len == 0) { return -1; } ... 2. utf8_to_utf16() should check whether input string is valid. Change-Id: I546138a7a8050681a524eabce9864219fc44f48e --- libutils/Unicode.cpp | 358 +++++++++++++++++++++++++------------------ 1 file changed, 209 insertions(+), 149 deletions(-) diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp index 3ffcf7e34c57..364a1778c632 100644 --- a/libutils/Unicode.cpp +++ b/libutils/Unicode.cpp @@ -280,158 +280,181 @@ int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2) : 0); } -void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst, size_t dst_len) -{ - if (src == nullptr || src_len == 0 || dst == nullptr) { - return; - } - - const char16_t* cur_utf16 = src; - const char16_t* const end_utf16 = src + src_len; - char *cur = dst; - while (cur_utf16 < end_utf16) { - char32_t utf32; - // surrogate pairs - if((*cur_utf16 & 0xFC00) == 0xD800 && (cur_utf16 + 1) < end_utf16 - && (*(cur_utf16 + 1) & 0xFC00) == 0xDC00) { - utf32 = (*cur_utf16++ - 0xD800) << 10; - utf32 |= *cur_utf16++ - 0xDC00; - utf32 += 0x10000; - } else { - utf32 = (char32_t) *cur_utf16++; - } - const size_t len = utf32_codepoint_utf8_length(utf32); - LOG_ALWAYS_FATAL_IF(dst_len < len, "%zu < %zu", dst_len, len); - utf32_codepoint_to_utf8((uint8_t*)cur, utf32, len); - cur += len; - dst_len -= len; - } - LOG_ALWAYS_FATAL_IF(dst_len < 1, "%zu < 1", dst_len); - *cur = '\0'; +// is_any_surrogate() returns true if w is either a high or low surrogate +static constexpr bool is_any_surrogate(char16_t w) { + return (w & 0xf800) == 0xd800; } -// -------------------------------------------------------------------------- -// UTF-8 -// -------------------------------------------------------------------------- +// is_surrogate_pair() returns true if w1 and w2 form a valid surrogate pair +static constexpr bool is_surrogate_pair(char16_t w1, char16_t w2) { + return ((w1 & 0xfc00) == 0xd800) && ((w2 & 0xfc00) == 0xdc00); +} +// TODO: currently utf16_to_utf8_length() returns -1 if src_len == 0, +// which is inconsistent with utf8_to_utf16_length(), here we keep the +// current behavior as intended not to break compatibility ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len) { - if (src == nullptr || src_len == 0) { + if (src == nullptr || src_len == 0) return -1; - } - size_t ret = 0; const char16_t* const end = src + src_len; - while (src < end) { - size_t char_len; - if ((*src & 0xFC00) == 0xD800 && (src + 1) < end - && (*(src + 1) & 0xFC00) == 0xDC00) { - // surrogate pairs are always 4 bytes. - char_len = 4; - src += 2; - } else { - char_len = utf32_codepoint_utf8_length((char32_t)*src++); + const char16_t* in = src; + size_t utf8_len = 0; + + while (in < end) { + char16_t w = *in++; + if (LIKELY(w < 0x0080)) { + utf8_len += 1; + continue; } - if (SSIZE_MAX - char_len < ret) { - // If this happens, we would overflow the ssize_t type when - // returning from this function, so we cannot express how - // long this string is in an ssize_t. - android_errorWriteLog(0x534e4554, "37723026"); - return -1; + if (LIKELY(w < 0x0800)) { + utf8_len += 2; + continue; } - ret += char_len; + if (LIKELY(!is_any_surrogate(w))) { + utf8_len += 3; + continue; + } + if (in < end && is_surrogate_pair(w, *in)) { + utf8_len += 4; + in++; + continue; + } + /* skip if at the end of the string or invalid surrogate pair */ } - return ret; + return (in == end && utf8_len < SSIZE_MAX) ? utf8_len : -1; } -/** - * Returns 1-4 based on the number of leading bits. - * - * 1111 -> 4 - * 1110 -> 3 - * 110x -> 2 - * 10xx -> 1 - * 0xxx -> 1 - */ -static inline size_t utf8_codepoint_len(uint8_t ch) +void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst, size_t dst_len) { - return ((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1; -} + if (src == nullptr || src_len == 0 || dst == nullptr) { + return; + } -static inline void utf8_shift_and_mask(uint32_t* codePoint, const uint8_t byte) -{ - *codePoint <<= 6; - *codePoint |= 0x3F & byte; + const char16_t* in = src; + const char16_t* const in_end = src + src_len; + char* out = dst; + const char* const out_end = dst + dst_len; + char16_t w2; + + auto err_out = [&out, &out_end, &dst_len]() { + LOG_ALWAYS_FATAL_IF(out >= out_end, + "target utf8 string size %zu too short", dst_len); + }; + + while (in < in_end) { + char16_t w = *in++; + if (LIKELY(w < 0x0080)) { + if (out + 1 > out_end) + return err_out(); + *out++ = (char)(w & 0xff); + continue; + } + if (LIKELY(w < 0x0800)) { + if (out + 2 > out_end) + return err_out(); + *out++ = (char)(0xc0 | ((w >> 6) & 0x1f)); + *out++ = (char)(0x80 | ((w >> 0) & 0x3f)); + continue; + } + if (LIKELY(!is_any_surrogate(w))) { + if (out + 3 > out_end) + return err_out(); + *out++ = (char)(0xe0 | ((w >> 12) & 0xf)); + *out++ = (char)(0x80 | ((w >> 6) & 0x3f)); + *out++ = (char)(0x80 | ((w >> 0) & 0x3f)); + continue; + } + /* surrogate pair */ + if (in < in_end && (w2 = *in, is_surrogate_pair(w, w2))) { + if (out + 4 > out_end) + return err_out(); + char32_t dw = (char32_t)(0x10000 + ((w - 0xd800) << 10) + (w2 - 0xdc00)); + *out++ = (char)(0xf0 | ((dw >> 18) & 0x07)); + *out++ = (char)(0x80 | ((dw >> 12) & 0x3f)); + *out++ = (char)(0x80 | ((dw >> 6) & 0x3f)); + *out++ = (char)(0x80 | ((dw >> 0) & 0x3f)); + in++; + } + /* We reach here in two cases: + * 1) (in == in_end), which means end of the input string + * 2) (w2 & 0xfc00) != 0xdc00, which means invalid surrogate pair + * In either case, we intentionally do nothing and skip + */ + } + *out = '\0'; + return; } -static inline uint32_t utf8_to_utf32_codepoint(const uint8_t *src, size_t length) -{ - uint32_t unicode; - - switch (length) - { - case 1: - return src[0]; - case 2: - unicode = src[0] & 0x1f; - utf8_shift_and_mask(&unicode, src[1]); - return unicode; - case 3: - unicode = src[0] & 0x0f; - utf8_shift_and_mask(&unicode, src[1]); - utf8_shift_and_mask(&unicode, src[2]); - return unicode; - case 4: - unicode = src[0] & 0x07; - utf8_shift_and_mask(&unicode, src[1]); - utf8_shift_and_mask(&unicode, src[2]); - utf8_shift_and_mask(&unicode, src[3]); - return unicode; - default: - return 0xffff; - } +// -------------------------------------------------------------------------- +// UTF-8 +// -------------------------------------------------------------------------- - //printf("Char at %p: len=%d, utf-16=%p\n", src, length, (void*)result); +static char32_t utf8_4b_to_utf32(uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4) { + return ((c1 & 0x07) << 18) | ((c2 & 0x3f) << 12) | ((c3 & 0x3f) << 6) | (c4 & 0x3f); } +// TODO: current behavior of converting UTF8 to UTF-16 has a few issues below +// +// 1. invalid trailing bytes (i.e. not b'10xxxxxx) are treated as valid trailing +// bytes and follows normal conversion rules +// 2. invalid leading byte (b'10xxxxxx) is treated as a valid single UTF-8 byte +// 3. invalid leading byte (b'11111xxx) is treated as a valid leading byte +// (same as b'11110xxx) for a 4-byte UTF-8 sequence +// 4. an invalid 4-byte UTF-8 sequence that translates to a codepoint < U+10000 +// will be converted as a valid UTF-16 character +// +// We keep the current behavior as is but with warnings logged, so as not to +// break compatibility. However, this needs to be addressed later. + ssize_t utf8_to_utf16_length(const uint8_t* u8str, size_t u8len, bool overreadIsFatal) { - const uint8_t* const u8end = u8str + u8len; - const uint8_t* u8cur = u8str; - - /* Validate that the UTF-8 is the correct len */ - size_t u16measuredLen = 0; - while (u8cur < u8end) { - u16measuredLen++; - int u8charLen = utf8_codepoint_len(*u8cur); - // Malformed utf8, some characters are beyond the end. - // Cases: - // If u8charLen == 1, this becomes u8cur >= u8end, which cannot happen as u8cur < u8end, - // then this condition fail and we continue, as expected. - // If u8charLen == 2, this becomes u8cur + 1 >= u8end, which fails only if - // u8cur == u8end - 1, that is, there was only one remaining character to read but we need - // 2 of them. This condition holds and we return -1, as expected. - if (u8cur + u8charLen - 1 >= u8end) { - if (overreadIsFatal) { - LOG_ALWAYS_FATAL("Attempt to overread computing length of utf8 string"); - } else { - return -1; + if (u8str == nullptr) + return -1; + + const uint8_t* const in_end = u8str + u8len; + const uint8_t* in = u8str; + size_t utf16_len = 0; + + while (in < in_end) { + uint8_t c = *in; + utf16_len++; + if (LIKELY((c & 0x80) == 0)) { + in++; + continue; + } + if (UNLIKELY(c < 0xc0)) { + ALOGW("Invalid UTF-8 leading byte: 0x%02x", c); + in++; + continue; + } + if (LIKELY(c < 0xe0)) { + in += 2; + continue; + } + if (LIKELY(c < 0xf0)) { + in += 3; + continue; + } else { + uint8_t c2, c3, c4; + if (UNLIKELY(c >= 0xf8)) { + ALOGW("Invalid UTF-8 leading byte: 0x%02x", c); + } + c2 = in[1]; c3 = in[2]; c4 = in[3]; + if (utf8_4b_to_utf32(c, c2, c3, c4) >= 0x10000) { + utf16_len++; } + in += 4; + continue; } - uint32_t codepoint = utf8_to_utf32_codepoint(u8cur, u8charLen); - if (codepoint > 0xFFFF) u16measuredLen++; // this will be a surrogate pair in utf16 - u8cur += u8charLen; } - - /** - * Make sure that we ended where we thought we would and the output UTF-16 - * will be exactly how long we were told it would be. - */ - if (u8cur != u8end) { - return -1; + if (in == in_end) { + return utf16_len < SSIZE_MAX ? utf16_len : -1; } - - return u16measuredLen; + if (overreadIsFatal) + LOG_ALWAYS_FATAL("Attempt to overread computing length of utf8 string"); + return -1; } char16_t* utf8_to_utf16(const uint8_t* u8str, size_t u8len, char16_t* u16str, size_t u16len) { @@ -444,38 +467,75 @@ char16_t* utf8_to_utf16(const uint8_t* u8str, size_t u8len, char16_t* u16str, si char16_t* utf8_to_utf16_no_null_terminator( const uint8_t* src, size_t srcLen, char16_t* dst, size_t dstLen) { - if (dstLen == 0) { + if (src == nullptr || srcLen == 0 || dstLen == 0) { return dst; } // A value > SSIZE_MAX is probably a negative value returned as an error and casted. LOG_ALWAYS_FATAL_IF(dstLen > SSIZE_MAX, "dstLen is %zu", dstLen); - const uint8_t* const u8end = src + srcLen; - const uint8_t* u8cur = src; - const char16_t* const u16end = dst + dstLen; - char16_t* u16cur = dst; - - while (u8cur < u8end && u16cur < u16end) { - size_t u8len = utf8_codepoint_len(*u8cur); - uint32_t codepoint = utf8_to_utf32_codepoint(u8cur, u8len); - - // Convert the UTF32 codepoint to one or more UTF16 codepoints - if (codepoint <= 0xFFFF) { - // Single UTF16 character - *u16cur++ = (char16_t) codepoint; + + const uint8_t* const in_end = src + srcLen; + const uint8_t* in = src; + const char16_t* const out_end = dst + dstLen; + char16_t* out = dst; + uint8_t c, c2, c3, c4; + char32_t w; + + auto err_in = [&c, &out]() { + ALOGW("Unended UTF-8 byte: 0x%02x", c); + return out; + }; + + while (in < in_end && out < out_end) { + c = *in++; + if (LIKELY((c & 0x80) == 0)) { + *out++ = (char16_t)(c); + continue; + } + if (UNLIKELY(c < 0xc0)) { + ALOGW("Invalid UTF-8 leading byte: 0x%02x", c); + *out++ = (char16_t)(c); + continue; + } + if (LIKELY(c < 0xe0)) { + if (UNLIKELY(in + 1 > in_end)) { + return err_in(); + } + c2 = *in++; + *out++ = (char16_t)(((c & 0x1f) << 6) | (c2 & 0x3f)); + continue; + } + if (LIKELY(c < 0xf0)) { + if (UNLIKELY(in + 2 > in_end)) { + return err_in(); + } + c2 = *in++; c3 = *in++; + *out++ = (char16_t)(((c & 0x0f) << 12) | + ((c2 & 0x3f) << 6) | (c3 & 0x3f)); + continue; } else { + if (UNLIKELY(in + 3 > in_end)) { + return err_in(); + } + if (UNLIKELY(c >= 0xf8)) { + ALOGW("Invalid UTF-8 leading byte: 0x%02x", c); + } // Multiple UTF16 characters with surrogates - codepoint = codepoint - 0x10000; - *u16cur++ = (char16_t) ((codepoint >> 10) + 0xD800); - if (u16cur >= u16end) { - // Ooops... not enough room for this surrogate pair. - return u16cur-1; + c2 = *in++; c3 = *in++; c4 = *in++; + w = utf8_4b_to_utf32(c, c2, c3, c4); + if (UNLIKELY(w < 0x10000)) { + *out++ = (char16_t)(w); + } else { + if (UNLIKELY(out + 2 > out_end)) { + // Ooops.... not enough room for this surrogate pair. + return out; + } + *out++ = (char16_t)(((w - 0x10000) >> 10) + 0xd800); + *out++ = (char16_t)(((w - 0x10000) & 0x3ff) + 0xdc00); } - *u16cur++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00); + continue; } - - u8cur += u8len; } - return u16cur; + return out; } } From a4648c2be0f8cc58474c426f850ac02745154c35 Mon Sep 17 00:00:00 2001 From: Kiyoung Kim Date: Fri, 23 Jun 2023 11:12:38 +0900 Subject: [PATCH 0184/1487] Enable ABI dump for libcutils Enable ABI dump for libcutils, so ABI can be stabilized from any update after official release. Bug: 254141417 Test: abidiff intermediates found from libcutils.vendor build Change-Id: Ic27c82b908b7836c7bc538a24202ed8adba4d048 --- libcutils/Android.bp | 8 + .../arm64/source-based/libcutils.so.lsdump | 2690 ++++++++++++++++ .../source-based/libcutils.so.lsdump | 2700 +++++++++++++++++ 3 files changed, 5398 insertions(+) create mode 100644 libcutils/abi-dumps/arm64/source-based/libcutils.so.lsdump create mode 100644 libcutils/abi-dumps/arm_arm64/source-based/libcutils.so.lsdump diff --git a/libcutils/Android.bp b/libcutils/Android.bp index 0b5c1254ea2a..92486e3357a8 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -219,11 +219,19 @@ cc_library { exclude_srcs: [ "qtaguid.cpp", ], + header_abi_checker: { + enabled: true, + ref_dump_dirs: ["abi-dumps"], + }, }, product: { exclude_srcs: [ "qtaguid.cpp", ], + header_abi_checker: { + enabled: true, + ref_dump_dirs: ["abi-dumps"], + }, }, }, diff --git a/libcutils/abi-dumps/arm64/source-based/libcutils.so.lsdump b/libcutils/abi-dumps/arm64/source-based/libcutils.so.lsdump new file mode 100644 index 000000000000..333e61c181fa --- /dev/null +++ b/libcutils/abi-dumps/arm64/source-based/libcutils.so.lsdump @@ -0,0 +1,2690 @@ +{ + "array_types" : + [ + { + "alignment" : 4, + "linker_set_key" : "_ZTIA0_i", + "name" : "int[0]", + "referenced_type" : "_ZTIi", + "self_type" : "_ZTIA0_i", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + } + ], + "builtin_types" : + [ + { + "alignment" : 1, + "is_integral" : true, + "linker_set_key" : "_ZTIa", + "name" : "signed char", + "referenced_type" : "_ZTIa", + "self_type" : "_ZTIa", + "size" : 1 + }, + { + "alignment" : 1, + "is_integral" : true, + "is_unsigned" : true, + "linker_set_key" : "_ZTIb", + "name" : "bool", + "referenced_type" : "_ZTIb", + "self_type" : "_ZTIb", + "size" : 1 + }, + { + "alignment" : 1, + "is_integral" : true, + "is_unsigned" : true, + "linker_set_key" : "_ZTIc", + "name" : "char", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIc", + "size" : 1 + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIf", + "name" : "float", + "referenced_type" : "_ZTIf", + "self_type" : "_ZTIf", + "size" : 4 + }, + { + "alignment" : 4, + "is_integral" : true, + "linker_set_key" : "_ZTIi", + "name" : "int", + "referenced_type" : "_ZTIi", + "self_type" : "_ZTIi", + "size" : 4 + }, + { + "alignment" : 4, + "is_integral" : true, + "is_unsigned" : true, + "linker_set_key" : "_ZTIj", + "name" : "unsigned int", + "referenced_type" : "_ZTIj", + "self_type" : "_ZTIj", + "size" : 4 + }, + { + "alignment" : 8, + "is_integral" : true, + "linker_set_key" : "_ZTIl", + "name" : "long", + "referenced_type" : "_ZTIl", + "self_type" : "_ZTIl", + "size" : 8 + }, + { + "alignment" : 8, + "is_integral" : true, + "is_unsigned" : true, + "linker_set_key" : "_ZTIm", + "name" : "unsigned long", + "referenced_type" : "_ZTIm", + "self_type" : "_ZTIm", + "size" : 8 + }, + { + "linker_set_key" : "_ZTIv", + "name" : "void", + "referenced_type" : "_ZTIv", + "self_type" : "_ZTIv" + } + ], + "elf_functions" : + [ + { + "name" : "_Z23socket_make_sockaddr_unPKciP11sockaddr_unPj" + }, + { + "binding" : "weak", + "name" : "_ZN7android4base4TrimIRNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEES8_OT_" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE4syncEv" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE5imbueERKNS_6localeE" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE6setbufEPcl" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE7seekoffExNS_8ios_base7seekdirEj" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE7seekposENS_4fposI9mbstate_tEEj" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE8overflowEi" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE9pbackfailEi" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE9underflowEv" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEEC2Ev" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEED0Ev" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEED2Ev" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__16vectorI5EntryNS_9allocatorIS1_EEE24__emplace_back_slow_pathIJS1_EEEvDpOT_" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__17getlineIcNS_11char_traitsIcEENS_9allocatorIcEEEERNS_13basic_istreamIT_T0_EES9_RNS_12basic_stringIS6_S7_T1_EES6_" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__1lsINS_11char_traitsIcEEEERNS_13basic_ostreamIcT_EES6_PKc" + }, + { + "name" : "android_get_control_file" + }, + { + "name" : "android_get_control_socket" + }, + { + "name" : "android_get_ioprio" + }, + { + "name" : "android_reboot" + }, + { + "name" : "android_set_ioprio" + }, + { + "name" : "ashmem_create_region" + }, + { + "name" : "ashmem_get_size_region" + }, + { + "name" : "ashmem_pin_region" + }, + { + "name" : "ashmem_set_prot_region" + }, + { + "name" : "ashmem_unpin_region" + }, + { + "name" : "ashmem_valid" + }, + { + "name" : "atrace_async_begin_body" + }, + { + "name" : "atrace_async_end_body" + }, + { + "name" : "atrace_async_for_track_begin_body" + }, + { + "name" : "atrace_async_for_track_end_body" + }, + { + "name" : "atrace_begin_body" + }, + { + "name" : "atrace_end_body" + }, + { + "name" : "atrace_get_enabled_tags" + }, + { + "name" : "atrace_init" + }, + { + "name" : "atrace_instant_body" + }, + { + "name" : "atrace_instant_for_track_body" + }, + { + "name" : "atrace_int64_body" + }, + { + "name" : "atrace_int_body" + }, + { + "name" : "atrace_set_tracing_enabled" + }, + { + "name" : "atrace_setup" + }, + { + "name" : "atrace_update_tags" + }, + { + "name" : "canned_fs_config" + }, + { + "name" : "config_bool" + }, + { + "name" : "config_find" + }, + { + "name" : "config_free" + }, + { + "name" : "config_load" + }, + { + "name" : "config_load_file" + }, + { + "name" : "config_node" + }, + { + "name" : "config_set" + }, + { + "name" : "config_str" + }, + { + "name" : "fs_config" + }, + { + "name" : "fs_mkdirs" + }, + { + "name" : "fs_prepare_dir" + }, + { + "name" : "fs_prepare_dir_strict" + }, + { + "name" : "fs_prepare_file_strict" + }, + { + "name" : "fs_read_atomic_int" + }, + { + "name" : "fs_write_atomic_int" + }, + { + "name" : "hashmapCreate" + }, + { + "name" : "hashmapForEach" + }, + { + "name" : "hashmapFree" + }, + { + "name" : "hashmapGet" + }, + { + "name" : "hashmapHash" + }, + { + "name" : "hashmapLock" + }, + { + "name" : "hashmapPut" + }, + { + "name" : "hashmapRemove" + }, + { + "name" : "hashmapUnlock" + }, + { + "name" : "klog_set_level" + }, + { + "name" : "klog_write" + }, + { + "name" : "klog_writev" + }, + { + "name" : "load_canned_fs_config" + }, + { + "name" : "load_file" + }, + { + "name" : "multiuser_convert_sdk_sandbox_to_app_uid" + }, + { + "name" : "multiuser_get_app_id" + }, + { + "name" : "multiuser_get_cache_gid" + }, + { + "name" : "multiuser_get_ext_cache_gid" + }, + { + "name" : "multiuser_get_ext_gid" + }, + { + "name" : "multiuser_get_sdk_sandbox_uid" + }, + { + "name" : "multiuser_get_shared_app_gid" + }, + { + "name" : "multiuser_get_shared_gid" + }, + { + "name" : "multiuser_get_uid" + }, + { + "name" : "multiuser_get_user_id" + }, + { + "name" : "native_handle_clone" + }, + { + "name" : "native_handle_close" + }, + { + "name" : "native_handle_close_with_tag" + }, + { + "name" : "native_handle_create" + }, + { + "name" : "native_handle_delete" + }, + { + "name" : "native_handle_init" + }, + { + "name" : "native_handle_set_fdsan_tag" + }, + { + "name" : "native_handle_unset_fdsan_tag" + }, + { + "name" : "partition_wiped" + }, + { + "name" : "property_get" + }, + { + "name" : "property_get_bool" + }, + { + "name" : "property_get_int32" + }, + { + "name" : "property_get_int64" + }, + { + "name" : "property_list" + }, + { + "name" : "property_set" + }, + { + "name" : "record_stream_free" + }, + { + "name" : "record_stream_get_next" + }, + { + "name" : "record_stream_new" + }, + { + "name" : "socket_close" + }, + { + "name" : "socket_get_local_port" + }, + { + "name" : "socket_inaddr_any_server" + }, + { + "name" : "socket_local_client" + }, + { + "name" : "socket_local_client_connect" + }, + { + "name" : "socket_local_server" + }, + { + "name" : "socket_local_server_bind" + }, + { + "name" : "socket_network_client" + }, + { + "name" : "socket_network_client_timeout" + }, + { + "name" : "socket_send_buffers" + }, + { + "name" : "str_parms_add_float" + }, + { + "name" : "str_parms_add_int" + }, + { + "name" : "str_parms_add_str" + }, + { + "name" : "str_parms_create" + }, + { + "name" : "str_parms_create_str" + }, + { + "name" : "str_parms_del" + }, + { + "name" : "str_parms_destroy" + }, + { + "name" : "str_parms_dump" + }, + { + "name" : "str_parms_get_float" + }, + { + "name" : "str_parms_get_int" + }, + { + "name" : "str_parms_get_str" + }, + { + "name" : "str_parms_has_key" + }, + { + "name" : "str_parms_to_str" + }, + { + "name" : "uevent_kernel_multicast_recv" + }, + { + "name" : "uevent_kernel_multicast_uid_recv" + }, + { + "name" : "uevent_kernel_recv" + }, + { + "name" : "uevent_open_socket" + } + ], + "elf_objects" : + [ + { + "binding" : "weak", + "name" : "_ZTCNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE0_NS_13basic_istreamIcS2_EE" + }, + { + "binding" : "weak", + "name" : "_ZTTNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE" + }, + { + "binding" : "weak", + "name" : "_ZTVNSt3__113basic_filebufIcNS_11char_traitsIcEEEE" + }, + { + "binding" : "weak", + "name" : "_ZTVNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE" + }, + { + "name" : "atrace_enabled_tags" + }, + { + "name" : "atrace_is_ready" + }, + { + "name" : "atrace_marker_fd" + } + ], + "enum_types" : + [ + { + "alignment" : 4, + "enum_fields" : + [ + { + "enum_field_value" : 0, + "name" : "IoSchedClass_NONE" + }, + { + "enum_field_value" : 1, + "name" : "IoSchedClass_RT" + }, + { + "enum_field_value" : 2, + "name" : "IoSchedClass_BE" + }, + { + "enum_field_value" : 3, + "name" : "IoSchedClass_IDLE" + } + ], + "linker_set_key" : "_ZTI12IoSchedClass", + "name" : "IoSchedClass", + "referenced_type" : "_ZTI12IoSchedClass", + "self_type" : "_ZTI12IoSchedClass", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h", + "underlying_type" : "_ZTIj" + } + ], + "function_types" : + [ + { + "alignment" : 4, + "linker_set_key" : "_ZTIFbPvS_E", + "name" : "bool (void *, void *)", + "parameters" : + [ + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "referenced_type" : "_ZTIFbPvS_E", + "return_type" : "_ZTIb", + "self_type" : "_ZTIFbPvS_E", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIFbPvS_S_E", + "name" : "bool (void *, void *, void *)", + "parameters" : + [ + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "referenced_type" : "_ZTIFbPvS_S_E", + "return_type" : "_ZTIb", + "self_type" : "_ZTIFbPvS_S_E", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIFiPvE", + "name" : "int (void *)", + "parameters" : + [ + { + "referenced_type" : "_ZTIPv" + } + ], + "referenced_type" : "_ZTIFiPvE", + "return_type" : "_ZTIi", + "self_type" : "_ZTIFiPvE", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIFvPKcS0_PvE", + "name" : "void (const char *, const char *, void *)", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "referenced_type" : "_ZTIFvPKcS0_PvE", + "return_type" : "_ZTIv", + "self_type" : "_ZTIFvPKcS0_PvE", + "source_file" : "system/core/libcutils/include/cutils/properties.h" + } + ], + "functions" : + [ + { + "function_name" : "android_get_control_file", + "linker_set_key" : "android_get_control_file", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/android_get_control_file.h" + }, + { + "function_name" : "android_get_control_socket", + "linker_set_key" : "android_get_control_socket", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "android_get_ioprio", + "linker_set_key" : "android_get_ioprio", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIP12IoSchedClass" + }, + { + "referenced_type" : "_ZTIPi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h" + }, + { + "function_name" : "android_reboot", + "linker_set_key" : "android_reboot", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/android_reboot.h" + }, + { + "function_name" : "android_set_ioprio", + "linker_set_key" : "android_set_ioprio", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTI12IoSchedClass" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h" + }, + { + "function_name" : "ashmem_create_region", + "linker_set_key" : "ashmem_create_region", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIm" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/ashmem.h" + }, + { + "function_name" : "ashmem_get_size_region", + "linker_set_key" : "ashmem_get_size_region", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/ashmem.h" + }, + { + "function_name" : "ashmem_pin_region", + "linker_set_key" : "ashmem_pin_region", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIm" + }, + { + "referenced_type" : "_ZTIm" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/ashmem.h" + }, + { + "function_name" : "ashmem_set_prot_region", + "linker_set_key" : "ashmem_set_prot_region", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/ashmem.h" + }, + { + "function_name" : "ashmem_unpin_region", + "linker_set_key" : "ashmem_unpin_region", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIm" + }, + { + "referenced_type" : "_ZTIm" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/ashmem.h" + }, + { + "function_name" : "ashmem_valid", + "linker_set_key" : "ashmem_valid", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/ashmem.h" + }, + { + "function_name" : "atrace_async_begin_body", + "linker_set_key" : "atrace_async_begin_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_async_end_body", + "linker_set_key" : "atrace_async_end_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_async_for_track_begin_body", + "linker_set_key" : "atrace_async_for_track_begin_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_async_for_track_end_body", + "linker_set_key" : "atrace_async_for_track_end_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_begin_body", + "linker_set_key" : "atrace_begin_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_end_body", + "linker_set_key" : "atrace_end_body", + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_get_enabled_tags", + "linker_set_key" : "atrace_get_enabled_tags", + "return_type" : "_ZTIm", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_init", + "linker_set_key" : "atrace_init", + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_instant_body", + "linker_set_key" : "atrace_instant_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_instant_for_track_body", + "linker_set_key" : "atrace_instant_for_track_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_int64_body", + "linker_set_key" : "atrace_int64_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIl" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_int_body", + "linker_set_key" : "atrace_int_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_set_tracing_enabled", + "linker_set_key" : "atrace_set_tracing_enabled", + "parameters" : + [ + { + "referenced_type" : "_ZTIb" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_setup", + "linker_set_key" : "atrace_setup", + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_update_tags", + "linker_set_key" : "atrace_update_tags", + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "canned_fs_config", + "linker_set_key" : "canned_fs_config", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPj" + }, + { + "referenced_type" : "_ZTIPj" + }, + { + "referenced_type" : "_ZTIPj" + }, + { + "referenced_type" : "_ZTIPm" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/private/canned_fs_config.h" + }, + { + "function_name" : "config_bool", + "linker_set_key" : "config_bool", + "parameters" : + [ + { + "referenced_type" : "_ZTIP5cnode" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "config_find", + "linker_set_key" : "config_find", + "parameters" : + [ + { + "referenced_type" : "_ZTIP5cnode" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIP5cnode", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "config_free", + "linker_set_key" : "config_free", + "parameters" : + [ + { + "referenced_type" : "_ZTIP5cnode" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "config_load", + "linker_set_key" : "config_load", + "parameters" : + [ + { + "referenced_type" : "_ZTIP5cnode" + }, + { + "referenced_type" : "_ZTIPc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "config_load_file", + "linker_set_key" : "config_load_file", + "parameters" : + [ + { + "referenced_type" : "_ZTIP5cnode" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "config_node", + "linker_set_key" : "config_node", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIP5cnode", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "config_set", + "linker_set_key" : "config_set", + "parameters" : + [ + { + "referenced_type" : "_ZTIP5cnode" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "config_str", + "linker_set_key" : "config_str", + "parameters" : + [ + { + "referenced_type" : "_ZTIP5cnode" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIPKc", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "fs_config", + "linker_set_key" : "fs_config", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPj" + }, + { + "referenced_type" : "_ZTIPj" + }, + { + "referenced_type" : "_ZTIPj" + }, + { + "referenced_type" : "_ZTIPm" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/private/fs_config.h" + }, + { + "function_name" : "fs_mkdirs", + "linker_set_key" : "fs_mkdirs", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/fs.h" + }, + { + "function_name" : "fs_prepare_dir", + "linker_set_key" : "fs_prepare_dir", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/fs.h" + }, + { + "function_name" : "fs_prepare_dir_strict", + "linker_set_key" : "fs_prepare_dir_strict", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/fs.h" + }, + { + "function_name" : "fs_prepare_file_strict", + "linker_set_key" : "fs_prepare_file_strict", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/fs.h" + }, + { + "function_name" : "fs_read_atomic_int", + "linker_set_key" : "fs_read_atomic_int", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/fs.h" + }, + { + "function_name" : "fs_write_atomic_int", + "linker_set_key" : "fs_write_atomic_int", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/fs.h" + }, + { + "function_name" : "hashmapCreate", + "linker_set_key" : "hashmapCreate", + "parameters" : + [ + { + "referenced_type" : "_ZTIm" + }, + { + "referenced_type" : "_ZTIPFiPvE" + }, + { + "referenced_type" : "_ZTIPFbPvS_E" + } + ], + "return_type" : "_ZTIP7Hashmap", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapForEach", + "linker_set_key" : "hashmapForEach", + "parameters" : + [ + { + "referenced_type" : "_ZTIP7Hashmap" + }, + { + "referenced_type" : "_ZTIPFbPvS_S_E" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapFree", + "linker_set_key" : "hashmapFree", + "parameters" : + [ + { + "referenced_type" : "_ZTIP7Hashmap" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapGet", + "linker_set_key" : "hashmapGet", + "parameters" : + [ + { + "referenced_type" : "_ZTIP7Hashmap" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "return_type" : "_ZTIPv", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapHash", + "linker_set_key" : "hashmapHash", + "parameters" : + [ + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIm" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapLock", + "linker_set_key" : "hashmapLock", + "parameters" : + [ + { + "referenced_type" : "_ZTIP7Hashmap" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapPut", + "linker_set_key" : "hashmapPut", + "parameters" : + [ + { + "referenced_type" : "_ZTIP7Hashmap" + }, + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "return_type" : "_ZTIPv", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapRemove", + "linker_set_key" : "hashmapRemove", + "parameters" : + [ + { + "referenced_type" : "_ZTIP7Hashmap" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "return_type" : "_ZTIPv", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapUnlock", + "linker_set_key" : "hashmapUnlock", + "parameters" : + [ + { + "referenced_type" : "_ZTIP7Hashmap" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "klog_set_level", + "linker_set_key" : "klog_set_level", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/klog.h" + }, + { + "function_name" : "klog_write", + "linker_set_key" : "klog_write", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/klog.h" + }, + { + "function_name" : "klog_writev", + "linker_set_key" : "klog_writev", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPK5iovec" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/klog.h" + }, + { + "function_name" : "load_canned_fs_config", + "linker_set_key" : "load_canned_fs_config", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/private/canned_fs_config.h" + }, + { + "function_name" : "load_file", + "linker_set_key" : "load_file", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPj" + } + ], + "return_type" : "_ZTIPv", + "source_file" : "system/core/libcutils/include/cutils/misc.h" + }, + { + "function_name" : "multiuser_convert_sdk_sandbox_to_app_uid", + "linker_set_key" : "multiuser_convert_sdk_sandbox_to_app_uid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_app_id", + "linker_set_key" : "multiuser_get_app_id", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_cache_gid", + "linker_set_key" : "multiuser_get_cache_gid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_ext_cache_gid", + "linker_set_key" : "multiuser_get_ext_cache_gid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_ext_gid", + "linker_set_key" : "multiuser_get_ext_gid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_sdk_sandbox_uid", + "linker_set_key" : "multiuser_get_sdk_sandbox_uid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_shared_app_gid", + "linker_set_key" : "multiuser_get_shared_app_gid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_shared_gid", + "linker_set_key" : "multiuser_get_shared_gid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_uid", + "linker_set_key" : "multiuser_get_uid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_user_id", + "linker_set_key" : "multiuser_get_user_id", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "native_handle_clone", + "linker_set_key" : "native_handle_clone", + "parameters" : + [ + { + "referenced_type" : "_ZTIPK13native_handle" + } + ], + "return_type" : "_ZTIP13native_handle", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "native_handle_close", + "linker_set_key" : "native_handle_close", + "parameters" : + [ + { + "referenced_type" : "_ZTIPK13native_handle" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "native_handle_close_with_tag", + "linker_set_key" : "native_handle_close_with_tag", + "parameters" : + [ + { + "referenced_type" : "_ZTIPK13native_handle" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "native_handle_create", + "linker_set_key" : "native_handle_create", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIP13native_handle", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "native_handle_delete", + "linker_set_key" : "native_handle_delete", + "parameters" : + [ + { + "referenced_type" : "_ZTIP13native_handle" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "native_handle_init", + "linker_set_key" : "native_handle_init", + "parameters" : + [ + { + "referenced_type" : "_ZTIPc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIP13native_handle", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "native_handle_set_fdsan_tag", + "linker_set_key" : "native_handle_set_fdsan_tag", + "parameters" : + [ + { + "referenced_type" : "_ZTIPK13native_handle" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "native_handle_unset_fdsan_tag", + "linker_set_key" : "native_handle_unset_fdsan_tag", + "parameters" : + [ + { + "referenced_type" : "_ZTIPK13native_handle" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "partition_wiped", + "linker_set_key" : "partition_wiped", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/partition_utils.h" + }, + { + "function_name" : "property_get", + "linker_set_key" : "property_get", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPc" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/properties.h" + }, + { + "function_name" : "property_get_bool", + "linker_set_key" : "property_get_bool", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIa" + } + ], + "return_type" : "_ZTIa", + "source_file" : "system/core/libcutils/include/cutils/properties.h" + }, + { + "function_name" : "property_get_int32", + "linker_set_key" : "property_get_int32", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/properties.h" + }, + { + "function_name" : "property_get_int64", + "linker_set_key" : "property_get_int64", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIl" + } + ], + "return_type" : "_ZTIl", + "source_file" : "system/core/libcutils/include/cutils/properties.h" + }, + { + "function_name" : "property_list", + "linker_set_key" : "property_list", + "parameters" : + [ + { + "referenced_type" : "_ZTIPFvPKcS0_PvE" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/properties.h" + }, + { + "function_name" : "property_set", + "linker_set_key" : "property_set", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/properties.h" + }, + { + "function_name" : "record_stream_free", + "linker_set_key" : "record_stream_free", + "parameters" : + [ + { + "referenced_type" : "_ZTIP12RecordStream" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/record_stream.h" + }, + { + "function_name" : "record_stream_get_next", + "linker_set_key" : "record_stream_get_next", + "parameters" : + [ + { + "referenced_type" : "_ZTIP12RecordStream" + }, + { + "referenced_type" : "_ZTIPPv" + }, + { + "referenced_type" : "_ZTIPm" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/record_stream.h" + }, + { + "function_name" : "record_stream_new", + "linker_set_key" : "record_stream_new", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIm" + } + ], + "return_type" : "_ZTIP12RecordStream", + "source_file" : "system/core/libcutils/include/cutils/record_stream.h" + }, + { + "function_name" : "socket_close", + "linker_set_key" : "socket_close", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_get_local_port", + "linker_set_key" : "socket_get_local_port", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_inaddr_any_server", + "linker_set_key" : "socket_inaddr_any_server", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_local_client", + "linker_set_key" : "socket_local_client", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_local_client_connect", + "linker_set_key" : "socket_local_client_connect", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_local_server", + "linker_set_key" : "socket_local_server", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_local_server_bind", + "linker_set_key" : "socket_local_server_bind", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_network_client", + "linker_set_key" : "socket_network_client", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_network_client_timeout", + "linker_set_key" : "socket_network_client_timeout", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_send_buffers", + "linker_set_key" : "socket_send_buffers", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPK22cutils_socket_buffer_t" + }, + { + "referenced_type" : "_ZTIm" + } + ], + "return_type" : "_ZTIl", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "str_parms_add_float", + "linker_set_key" : "str_parms_add_float", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIf" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_add_int", + "linker_set_key" : "str_parms_add_int", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_add_str", + "linker_set_key" : "str_parms_add_str", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_create", + "linker_set_key" : "str_parms_create", + "return_type" : "_ZTIP9str_parms", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_create_str", + "linker_set_key" : "str_parms_create_str", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIP9str_parms", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_del", + "linker_set_key" : "str_parms_del", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_destroy", + "linker_set_key" : "str_parms_destroy", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_dump", + "linker_set_key" : "str_parms_dump", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_get_float", + "linker_set_key" : "str_parms_get_float", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPf" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_get_int", + "linker_set_key" : "str_parms_get_int", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_get_str", + "linker_set_key" : "str_parms_get_str", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_has_key", + "linker_set_key" : "str_parms_has_key", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_to_str", + "linker_set_key" : "str_parms_to_str", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + } + ], + "return_type" : "_ZTIPc", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "uevent_kernel_multicast_recv", + "linker_set_key" : "uevent_kernel_multicast_recv", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIm" + } + ], + "return_type" : "_ZTIl", + "source_file" : "system/core/libcutils/include/cutils/uevent.h" + }, + { + "function_name" : "uevent_kernel_multicast_uid_recv", + "linker_set_key" : "uevent_kernel_multicast_uid_recv", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIm" + }, + { + "referenced_type" : "_ZTIPj" + } + ], + "return_type" : "_ZTIl", + "source_file" : "system/core/libcutils/include/cutils/uevent.h" + }, + { + "function_name" : "uevent_kernel_recv", + "linker_set_key" : "uevent_kernel_recv", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIm" + }, + { + "referenced_type" : "_ZTIb" + }, + { + "referenced_type" : "_ZTIPj" + } + ], + "return_type" : "_ZTIl", + "source_file" : "system/core/libcutils/include/cutils/uevent.h" + }, + { + "function_name" : "uevent_open_socket", + "linker_set_key" : "uevent_open_socket", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIb" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/uevent.h" + } + ], + "global_vars" : + [ + { + "linker_set_key" : "atrace_enabled_tags", + "name" : "atrace_enabled_tags", + "referenced_type" : "_ZTIm", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "linker_set_key" : "atrace_is_ready", + "name" : "atrace_is_ready", + "referenced_type" : "_ZTINSt3__16atomicIbEE", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "linker_set_key" : "atrace_marker_fd", + "name" : "atrace_marker_fd", + "referenced_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + } + ], + "lvalue_reference_types" : [], + "pointer_types" : + [ + { + "alignment" : 8, + "linker_set_key" : "_ZTIP12IoSchedClass", + "name" : "IoSchedClass *", + "referenced_type" : "_ZTI12IoSchedClass", + "self_type" : "_ZTIP12IoSchedClass", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIP12RecordStream", + "name" : "RecordStream *", + "referenced_type" : "_ZTI12RecordStream", + "self_type" : "_ZTIP12RecordStream", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/record_stream.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIP13native_handle", + "name" : "native_handle *", + "referenced_type" : "_ZTI13native_handle", + "self_type" : "_ZTIP13native_handle", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIP5cnode", + "name" : "cnode *", + "referenced_type" : "_ZTI5cnode", + "self_type" : "_ZTIP5cnode", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIP7Hashmap", + "name" : "Hashmap *", + "referenced_type" : "_ZTI7Hashmap", + "self_type" : "_ZTIP7Hashmap", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIP9str_parms", + "name" : "str_parms *", + "referenced_type" : "_ZTI9str_parms", + "self_type" : "_ZTIP9str_parms", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPFbPvS_E", + "name" : "bool (*)(void *, void *)", + "referenced_type" : "_ZTIFbPvS_E", + "self_type" : "_ZTIPFbPvS_E", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPFbPvS_S_E", + "name" : "bool (*)(void *, void *, void *)", + "referenced_type" : "_ZTIFbPvS_S_E", + "self_type" : "_ZTIPFbPvS_S_E", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPFiPvE", + "name" : "int (*)(void *)", + "referenced_type" : "_ZTIFiPvE", + "self_type" : "_ZTIPFiPvE", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPFvPKcS0_PvE", + "name" : "void (*)(const char *, const char *, void *)", + "referenced_type" : "_ZTIFvPKcS0_PvE", + "self_type" : "_ZTIPFvPKcS0_PvE", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/properties.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPK13native_handle", + "name" : "const native_handle *", + "referenced_type" : "_ZTIK13native_handle", + "self_type" : "_ZTIPK13native_handle", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPK22cutils_socket_buffer_t", + "name" : "const cutils_socket_buffer_t *", + "referenced_type" : "_ZTIK22cutils_socket_buffer_t", + "self_type" : "_ZTIPK22cutils_socket_buffer_t", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPK5iovec", + "name" : "const iovec *", + "referenced_type" : "_ZTIK5iovec", + "self_type" : "_ZTIPK5iovec", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/klog.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPKc", + "name" : "const char *", + "referenced_type" : "_ZTIKc", + "self_type" : "_ZTIPKc", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPKv", + "name" : "const void *", + "referenced_type" : "_ZTIKv", + "self_type" : "_ZTIPKv", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPPv", + "name" : "void **", + "referenced_type" : "_ZTIPv", + "self_type" : "_ZTIPPv", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/record_stream.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPc", + "name" : "char *", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIPc", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPf", + "name" : "float *", + "referenced_type" : "_ZTIf", + "self_type" : "_ZTIPf", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPi", + "name" : "int *", + "referenced_type" : "_ZTIi", + "self_type" : "_ZTIPi", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPj", + "name" : "unsigned int *", + "referenced_type" : "_ZTIj", + "self_type" : "_ZTIPj", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/misc.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPm", + "name" : "unsigned long *", + "referenced_type" : "_ZTIm", + "self_type" : "_ZTIPm", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/record_stream.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPv", + "name" : "void *", + "referenced_type" : "_ZTIv", + "self_type" : "_ZTIPv", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/misc.h" + } + ], + "qualified_types" : + [ + { + "alignment" : 4, + "is_const" : true, + "linker_set_key" : "_ZTIK13native_handle", + "name" : "const native_handle", + "referenced_type" : "_ZTI13native_handle", + "self_type" : "_ZTIK13native_handle", + "size" : 12, + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "alignment" : 8, + "is_const" : true, + "linker_set_key" : "_ZTIK22cutils_socket_buffer_t", + "name" : "const cutils_socket_buffer_t", + "referenced_type" : "_ZTI22cutils_socket_buffer_t", + "self_type" : "_ZTIK22cutils_socket_buffer_t", + "size" : 16, + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "alignment" : 8, + "is_const" : true, + "linker_set_key" : "_ZTIK5iovec", + "name" : "const iovec", + "referenced_type" : "_ZTI5iovec", + "self_type" : "_ZTIK5iovec", + "size" : 16, + "source_file" : "system/core/libcutils/include/cutils/klog.h" + }, + { + "alignment" : 1, + "is_const" : true, + "linker_set_key" : "_ZTIKc", + "name" : "const char", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIKc", + "size" : 1, + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "is_const" : true, + "linker_set_key" : "_ZTIKv", + "name" : "const void", + "referenced_type" : "_ZTIv", + "self_type" : "_ZTIKv", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + } + ], + "record_types" : + [ + { + "alignment" : 4, + "fields" : + [ + { + "field_name" : "version", + "referenced_type" : "_ZTIi" + }, + { + "field_name" : "numFds", + "field_offset" : 32, + "referenced_type" : "_ZTIi" + }, + { + "field_name" : "numInts", + "field_offset" : 64, + "referenced_type" : "_ZTIi" + }, + { + "field_name" : "data", + "field_offset" : 96, + "referenced_type" : "_ZTIA0_i" + } + ], + "linker_set_key" : "_ZTI13native_handle", + "name" : "native_handle", + "referenced_type" : "_ZTI13native_handle", + "self_type" : "_ZTI13native_handle", + "size" : 12, + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "alignment" : 8, + "fields" : + [ + { + "field_name" : "data", + "referenced_type" : "_ZTIPKv" + }, + { + "field_name" : "length", + "field_offset" : 64, + "referenced_type" : "_ZTIm" + } + ], + "linker_set_key" : "_ZTI22cutils_socket_buffer_t", + "name" : "cutils_socket_buffer_t", + "referenced_type" : "_ZTI22cutils_socket_buffer_t", + "self_type" : "_ZTI22cutils_socket_buffer_t", + "size" : 16, + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "alignment" : 8, + "fields" : + [ + { + "field_name" : "next", + "referenced_type" : "_ZTIP5cnode" + }, + { + "field_name" : "first_child", + "field_offset" : 64, + "referenced_type" : "_ZTIP5cnode" + }, + { + "field_name" : "last_child", + "field_offset" : 128, + "referenced_type" : "_ZTIP5cnode" + }, + { + "field_name" : "name", + "field_offset" : 192, + "referenced_type" : "_ZTIPKc" + }, + { + "field_name" : "value", + "field_offset" : 256, + "referenced_type" : "_ZTIPKc" + } + ], + "linker_set_key" : "_ZTI5cnode", + "name" : "cnode", + "referenced_type" : "_ZTI5cnode", + "self_type" : "_ZTI5cnode", + "size" : 40, + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + } + ], + "rvalue_reference_types" : [] +} diff --git a/libcutils/abi-dumps/arm_arm64/source-based/libcutils.so.lsdump b/libcutils/abi-dumps/arm_arm64/source-based/libcutils.so.lsdump new file mode 100644 index 000000000000..f612fb9420a4 --- /dev/null +++ b/libcutils/abi-dumps/arm_arm64/source-based/libcutils.so.lsdump @@ -0,0 +1,2700 @@ +{ + "array_types" : + [ + { + "alignment" : 4, + "linker_set_key" : "_ZTIA0_i", + "name" : "int[0]", + "referenced_type" : "_ZTIi", + "self_type" : "_ZTIA0_i", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + } + ], + "builtin_types" : + [ + { + "alignment" : 1, + "is_integral" : true, + "linker_set_key" : "_ZTIa", + "name" : "signed char", + "referenced_type" : "_ZTIa", + "self_type" : "_ZTIa", + "size" : 1 + }, + { + "alignment" : 1, + "is_integral" : true, + "is_unsigned" : true, + "linker_set_key" : "_ZTIb", + "name" : "bool", + "referenced_type" : "_ZTIb", + "self_type" : "_ZTIb", + "size" : 1 + }, + { + "alignment" : 1, + "is_integral" : true, + "is_unsigned" : true, + "linker_set_key" : "_ZTIc", + "name" : "char", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIc", + "size" : 1 + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIf", + "name" : "float", + "referenced_type" : "_ZTIf", + "self_type" : "_ZTIf", + "size" : 4 + }, + { + "alignment" : 4, + "is_integral" : true, + "linker_set_key" : "_ZTIi", + "name" : "int", + "referenced_type" : "_ZTIi", + "self_type" : "_ZTIi", + "size" : 4 + }, + { + "alignment" : 4, + "is_integral" : true, + "is_unsigned" : true, + "linker_set_key" : "_ZTIj", + "name" : "unsigned int", + "referenced_type" : "_ZTIj", + "self_type" : "_ZTIj", + "size" : 4 + }, + { + "alignment" : 2, + "is_integral" : true, + "is_unsigned" : true, + "linker_set_key" : "_ZTIt", + "name" : "unsigned short", + "referenced_type" : "_ZTIt", + "self_type" : "_ZTIt", + "size" : 2 + }, + { + "linker_set_key" : "_ZTIv", + "name" : "void", + "referenced_type" : "_ZTIv", + "self_type" : "_ZTIv" + }, + { + "alignment" : 8, + "is_integral" : true, + "linker_set_key" : "_ZTIx", + "name" : "long long", + "referenced_type" : "_ZTIx", + "self_type" : "_ZTIx", + "size" : 8 + }, + { + "alignment" : 8, + "is_integral" : true, + "is_unsigned" : true, + "linker_set_key" : "_ZTIy", + "name" : "unsigned long long", + "referenced_type" : "_ZTIy", + "self_type" : "_ZTIy", + "size" : 8 + } + ], + "elf_functions" : + [ + { + "name" : "_Z23socket_make_sockaddr_unPKciP11sockaddr_unPi" + }, + { + "binding" : "weak", + "name" : "_ZN7android4base4TrimIRNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEES8_OT_" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE4syncEv" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE5imbueERKNS_6localeE" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE6setbufEPci" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE7seekoffExNS_8ios_base7seekdirEj" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE7seekposENS_4fposI9mbstate_tEEj" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE8overflowEi" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE9pbackfailEi" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE9underflowEv" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEEC2Ev" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEED0Ev" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEED2Ev" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_j" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__16vectorI5EntryNS_9allocatorIS1_EEE24__emplace_back_slow_pathIJS1_EEEvDpOT_" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__17getlineIcNS_11char_traitsIcEENS_9allocatorIcEEEERNS_13basic_istreamIT_T0_EES9_RNS_12basic_stringIS6_S7_T1_EES6_" + }, + { + "binding" : "weak", + "name" : "_ZNSt3__1lsINS_11char_traitsIcEEEERNS_13basic_ostreamIcT_EES6_PKc" + }, + { + "name" : "android_get_control_file" + }, + { + "name" : "android_get_control_socket" + }, + { + "name" : "android_get_ioprio" + }, + { + "name" : "android_reboot" + }, + { + "name" : "android_set_ioprio" + }, + { + "name" : "ashmem_create_region" + }, + { + "name" : "ashmem_get_size_region" + }, + { + "name" : "ashmem_pin_region" + }, + { + "name" : "ashmem_set_prot_region" + }, + { + "name" : "ashmem_unpin_region" + }, + { + "name" : "ashmem_valid" + }, + { + "name" : "atrace_async_begin_body" + }, + { + "name" : "atrace_async_end_body" + }, + { + "name" : "atrace_async_for_track_begin_body" + }, + { + "name" : "atrace_async_for_track_end_body" + }, + { + "name" : "atrace_begin_body" + }, + { + "name" : "atrace_end_body" + }, + { + "name" : "atrace_get_enabled_tags" + }, + { + "name" : "atrace_init" + }, + { + "name" : "atrace_instant_body" + }, + { + "name" : "atrace_instant_for_track_body" + }, + { + "name" : "atrace_int64_body" + }, + { + "name" : "atrace_int_body" + }, + { + "name" : "atrace_set_tracing_enabled" + }, + { + "name" : "atrace_setup" + }, + { + "name" : "atrace_update_tags" + }, + { + "name" : "canned_fs_config" + }, + { + "name" : "config_bool" + }, + { + "name" : "config_find" + }, + { + "name" : "config_free" + }, + { + "name" : "config_load" + }, + { + "name" : "config_load_file" + }, + { + "name" : "config_node" + }, + { + "name" : "config_set" + }, + { + "name" : "config_str" + }, + { + "name" : "fs_config" + }, + { + "name" : "fs_mkdirs" + }, + { + "name" : "fs_prepare_dir" + }, + { + "name" : "fs_prepare_dir_strict" + }, + { + "name" : "fs_prepare_file_strict" + }, + { + "name" : "fs_read_atomic_int" + }, + { + "name" : "fs_write_atomic_int" + }, + { + "name" : "hashmapCreate" + }, + { + "name" : "hashmapForEach" + }, + { + "name" : "hashmapFree" + }, + { + "name" : "hashmapGet" + }, + { + "name" : "hashmapHash" + }, + { + "name" : "hashmapLock" + }, + { + "name" : "hashmapPut" + }, + { + "name" : "hashmapRemove" + }, + { + "name" : "hashmapUnlock" + }, + { + "name" : "klog_set_level" + }, + { + "name" : "klog_write" + }, + { + "name" : "klog_writev" + }, + { + "name" : "load_canned_fs_config" + }, + { + "name" : "load_file" + }, + { + "name" : "multiuser_convert_sdk_sandbox_to_app_uid" + }, + { + "name" : "multiuser_get_app_id" + }, + { + "name" : "multiuser_get_cache_gid" + }, + { + "name" : "multiuser_get_ext_cache_gid" + }, + { + "name" : "multiuser_get_ext_gid" + }, + { + "name" : "multiuser_get_sdk_sandbox_uid" + }, + { + "name" : "multiuser_get_shared_app_gid" + }, + { + "name" : "multiuser_get_shared_gid" + }, + { + "name" : "multiuser_get_uid" + }, + { + "name" : "multiuser_get_user_id" + }, + { + "name" : "native_handle_clone" + }, + { + "name" : "native_handle_close" + }, + { + "name" : "native_handle_close_with_tag" + }, + { + "name" : "native_handle_create" + }, + { + "name" : "native_handle_delete" + }, + { + "name" : "native_handle_init" + }, + { + "name" : "native_handle_set_fdsan_tag" + }, + { + "name" : "native_handle_unset_fdsan_tag" + }, + { + "name" : "partition_wiped" + }, + { + "name" : "property_get" + }, + { + "name" : "property_get_bool" + }, + { + "name" : "property_get_int32" + }, + { + "name" : "property_get_int64" + }, + { + "name" : "property_list" + }, + { + "name" : "property_set" + }, + { + "name" : "record_stream_free" + }, + { + "name" : "record_stream_get_next" + }, + { + "name" : "record_stream_new" + }, + { + "name" : "socket_close" + }, + { + "name" : "socket_get_local_port" + }, + { + "name" : "socket_inaddr_any_server" + }, + { + "name" : "socket_local_client" + }, + { + "name" : "socket_local_client_connect" + }, + { + "name" : "socket_local_server" + }, + { + "name" : "socket_local_server_bind" + }, + { + "name" : "socket_network_client" + }, + { + "name" : "socket_network_client_timeout" + }, + { + "name" : "socket_send_buffers" + }, + { + "name" : "str_parms_add_float" + }, + { + "name" : "str_parms_add_int" + }, + { + "name" : "str_parms_add_str" + }, + { + "name" : "str_parms_create" + }, + { + "name" : "str_parms_create_str" + }, + { + "name" : "str_parms_del" + }, + { + "name" : "str_parms_destroy" + }, + { + "name" : "str_parms_dump" + }, + { + "name" : "str_parms_get_float" + }, + { + "name" : "str_parms_get_int" + }, + { + "name" : "str_parms_get_str" + }, + { + "name" : "str_parms_has_key" + }, + { + "name" : "str_parms_to_str" + }, + { + "name" : "uevent_kernel_multicast_recv" + }, + { + "name" : "uevent_kernel_multicast_uid_recv" + }, + { + "name" : "uevent_kernel_recv" + }, + { + "name" : "uevent_open_socket" + } + ], + "elf_objects" : + [ + { + "binding" : "weak", + "name" : "_ZTCNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE0_NS_13basic_istreamIcS2_EE" + }, + { + "binding" : "weak", + "name" : "_ZTTNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE" + }, + { + "binding" : "weak", + "name" : "_ZTVNSt3__113basic_filebufIcNS_11char_traitsIcEEEE" + }, + { + "binding" : "weak", + "name" : "_ZTVNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE" + }, + { + "name" : "atrace_enabled_tags" + }, + { + "name" : "atrace_is_ready" + }, + { + "name" : "atrace_marker_fd" + } + ], + "enum_types" : + [ + { + "alignment" : 4, + "enum_fields" : + [ + { + "enum_field_value" : 0, + "name" : "IoSchedClass_NONE" + }, + { + "enum_field_value" : 1, + "name" : "IoSchedClass_RT" + }, + { + "enum_field_value" : 2, + "name" : "IoSchedClass_BE" + }, + { + "enum_field_value" : 3, + "name" : "IoSchedClass_IDLE" + } + ], + "linker_set_key" : "_ZTI12IoSchedClass", + "name" : "IoSchedClass", + "referenced_type" : "_ZTI12IoSchedClass", + "self_type" : "_ZTI12IoSchedClass", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h", + "underlying_type" : "_ZTIj" + } + ], + "function_types" : + [ + { + "alignment" : 4, + "linker_set_key" : "_ZTIFbPvS_E", + "name" : "bool (void *, void *)", + "parameters" : + [ + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "referenced_type" : "_ZTIFbPvS_E", + "return_type" : "_ZTIb", + "self_type" : "_ZTIFbPvS_E", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIFbPvS_S_E", + "name" : "bool (void *, void *, void *)", + "parameters" : + [ + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "referenced_type" : "_ZTIFbPvS_S_E", + "return_type" : "_ZTIb", + "self_type" : "_ZTIFbPvS_S_E", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIFiPvE", + "name" : "int (void *)", + "parameters" : + [ + { + "referenced_type" : "_ZTIPv" + } + ], + "referenced_type" : "_ZTIFiPvE", + "return_type" : "_ZTIi", + "self_type" : "_ZTIFiPvE", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIFvPKcS0_PvE", + "name" : "void (const char *, const char *, void *)", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "referenced_type" : "_ZTIFvPKcS0_PvE", + "return_type" : "_ZTIv", + "self_type" : "_ZTIFvPKcS0_PvE", + "source_file" : "system/core/libcutils/include/cutils/properties.h" + } + ], + "functions" : + [ + { + "function_name" : "android_get_control_file", + "linker_set_key" : "android_get_control_file", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/android_get_control_file.h" + }, + { + "function_name" : "android_get_control_socket", + "linker_set_key" : "android_get_control_socket", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "android_get_ioprio", + "linker_set_key" : "android_get_ioprio", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIP12IoSchedClass" + }, + { + "referenced_type" : "_ZTIPi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h" + }, + { + "function_name" : "android_reboot", + "linker_set_key" : "android_reboot", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/android_reboot.h" + }, + { + "function_name" : "android_set_ioprio", + "linker_set_key" : "android_set_ioprio", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTI12IoSchedClass" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h" + }, + { + "function_name" : "ashmem_create_region", + "linker_set_key" : "ashmem_create_region", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/ashmem.h" + }, + { + "function_name" : "ashmem_get_size_region", + "linker_set_key" : "ashmem_get_size_region", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/ashmem.h" + }, + { + "function_name" : "ashmem_pin_region", + "linker_set_key" : "ashmem_pin_region", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/ashmem.h" + }, + { + "function_name" : "ashmem_set_prot_region", + "linker_set_key" : "ashmem_set_prot_region", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/ashmem.h" + }, + { + "function_name" : "ashmem_unpin_region", + "linker_set_key" : "ashmem_unpin_region", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/ashmem.h" + }, + { + "function_name" : "ashmem_valid", + "linker_set_key" : "ashmem_valid", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/ashmem.h" + }, + { + "function_name" : "atrace_async_begin_body", + "linker_set_key" : "atrace_async_begin_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_async_end_body", + "linker_set_key" : "atrace_async_end_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_async_for_track_begin_body", + "linker_set_key" : "atrace_async_for_track_begin_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_async_for_track_end_body", + "linker_set_key" : "atrace_async_for_track_end_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_begin_body", + "linker_set_key" : "atrace_begin_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_end_body", + "linker_set_key" : "atrace_end_body", + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_get_enabled_tags", + "linker_set_key" : "atrace_get_enabled_tags", + "return_type" : "_ZTIy", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_init", + "linker_set_key" : "atrace_init", + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_instant_body", + "linker_set_key" : "atrace_instant_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_instant_for_track_body", + "linker_set_key" : "atrace_instant_for_track_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_int64_body", + "linker_set_key" : "atrace_int64_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIx" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_int_body", + "linker_set_key" : "atrace_int_body", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_set_tracing_enabled", + "linker_set_key" : "atrace_set_tracing_enabled", + "parameters" : + [ + { + "referenced_type" : "_ZTIb" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_setup", + "linker_set_key" : "atrace_setup", + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "atrace_update_tags", + "linker_set_key" : "atrace_update_tags", + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "function_name" : "canned_fs_config", + "linker_set_key" : "canned_fs_config", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPj" + }, + { + "referenced_type" : "_ZTIPj" + }, + { + "referenced_type" : "_ZTIPj" + }, + { + "referenced_type" : "_ZTIPy" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/private/canned_fs_config.h" + }, + { + "function_name" : "config_bool", + "linker_set_key" : "config_bool", + "parameters" : + [ + { + "referenced_type" : "_ZTIP5cnode" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "config_find", + "linker_set_key" : "config_find", + "parameters" : + [ + { + "referenced_type" : "_ZTIP5cnode" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIP5cnode", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "config_free", + "linker_set_key" : "config_free", + "parameters" : + [ + { + "referenced_type" : "_ZTIP5cnode" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "config_load", + "linker_set_key" : "config_load", + "parameters" : + [ + { + "referenced_type" : "_ZTIP5cnode" + }, + { + "referenced_type" : "_ZTIPc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "config_load_file", + "linker_set_key" : "config_load_file", + "parameters" : + [ + { + "referenced_type" : "_ZTIP5cnode" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "config_node", + "linker_set_key" : "config_node", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIP5cnode", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "config_set", + "linker_set_key" : "config_set", + "parameters" : + [ + { + "referenced_type" : "_ZTIP5cnode" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "config_str", + "linker_set_key" : "config_str", + "parameters" : + [ + { + "referenced_type" : "_ZTIP5cnode" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIPKc", + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "function_name" : "fs_config", + "linker_set_key" : "fs_config", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPj" + }, + { + "referenced_type" : "_ZTIPj" + }, + { + "referenced_type" : "_ZTIPj" + }, + { + "referenced_type" : "_ZTIPy" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/private/fs_config.h" + }, + { + "function_name" : "fs_mkdirs", + "linker_set_key" : "fs_mkdirs", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIt" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/fs.h" + }, + { + "function_name" : "fs_prepare_dir", + "linker_set_key" : "fs_prepare_dir", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIt" + }, + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/fs.h" + }, + { + "function_name" : "fs_prepare_dir_strict", + "linker_set_key" : "fs_prepare_dir_strict", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIt" + }, + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/fs.h" + }, + { + "function_name" : "fs_prepare_file_strict", + "linker_set_key" : "fs_prepare_file_strict", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIt" + }, + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/fs.h" + }, + { + "function_name" : "fs_read_atomic_int", + "linker_set_key" : "fs_read_atomic_int", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/fs.h" + }, + { + "function_name" : "fs_write_atomic_int", + "linker_set_key" : "fs_write_atomic_int", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/fs.h" + }, + { + "function_name" : "hashmapCreate", + "linker_set_key" : "hashmapCreate", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIPFiPvE" + }, + { + "referenced_type" : "_ZTIPFbPvS_E" + } + ], + "return_type" : "_ZTIP7Hashmap", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapForEach", + "linker_set_key" : "hashmapForEach", + "parameters" : + [ + { + "referenced_type" : "_ZTIP7Hashmap" + }, + { + "referenced_type" : "_ZTIPFbPvS_S_E" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapFree", + "linker_set_key" : "hashmapFree", + "parameters" : + [ + { + "referenced_type" : "_ZTIP7Hashmap" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapGet", + "linker_set_key" : "hashmapGet", + "parameters" : + [ + { + "referenced_type" : "_ZTIP7Hashmap" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "return_type" : "_ZTIPv", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapHash", + "linker_set_key" : "hashmapHash", + "parameters" : + [ + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapLock", + "linker_set_key" : "hashmapLock", + "parameters" : + [ + { + "referenced_type" : "_ZTIP7Hashmap" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapPut", + "linker_set_key" : "hashmapPut", + "parameters" : + [ + { + "referenced_type" : "_ZTIP7Hashmap" + }, + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "return_type" : "_ZTIPv", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapRemove", + "linker_set_key" : "hashmapRemove", + "parameters" : + [ + { + "referenced_type" : "_ZTIP7Hashmap" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "return_type" : "_ZTIPv", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "hashmapUnlock", + "linker_set_key" : "hashmapUnlock", + "parameters" : + [ + { + "referenced_type" : "_ZTIP7Hashmap" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "function_name" : "klog_set_level", + "linker_set_key" : "klog_set_level", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/klog.h" + }, + { + "function_name" : "klog_write", + "linker_set_key" : "klog_write", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/klog.h" + }, + { + "function_name" : "klog_writev", + "linker_set_key" : "klog_writev", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPK5iovec" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/klog.h" + }, + { + "function_name" : "load_canned_fs_config", + "linker_set_key" : "load_canned_fs_config", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/private/canned_fs_config.h" + }, + { + "function_name" : "load_file", + "linker_set_key" : "load_file", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPj" + } + ], + "return_type" : "_ZTIPv", + "source_file" : "system/core/libcutils/include/cutils/misc.h" + }, + { + "function_name" : "multiuser_convert_sdk_sandbox_to_app_uid", + "linker_set_key" : "multiuser_convert_sdk_sandbox_to_app_uid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_app_id", + "linker_set_key" : "multiuser_get_app_id", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_cache_gid", + "linker_set_key" : "multiuser_get_cache_gid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_ext_cache_gid", + "linker_set_key" : "multiuser_get_ext_cache_gid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_ext_gid", + "linker_set_key" : "multiuser_get_ext_gid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_sdk_sandbox_uid", + "linker_set_key" : "multiuser_get_sdk_sandbox_uid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_shared_app_gid", + "linker_set_key" : "multiuser_get_shared_app_gid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_shared_gid", + "linker_set_key" : "multiuser_get_shared_gid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_uid", + "linker_set_key" : "multiuser_get_uid", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "multiuser_get_user_id", + "linker_set_key" : "multiuser_get_user_id", + "parameters" : + [ + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIj", + "source_file" : "system/core/libcutils/include/cutils/multiuser.h" + }, + { + "function_name" : "native_handle_clone", + "linker_set_key" : "native_handle_clone", + "parameters" : + [ + { + "referenced_type" : "_ZTIPK13native_handle" + } + ], + "return_type" : "_ZTIP13native_handle", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "native_handle_close", + "linker_set_key" : "native_handle_close", + "parameters" : + [ + { + "referenced_type" : "_ZTIPK13native_handle" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "native_handle_close_with_tag", + "linker_set_key" : "native_handle_close_with_tag", + "parameters" : + [ + { + "referenced_type" : "_ZTIPK13native_handle" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "native_handle_create", + "linker_set_key" : "native_handle_create", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIP13native_handle", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "native_handle_delete", + "linker_set_key" : "native_handle_delete", + "parameters" : + [ + { + "referenced_type" : "_ZTIP13native_handle" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "native_handle_init", + "linker_set_key" : "native_handle_init", + "parameters" : + [ + { + "referenced_type" : "_ZTIPc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIP13native_handle", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "native_handle_set_fdsan_tag", + "linker_set_key" : "native_handle_set_fdsan_tag", + "parameters" : + [ + { + "referenced_type" : "_ZTIPK13native_handle" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "native_handle_unset_fdsan_tag", + "linker_set_key" : "native_handle_unset_fdsan_tag", + "parameters" : + [ + { + "referenced_type" : "_ZTIPK13native_handle" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "function_name" : "partition_wiped", + "linker_set_key" : "partition_wiped", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/partition_utils.h" + }, + { + "function_name" : "property_get", + "linker_set_key" : "property_get", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPc" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/properties.h" + }, + { + "function_name" : "property_get_bool", + "linker_set_key" : "property_get_bool", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIa" + } + ], + "return_type" : "_ZTIa", + "source_file" : "system/core/libcutils/include/cutils/properties.h" + }, + { + "function_name" : "property_get_int32", + "linker_set_key" : "property_get_int32", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/properties.h" + }, + { + "function_name" : "property_get_int64", + "linker_set_key" : "property_get_int64", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIx" + } + ], + "return_type" : "_ZTIx", + "source_file" : "system/core/libcutils/include/cutils/properties.h" + }, + { + "function_name" : "property_list", + "linker_set_key" : "property_list", + "parameters" : + [ + { + "referenced_type" : "_ZTIPFvPKcS0_PvE" + }, + { + "referenced_type" : "_ZTIPv" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/properties.h" + }, + { + "function_name" : "property_set", + "linker_set_key" : "property_set", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/properties.h" + }, + { + "function_name" : "record_stream_free", + "linker_set_key" : "record_stream_free", + "parameters" : + [ + { + "referenced_type" : "_ZTIP12RecordStream" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/record_stream.h" + }, + { + "function_name" : "record_stream_get_next", + "linker_set_key" : "record_stream_get_next", + "parameters" : + [ + { + "referenced_type" : "_ZTIP12RecordStream" + }, + { + "referenced_type" : "_ZTIPPv" + }, + { + "referenced_type" : "_ZTIPj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/record_stream.h" + }, + { + "function_name" : "record_stream_new", + "linker_set_key" : "record_stream_new", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIP12RecordStream", + "source_file" : "system/core/libcutils/include/cutils/record_stream.h" + }, + { + "function_name" : "socket_close", + "linker_set_key" : "socket_close", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_get_local_port", + "linker_set_key" : "socket_get_local_port", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_inaddr_any_server", + "linker_set_key" : "socket_inaddr_any_server", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_local_client", + "linker_set_key" : "socket_local_client", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_local_client_connect", + "linker_set_key" : "socket_local_client_connect", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_local_server", + "linker_set_key" : "socket_local_server", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_local_server_bind", + "linker_set_key" : "socket_local_server_bind", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_network_client", + "linker_set_key" : "socket_network_client", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_network_client_timeout", + "linker_set_key" : "socket_network_client_timeout", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "socket_send_buffers", + "linker_set_key" : "socket_send_buffers", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPK22cutils_socket_buffer_t" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "function_name" : "str_parms_add_float", + "linker_set_key" : "str_parms_add_float", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIf" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_add_int", + "linker_set_key" : "str_parms_add_int", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_add_str", + "linker_set_key" : "str_parms_add_str", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_create", + "linker_set_key" : "str_parms_create", + "return_type" : "_ZTIP9str_parms", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_create_str", + "linker_set_key" : "str_parms_create_str", + "parameters" : + [ + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIP9str_parms", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_del", + "linker_set_key" : "str_parms_del", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_destroy", + "linker_set_key" : "str_parms_destroy", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_dump", + "linker_set_key" : "str_parms_dump", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + } + ], + "return_type" : "_ZTIv", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_get_float", + "linker_set_key" : "str_parms_get_float", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPf" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_get_int", + "linker_set_key" : "str_parms_get_int", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_get_str", + "linker_set_key" : "str_parms_get_str", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + }, + { + "referenced_type" : "_ZTIPc" + }, + { + "referenced_type" : "_ZTIi" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_has_key", + "linker_set_key" : "str_parms_has_key", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "str_parms_to_str", + "linker_set_key" : "str_parms_to_str", + "parameters" : + [ + { + "referenced_type" : "_ZTIP9str_parms" + } + ], + "return_type" : "_ZTIPc", + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "function_name" : "uevent_kernel_multicast_recv", + "linker_set_key" : "uevent_kernel_multicast_recv", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/uevent.h" + }, + { + "function_name" : "uevent_kernel_multicast_uid_recv", + "linker_set_key" : "uevent_kernel_multicast_uid_recv", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIPj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/uevent.h" + }, + { + "function_name" : "uevent_kernel_recv", + "linker_set_key" : "uevent_kernel_recv", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIPv" + }, + { + "referenced_type" : "_ZTIj" + }, + { + "referenced_type" : "_ZTIb" + }, + { + "referenced_type" : "_ZTIPj" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/uevent.h" + }, + { + "function_name" : "uevent_open_socket", + "linker_set_key" : "uevent_open_socket", + "parameters" : + [ + { + "referenced_type" : "_ZTIi" + }, + { + "referenced_type" : "_ZTIb" + } + ], + "return_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/uevent.h" + } + ], + "global_vars" : + [ + { + "linker_set_key" : "atrace_enabled_tags", + "name" : "atrace_enabled_tags", + "referenced_type" : "_ZTIy", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "linker_set_key" : "atrace_is_ready", + "name" : "atrace_is_ready", + "referenced_type" : "_ZTINSt3__16atomicIbEE", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + }, + { + "linker_set_key" : "atrace_marker_fd", + "name" : "atrace_marker_fd", + "referenced_type" : "_ZTIi", + "source_file" : "system/core/libcutils/include/cutils/trace.h" + } + ], + "lvalue_reference_types" : [], + "pointer_types" : + [ + { + "alignment" : 4, + "linker_set_key" : "_ZTIP12IoSchedClass", + "name" : "IoSchedClass *", + "referenced_type" : "_ZTI12IoSchedClass", + "self_type" : "_ZTIP12IoSchedClass", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIP12RecordStream", + "name" : "RecordStream *", + "referenced_type" : "_ZTI12RecordStream", + "self_type" : "_ZTIP12RecordStream", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/record_stream.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIP13native_handle", + "name" : "native_handle *", + "referenced_type" : "_ZTI13native_handle", + "self_type" : "_ZTIP13native_handle", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIP5cnode", + "name" : "cnode *", + "referenced_type" : "_ZTI5cnode", + "self_type" : "_ZTIP5cnode", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIP7Hashmap", + "name" : "Hashmap *", + "referenced_type" : "_ZTI7Hashmap", + "self_type" : "_ZTIP7Hashmap", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIP9str_parms", + "name" : "str_parms *", + "referenced_type" : "_ZTI9str_parms", + "self_type" : "_ZTIP9str_parms", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPFbPvS_E", + "name" : "bool (*)(void *, void *)", + "referenced_type" : "_ZTIFbPvS_E", + "self_type" : "_ZTIPFbPvS_E", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPFbPvS_S_E", + "name" : "bool (*)(void *, void *, void *)", + "referenced_type" : "_ZTIFbPvS_S_E", + "self_type" : "_ZTIPFbPvS_S_E", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPFiPvE", + "name" : "int (*)(void *)", + "referenced_type" : "_ZTIFiPvE", + "self_type" : "_ZTIPFiPvE", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/hashmap.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPFvPKcS0_PvE", + "name" : "void (*)(const char *, const char *, void *)", + "referenced_type" : "_ZTIFvPKcS0_PvE", + "self_type" : "_ZTIPFvPKcS0_PvE", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/properties.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPK13native_handle", + "name" : "const native_handle *", + "referenced_type" : "_ZTIK13native_handle", + "self_type" : "_ZTIPK13native_handle", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPK22cutils_socket_buffer_t", + "name" : "const cutils_socket_buffer_t *", + "referenced_type" : "_ZTIK22cutils_socket_buffer_t", + "self_type" : "_ZTIPK22cutils_socket_buffer_t", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPK5iovec", + "name" : "const iovec *", + "referenced_type" : "_ZTIK5iovec", + "self_type" : "_ZTIPK5iovec", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/klog.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPKc", + "name" : "const char *", + "referenced_type" : "_ZTIKc", + "self_type" : "_ZTIPKc", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPKv", + "name" : "const void *", + "referenced_type" : "_ZTIKv", + "self_type" : "_ZTIPKv", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPPv", + "name" : "void **", + "referenced_type" : "_ZTIPv", + "self_type" : "_ZTIPPv", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/record_stream.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPc", + "name" : "char *", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIPc", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPf", + "name" : "float *", + "referenced_type" : "_ZTIf", + "self_type" : "_ZTIPf", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/str_parms.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPi", + "name" : "int *", + "referenced_type" : "_ZTIi", + "self_type" : "_ZTIPi", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPj", + "name" : "unsigned int *", + "referenced_type" : "_ZTIj", + "self_type" : "_ZTIPj", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/misc.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPv", + "name" : "void *", + "referenced_type" : "_ZTIv", + "self_type" : "_ZTIPv", + "size" : 4, + "source_file" : "system/core/libcutils/include/cutils/misc.h" + }, + { + "alignment" : 4, + "linker_set_key" : "_ZTIPy", + "name" : "unsigned long long *", + "referenced_type" : "_ZTIy", + "self_type" : "_ZTIPy", + "size" : 4, + "source_file" : "system/core/libcutils/include/private/canned_fs_config.h" + } + ], + "qualified_types" : + [ + { + "alignment" : 4, + "is_const" : true, + "linker_set_key" : "_ZTIK13native_handle", + "name" : "const native_handle", + "referenced_type" : "_ZTI13native_handle", + "self_type" : "_ZTIK13native_handle", + "size" : 12, + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "alignment" : 4, + "is_const" : true, + "linker_set_key" : "_ZTIK22cutils_socket_buffer_t", + "name" : "const cutils_socket_buffer_t", + "referenced_type" : "_ZTI22cutils_socket_buffer_t", + "self_type" : "_ZTIK22cutils_socket_buffer_t", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "alignment" : 4, + "is_const" : true, + "linker_set_key" : "_ZTIK5iovec", + "name" : "const iovec", + "referenced_type" : "_ZTI5iovec", + "self_type" : "_ZTIK5iovec", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/klog.h" + }, + { + "alignment" : 1, + "is_const" : true, + "linker_set_key" : "_ZTIKc", + "name" : "const char", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIKc", + "size" : 1, + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + }, + { + "is_const" : true, + "linker_set_key" : "_ZTIKv", + "name" : "const void", + "referenced_type" : "_ZTIv", + "self_type" : "_ZTIKv", + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + } + ], + "record_types" : + [ + { + "alignment" : 4, + "fields" : + [ + { + "field_name" : "version", + "referenced_type" : "_ZTIi" + }, + { + "field_name" : "numFds", + "field_offset" : 32, + "referenced_type" : "_ZTIi" + }, + { + "field_name" : "numInts", + "field_offset" : 64, + "referenced_type" : "_ZTIi" + }, + { + "field_name" : "data", + "field_offset" : 96, + "referenced_type" : "_ZTIA0_i" + } + ], + "linker_set_key" : "_ZTI13native_handle", + "name" : "native_handle", + "referenced_type" : "_ZTI13native_handle", + "self_type" : "_ZTI13native_handle", + "size" : 12, + "source_file" : "system/core/libcutils/include/cutils/native_handle.h" + }, + { + "alignment" : 4, + "fields" : + [ + { + "field_name" : "data", + "referenced_type" : "_ZTIPKv" + }, + { + "field_name" : "length", + "field_offset" : 32, + "referenced_type" : "_ZTIj" + } + ], + "linker_set_key" : "_ZTI22cutils_socket_buffer_t", + "name" : "cutils_socket_buffer_t", + "referenced_type" : "_ZTI22cutils_socket_buffer_t", + "self_type" : "_ZTI22cutils_socket_buffer_t", + "size" : 8, + "source_file" : "system/core/libcutils/include/cutils/sockets.h" + }, + { + "alignment" : 4, + "fields" : + [ + { + "field_name" : "next", + "referenced_type" : "_ZTIP5cnode" + }, + { + "field_name" : "first_child", + "field_offset" : 32, + "referenced_type" : "_ZTIP5cnode" + }, + { + "field_name" : "last_child", + "field_offset" : 64, + "referenced_type" : "_ZTIP5cnode" + }, + { + "field_name" : "name", + "field_offset" : 96, + "referenced_type" : "_ZTIPKc" + }, + { + "field_name" : "value", + "field_offset" : 128, + "referenced_type" : "_ZTIPKc" + } + ], + "linker_set_key" : "_ZTI5cnode", + "name" : "cnode", + "referenced_type" : "_ZTI5cnode", + "self_type" : "_ZTI5cnode", + "size" : 20, + "source_file" : "system/core/libcutils/include/cutils/config_utils.h" + } + ], + "rvalue_reference_types" : [] +} From 54b86e7b7a3645cc7de6fef642ba76a805beff37 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Thu, 13 Jul 2023 17:33:50 +0900 Subject: [PATCH 0185/1487] Workaround for Global ThinLTO Global string literals are not initialized correctly with the new config. This change is a workaround by changing them into plain C literals until we have a better solution. Bug: 291033685 Test: adb-remount-test.sh Change-Id: I178286133f55ff5dc11030fa132a9e6db0747ae7 --- fs_mgr/fs_mgr_overlayfs.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index 01827d6cc576..82a8b8b233c9 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -75,8 +75,8 @@ bool fs_mgr_access(const std::string& path) { return access(path.c_str(), F_OK) == 0; } -const auto kLowerdirOption = "lowerdir="s; -const auto kUpperdirOption = "upperdir="s; +const auto kLowerdirOption = "lowerdir="; +const auto kUpperdirOption = "upperdir="; bool fs_mgr_in_recovery() { // Check the existence of recovery binary instead of using the compile time @@ -99,8 +99,8 @@ bool fs_mgr_is_dsu_running() { } // list of acceptable overlayfs backing storage -const auto kScratchMountPoint = "/mnt/scratch"s; -const auto kCacheMountPoint = "/cache"s; +const auto kScratchMountPoint = "/mnt/scratch"; +const auto kCacheMountPoint = "/cache"; bool IsABDevice() { return !android::base::GetProperty("ro.boot.slot_suffix", "").empty(); @@ -158,7 +158,7 @@ bool fs_mgr_filesystem_has_space(const std::string& mount_point) { (static_cast(vst.f_bfree) * vst.f_frsize) >= kSizeThreshold; } -const auto kPhysicalDevice = "/dev/block/by-name/"s; +const auto kPhysicalDevice = "/dev/block/by-name/"; constexpr char kScratchImageMetadata[] = "/metadata/gsi/remount/lp_metadata"; // Note: this is meant only for recovery/first-stage init. @@ -182,7 +182,7 @@ bool fs_mgr_update_blk_device(FstabEntry* entry) { } // special case for system-as-root (taimen and others) - auto blk_device = kPhysicalDevice + "system"; + auto blk_device = std::string(kPhysicalDevice) + "system"; if (!fs_mgr_access(blk_device)) { blk_device += fs_mgr_get_slot_suffix(); if (!fs_mgr_access(blk_device)) { @@ -301,9 +301,9 @@ bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int level = return ret; } -const auto kUpperName = "upper"s; -const auto kWorkName = "work"s; -const auto kOverlayTopDir = "/overlay"s; +const auto kUpperName = "upper"; +const auto kWorkName = "work"; +const auto kOverlayTopDir = "/overlay"; std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point) { if (!fs_mgr_is_dir(mount_point)) return ""; @@ -472,10 +472,10 @@ bool fs_mgr_overlayfs_has_logical(const Fstab& fstab) { // Returns true if immediate unmount succeeded and the scratch mount point was // removed. bool fs_mgr_overlayfs_umount_scratch() { - if (umount(kScratchMountPoint.c_str()) != 0) { + if (umount(kScratchMountPoint) != 0) { return false; } - if (rmdir(kScratchMountPoint.c_str()) != 0 && errno != ENOENT) { + if (rmdir(kScratchMountPoint) != 0 && errno != ENOENT) { PLOG(ERROR) << "rmdir " << kScratchMountPoint; } return true; @@ -573,7 +573,7 @@ bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string auto cleanup_all = mount_point.empty(); const auto partition_name = android::base::Basename(mount_point); const auto oldpath = top + (cleanup_all ? "" : ("/" + partition_name)); - const auto newpath = cleanup_all ? overlay + "/." + kOverlayTopDir.substr(1) + ".teardown" + const auto newpath = cleanup_all ? overlay + "/." + (kOverlayTopDir + 1) + ".teardown" : top + "/." + partition_name + ".teardown"; auto ret = fs_mgr_rm_all(newpath); if (!rename(oldpath.c_str(), newpath.c_str())) { @@ -853,7 +853,7 @@ bool MountScratch(const std::string& device_path, bool readonly = false) { if (!createcon.Ok()) { return false; } - if (mkdir(kScratchMountPoint.c_str(), 0755) && (errno != EEXIST)) { + if (mkdir(kScratchMountPoint, 0755) && (errno != EEXIST)) { PERROR << "create " << kScratchMountPoint; return false; } @@ -884,7 +884,7 @@ bool MountScratch(const std::string& device_path, bool readonly = false) { return false; } if (!mounted) { - rmdir(kScratchMountPoint.c_str()); + rmdir(kScratchMountPoint); return false; } return true; @@ -1192,7 +1192,7 @@ bool fs_mgr_overlayfs_setup_scratch(const Fstab& fstab) { // If the partition exists, assume first that it can be mounted. if (partition_exists) { if (MountScratch(scratch_device)) { - if (fs_mgr_access(kScratchMountPoint + kOverlayTopDir) || + if (fs_mgr_access(std::string(kScratchMountPoint) + kOverlayTopDir) || fs_mgr_filesystem_has_space(kScratchMountPoint)) { return true; } @@ -1331,7 +1331,7 @@ static void TryMountScratch() { if (!MountScratch(scratch_device, true /* readonly */)) { return; } - auto has_overlayfs_dir = fs_mgr_access(kScratchMountPoint + kOverlayTopDir); + auto has_overlayfs_dir = fs_mgr_access(std::string(kScratchMountPoint) + kOverlayTopDir); fs_mgr_overlayfs_umount_scratch(); if (has_overlayfs_dir) { MountScratch(scratch_device); From c28150f56f47d79e4b4802e082a51318af04f524 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 23 Jun 2023 12:19:57 -0700 Subject: [PATCH 0186/1487] snapuserd: Create a MergeWorker class. Merge threads and read threads share some common state but not much. Splitting into separate classes will help isolate dm-user specific code. Bug: 288273605 Test: snapuserd_test Change-Id: I612374bb0072b1eedf32c30270913dbe907cc6ab --- .../user-space-merge/handler_manager.cpp | 1 + .../user-space-merge/snapuserd_core.cpp | 15 ++++- .../user-space-merge/snapuserd_core.h | 37 ++---------- .../user-space-merge/snapuserd_merge.cpp | 31 ++++++---- .../user-space-merge/snapuserd_merge.h | 56 +++++++++++++++++++ 5 files changed, 92 insertions(+), 48 deletions(-) create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h 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 bdba5c0cc3ab..734e84f3c1a9 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp @@ -19,6 +19,7 @@ #include #include "snapuserd_core.h" +#include "snapuserd_merge.h" namespace android { namespace snapshot { 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 8e1212b7b3ce..4f7495c0a3f9 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -23,6 +23,8 @@ #include #include +#include "snapuserd_merge.h" + namespace android { namespace snapshot { @@ -57,8 +59,9 @@ bool SnapshotHandler::InitializeWorkers() { worker_threads_.push_back(std::move(wt)); } - merge_thread_ = std::make_unique(cow_device_, backing_store_device_, control_device_, - misc_name_, base_path_merge_, GetSharedPtr()); + merge_thread_ = + std::make_unique(cow_device_, backing_store_device_, control_device_, + misc_name_, base_path_merge_, GetSharedPtr()); read_ahead_thread_ = std::make_unique(cow_device_, backing_store_device_, misc_name_, GetSharedPtr()); @@ -316,7 +319,7 @@ bool SnapshotHandler::Start() { } std::future merge_thread = - std::async(std::launch::async, &Worker::RunMergeThread, merge_thread_.get()); + std::async(std::launch::async, &MergeWorker::Run, merge_thread_.get()); // Now that the worker threads are up, scan the partitions. if (perform_verification_) { @@ -452,5 +455,11 @@ bool SnapshotHandler::CheckPartitionVerification() { return update_verify_->CheckPartitionVerification(); } +void SnapshotHandler::FreeResources() { + worker_threads_.clear(); + read_ahead_thread_ = nullptr; + merge_thread_ = nullptr; +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index c984a61f89eb..fe10edfeeb8a 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -75,6 +75,7 @@ enum class MERGE_IO_TRANSITION { READ_AHEAD_FAILURE, }; +class MergeWorker; class SnapshotHandler; enum class MERGE_GROUP_STATE { @@ -104,10 +105,9 @@ class Worker { const std::string& control_device, const std::string& misc_name, const std::string& base_path_merge, std::shared_ptr snapuserd); bool RunThread(); - bool RunMergeThread(); bool Init(); - private: + protected: // Initialization void InitializeBufsink(); bool InitializeFds(); @@ -145,22 +145,9 @@ class Worker { bool ProcessXorOp(const CowOperation* cow_op); bool ProcessOrderedOp(const CowOperation* cow_op); - // Merge related ops - bool Merge(); - bool AsyncMerge(); - bool SyncMerge(); - bool MergeOrderedOps(); - bool MergeOrderedOpsAsync(); - bool MergeReplaceZeroOps(); - int PrepareMerge(uint64_t* source_offset, int* pending_ops, - std::vector* replace_zero_vec = nullptr); - sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; } chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; } - bool InitializeIouring(); - void FinalizeIouring(); - std::unique_ptr reader_; BufferSink bufsink_; XorSink xorsink_; @@ -178,18 +165,6 @@ class Worker { bool header_response_ = false; std::unique_ptr cowop_iter_; - size_t ra_block_index_ = 0; - uint64_t blocks_merged_in_group_ = 0; - bool merge_async_ = false; - // Queue depth of 8 seems optimal. We don't want - // to have a huge depth as it may put more memory pressure - // on the kernel worker threads given that we use - // IOSQE_ASYNC flag - ASYNC flags can potentially - // result in EINTR; Since we don't restart - // syscalls and fallback to synchronous I/O, we - // don't want huge queue depth - int queue_depth_ = 8; - std::unique_ptr ring_; std::shared_ptr snapuserd_; }; @@ -212,11 +187,7 @@ class SnapshotHandler : public std::enable_shared_from_this { bool CommitMerge(int num_merge_ops); void CloseFds() { cow_fd_ = {}; } - void FreeResources() { - worker_threads_.clear(); - read_ahead_thread_ = nullptr; - merge_thread_ = nullptr; - } + void FreeResources(); bool InitializeWorkers(); std::unique_ptr CloneReaderForWorker(); @@ -330,7 +301,7 @@ class SnapshotHandler : public std::enable_shared_from_this { // Merge Block state std::vector> merge_blk_state_; - std::unique_ptr merge_thread_; + std::unique_ptr merge_thread_; double merge_completion_percentage_; bool merge_initiated_ = false; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp index ce95b7659d9d..ee7101129dbc 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "snapuserd_merge.h" #include "snapuserd_core.h" @@ -23,8 +24,14 @@ using namespace android; using namespace android::dm; using android::base::unique_fd; -int Worker::PrepareMerge(uint64_t* source_offset, int* pending_ops, - std::vector* replace_zero_vec) { +MergeWorker::MergeWorker(const std::string& cow_device, const std::string& backing_device, + const std::string& control_device, const std::string& misc_name, + const std::string& base_path_merge, + std::shared_ptr snapuserd) + : Worker(cow_device, backing_device, control_device, misc_name, base_path_merge, snapuserd) {} + +int MergeWorker::PrepareMerge(uint64_t* source_offset, int* pending_ops, + std::vector* replace_zero_vec) { int num_ops = *pending_ops; int nr_consecutive = 0; bool checkOrderedOp = (replace_zero_vec == nullptr); @@ -70,7 +77,7 @@ int Worker::PrepareMerge(uint64_t* source_offset, int* pending_ops, return nr_consecutive; } -bool Worker::MergeReplaceZeroOps() { +bool MergeWorker::MergeReplaceZeroOps() { // Flush after merging 2MB. Since all ops are independent and there is no // dependency between COW ops, we will flush the data and the number // of ops merged in COW block device. If there is a crash, we will @@ -149,7 +156,7 @@ bool Worker::MergeReplaceZeroOps() { if (snapuserd_->IsIOTerminated()) { SNAP_LOG(ERROR) - << "MergeReplaceZeroOps: Worker threads terminated - shutting down merge"; + << "MergeReplaceZeroOps: MergeWorker threads terminated - shutting down merge"; return false; } } @@ -173,7 +180,7 @@ bool Worker::MergeReplaceZeroOps() { return true; } -bool Worker::MergeOrderedOpsAsync() { +bool MergeWorker::MergeOrderedOpsAsync() { void* mapped_addr = snapuserd_->GetMappedAddr(); void* read_ahead_buffer = static_cast((char*)mapped_addr + snapuserd_->GetBufferDataOffset()); @@ -354,7 +361,7 @@ bool Worker::MergeOrderedOpsAsync() { return true; } -bool Worker::MergeOrderedOps() { +bool MergeWorker::MergeOrderedOps() { void* mapped_addr = snapuserd_->GetMappedAddr(); void* read_ahead_buffer = static_cast((char*)mapped_addr + snapuserd_->GetBufferDataOffset()); @@ -439,7 +446,7 @@ bool Worker::MergeOrderedOps() { return true; } -bool Worker::AsyncMerge() { +bool MergeWorker::AsyncMerge() { if (!MergeOrderedOpsAsync()) { SNAP_LOG(ERROR) << "MergeOrderedOpsAsync failed - Falling back to synchronous I/O"; // Reset the iter so that we retry the merge @@ -455,7 +462,7 @@ bool Worker::AsyncMerge() { return true; } -bool Worker::SyncMerge() { +bool MergeWorker::SyncMerge() { if (!MergeOrderedOps()) { SNAP_LOG(ERROR) << "Merge failed for ordered ops"; return false; @@ -465,7 +472,7 @@ bool Worker::SyncMerge() { return true; } -bool Worker::Merge() { +bool MergeWorker::Merge() { cowop_iter_ = reader_->GetOpIter(true); bool retry = false; @@ -511,7 +518,7 @@ bool Worker::Merge() { return true; } -bool Worker::InitializeIouring() { +bool MergeWorker::InitializeIouring() { if (!snapuserd_->IsIouringSupported()) { return false; } @@ -530,13 +537,13 @@ bool Worker::InitializeIouring() { return true; } -void Worker::FinalizeIouring() { +void MergeWorker::FinalizeIouring() { if (merge_async_) { io_uring_queue_exit(ring_.get()); } } -bool Worker::RunMergeThread() { +bool MergeWorker::Run() { SNAP_LOG(DEBUG) << "Waiting for merge begin..."; if (!snapuserd_->WaitForMergeBegin()) { SNAP_LOG(ERROR) << "Merge terminated early..."; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h new file mode 100644 index 000000000000..08192a0ef3b7 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h @@ -0,0 +1,56 @@ +// Copyright (C) 2023 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. +#pragma once + +#include "snapuserd_core.h" + +namespace android { +namespace snapshot { + +class MergeWorker : public Worker { + public: + MergeWorker(const std::string& cow_device, const std::string& backing_device, + const std::string& control_device, const std::string& misc_name, + const std::string& base_path_merge, std::shared_ptr snapuserd); + bool Run(); + + private: + int PrepareMerge(uint64_t* source_offset, int* pending_ops, + std::vector* replace_zero_vec = nullptr); + bool MergeReplaceZeroOps(); + bool MergeOrderedOps(); + bool MergeOrderedOpsAsync(); + bool Merge(); + bool AsyncMerge(); + bool SyncMerge(); + bool InitializeIouring(); + void FinalizeIouring(); + + private: + std::unique_ptr ring_; + size_t ra_block_index_ = 0; + uint64_t blocks_merged_in_group_ = 0; + bool merge_async_ = false; + // Queue depth of 8 seems optimal. We don't want + // to have a huge depth as it may put more memory pressure + // on the kernel worker threads given that we use + // IOSQE_ASYNC flag - ASYNC flags can potentially + // result in EINTR; Since we don't restart + // syscalls and fallback to synchronous I/O, we + // don't want huge queue depth + int queue_depth_ = 8; +}; + +} // namespace snapshot +} // namespace android From d967591434f4e8467fce590286a7c18c1c06c64d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 23 Jun 2023 12:39:19 -0700 Subject: [PATCH 0187/1487] snapuserd: Create a ReadWorker class. This splits the dm-user specific parts of Worker into a derived class. Bug: 288273605 Test: snapuserd_test Change-Id: Ic0ed1a8dff30018fa8466e7dc6e92469f1c87579 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 2 +- .../user-space-merge/handler_manager.cpp | 1 + ...{snapuserd_dm_user.cpp => read_worker.cpp} | 41 +++++++++----- .../snapuserd/user-space-merge/read_worker.h | 53 +++++++++++++++++++ .../user-space-merge/snapuserd_core.cpp | 8 +-- .../user-space-merge/snapuserd_core.h | 27 ++-------- 6 files changed, 92 insertions(+), 40 deletions(-) rename fs_mgr/libsnapshot/snapuserd/user-space-merge/{snapuserd_dm_user.cpp => read_worker.cpp} (94%) create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 9fe567acbc7e..38ec23fc6d63 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -63,8 +63,8 @@ cc_library_static { "dm-snapshot-merge/snapuserd_readahead.cpp", "snapuserd_buffer.cpp", "user-space-merge/handler_manager.cpp", + "user-space-merge/read_worker.cpp", "user-space-merge/snapuserd_core.cpp", - "user-space-merge/snapuserd_dm_user.cpp", "user-space-merge/snapuserd_merge.cpp", "user-space-merge/snapuserd_readahead.cpp", "user-space-merge/snapuserd_transitions.cpp", 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 734e84f3c1a9..4105b4b4836a 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp @@ -18,6 +18,7 @@ #include +#include "read_worker.h" #include "snapuserd_core.h" #include "snapuserd_merge.h" diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp similarity index 94% rename from fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp rename to fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp index 2b9d14e9c19c..49a83608e290 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "read_worker.h" + #include "snapuserd_core.h" namespace android { @@ -34,6 +36,12 @@ Worker::Worker(const std::string& cow_device, const std::string& backing_device, snapuserd_ = snapuserd; } +ReadWorker::ReadWorker(const std::string& cow_device, const std::string& backing_device, + const std::string& control_device, const std::string& misc_name, + const std::string& base_path_merge, + std::shared_ptr snapuserd) + : Worker(cow_device, backing_device, control_device, misc_name, base_path_merge, snapuserd) {} + bool Worker::InitializeFds() { backing_store_fd_.reset(open(backing_store_device_.c_str(), O_RDONLY)); if (backing_store_fd_ < 0) { @@ -118,7 +126,7 @@ bool Worker::ReadFromSourceDevice(const CowOperation* cow_op) { // Start the copy operation. This will read the backing // block device which is represented by cow_op->source. -bool Worker::ProcessCopyOp(const CowOperation* cow_op) { +bool ReadWorker::ProcessCopyOp(const CowOperation* cow_op) { if (!ReadFromSourceDevice(cow_op)) { return false; } @@ -126,7 +134,7 @@ bool Worker::ProcessCopyOp(const CowOperation* cow_op) { return true; } -bool Worker::ProcessXorOp(const CowOperation* cow_op) { +bool ReadWorker::ProcessXorOp(const CowOperation* cow_op) { if (!ReadFromSourceDevice(cow_op)) { return false; } @@ -165,7 +173,7 @@ bool Worker::ProcessZeroOp() { return true; } -bool Worker::ProcessOrderedOp(const CowOperation* cow_op) { +bool ReadWorker::ProcessOrderedOp(const CowOperation* cow_op) { void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ); if (buffer == nullptr) { SNAP_LOG(ERROR) << "ProcessOrderedOp: Failed to get payload buffer"; @@ -218,7 +226,7 @@ bool Worker::ProcessOrderedOp(const CowOperation* cow_op) { return false; } -bool Worker::ProcessCowOp(const CowOperation* cow_op) { +bool ReadWorker::ProcessCowOp(const CowOperation* cow_op) { if (cow_op == nullptr) { SNAP_LOG(ERROR) << "ProcessCowOp: Invalid cow_op"; return false; @@ -257,7 +265,6 @@ void Worker::InitializeBufsink() { bool Worker::Init() { InitializeBufsink(); - xorsink_.Initialize(&bufsink_, BLOCK_SZ); if (!InitializeFds()) { return false; @@ -270,7 +277,15 @@ bool Worker::Init() { return true; } -bool Worker::RunThread() { +bool ReadWorker::Init() { + if (!Worker::Init()) { + return false; + } + xorsink_.Initialize(&bufsink_, BLOCK_SZ); + return true; +} + +bool ReadWorker::Run() { SNAP_LOG(INFO) << "Processing snapshot I/O requests...."; if (setpriority(PRIO_PROCESS, gettid(), kNiceValueForMergeThreads)) { @@ -291,7 +306,7 @@ bool Worker::RunThread() { } // Send the payload/data back to dm-user misc device. -bool Worker::WriteDmUserPayload(size_t size) { +bool ReadWorker::WriteDmUserPayload(size_t size) { size_t payload_size = size; void* buf = bufsink_.GetPayloadBufPtr(); if (header_response_) { @@ -329,7 +344,7 @@ bool Worker::ReadDataFromBaseDevice(sector_t sector, size_t read_size) { return true; } -bool Worker::ReadAlignedSector(sector_t sector, size_t sz) { +bool ReadWorker::ReadAlignedSector(sector_t sector, size_t sz) { size_t remaining_size = sz; std::vector>& chunk_vec = snapuserd_->GetChunkVec(); int ret = 0; @@ -389,7 +404,7 @@ bool Worker::ReadAlignedSector(sector_t sector, size_t sz) { return true; } -int Worker::ReadUnalignedSector( +int ReadWorker::ReadUnalignedSector( sector_t sector, size_t size, std::vector>::iterator& it) { size_t skip_sector_size = 0; @@ -424,7 +439,7 @@ int Worker::ReadUnalignedSector( return std::min(size, (BLOCK_SZ - skip_sector_size)); } -bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { +bool ReadWorker::ReadUnalignedSector(sector_t sector, size_t size) { bufsink_.ResetBufferOffset(); std::vector>& chunk_vec = snapuserd_->GetChunkVec(); @@ -563,7 +578,7 @@ bool Worker::ReadUnalignedSector(sector_t sector, size_t size) { return true; } -void Worker::RespondIOError() { +void ReadWorker::RespondIOError() { struct dm_user_header* header = bufsink_.GetHeaderPtr(); header->type = DM_USER_RESP_ERROR; // This is an issue with the dm-user interface. There @@ -580,7 +595,7 @@ void Worker::RespondIOError() { WriteDmUserPayload(0); } -bool Worker::DmuserReadRequest() { +bool ReadWorker::DmuserReadRequest() { struct dm_user_header* header = bufsink_.GetHeaderPtr(); // Unaligned I/O request @@ -591,7 +606,7 @@ bool Worker::DmuserReadRequest() { return ReadAlignedSector(header->sector, header->len); } -bool Worker::ProcessIORequest() { +bool ReadWorker::ProcessIORequest() { // Read Header from dm-user misc device. This gives // us the sector number for which IO is issued by dm-snapshot device struct dm_user_header* header = bufsink_.GetHeaderPtr(); diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h new file mode 100644 index 000000000000..262f8adfe26f --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h @@ -0,0 +1,53 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include "snapuserd_core.h" + +namespace android { +namespace snapshot { + +class ReadWorker : public Worker { + public: + ReadWorker(const std::string& cow_device, const std::string& backing_device, + const std::string& control_device, const std::string& misc_name, + const std::string& base_path_merge, std::shared_ptr snapuserd); + + bool Run(); + bool Init() override; + + private: + // Functions interacting with dm-user + bool ProcessIORequest(); + bool WriteDmUserPayload(size_t size); + bool DmuserReadRequest(); + void RespondIOError(); + + bool ProcessCowOp(const CowOperation* cow_op); + bool ProcessXorOp(const CowOperation* cow_op); + bool ProcessOrderedOp(const CowOperation* cow_op); + bool ProcessCopyOp(const CowOperation* cow_op); + + bool ReadAlignedSector(sector_t sector, size_t sz); + bool ReadUnalignedSector(sector_t sector, size_t size); + int ReadUnalignedSector(sector_t sector, size_t size, + std::vector>::iterator& it); + + XorSink xorsink_; + bool header_response_ = false; +}; + +} // namespace snapshot +} // namespace android 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 4f7495c0a3f9..baf06b393c05 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -23,6 +23,7 @@ #include #include +#include "read_worker.h" #include "snapuserd_merge.h" namespace android { @@ -48,9 +49,8 @@ SnapshotHandler::SnapshotHandler(std::string misc_name, std::string cow_device, bool SnapshotHandler::InitializeWorkers() { for (int i = 0; i < num_worker_threads_; i++) { - std::unique_ptr wt = - std::make_unique(cow_device_, backing_store_device_, control_device_, - misc_name_, base_path_merge_, GetSharedPtr()); + auto wt = std::make_unique(cow_device_, backing_store_device_, control_device_, + misc_name_, base_path_merge_, GetSharedPtr()); if (!wt->Init()) { SNAP_LOG(ERROR) << "Thread initialization failed"; return false; @@ -315,7 +315,7 @@ bool SnapshotHandler::Start() { // Launch worker threads for (int i = 0; i < worker_threads_.size(); i++) { threads.emplace_back( - std::async(std::launch::async, &Worker::RunThread, worker_threads_[i].get())); + std::async(std::launch::async, &ReadWorker::Run, worker_threads_[i].get())); } std::future merge_thread = diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index fe10edfeeb8a..0c30eac75821 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -76,6 +76,7 @@ enum class MERGE_IO_TRANSITION { }; class MergeWorker; +class ReadWorker; class SnapshotHandler; enum class MERGE_GROUP_STATE { @@ -104,8 +105,9 @@ class Worker { Worker(const std::string& cow_device, const std::string& backing_device, const std::string& control_device, const std::string& misc_name, const std::string& base_path_merge, std::shared_ptr snapuserd); - bool RunThread(); - bool Init(); + virtual ~Worker() = default; + + virtual bool Init(); protected: // Initialization @@ -118,39 +120,21 @@ class Worker { base_path_merge_fd_ = {}; } - // Functions interacting with dm-user - bool WriteDmUserPayload(size_t size); - bool DmuserReadRequest(); - // IO Path - bool ProcessIORequest(); bool IsBlockAligned(size_t size) { return ((size & (BLOCK_SZ - 1)) == 0); } bool ReadDataFromBaseDevice(sector_t sector, size_t read_size); bool ReadFromSourceDevice(const CowOperation* cow_op); - bool ReadAlignedSector(sector_t sector, size_t sz); - bool ReadUnalignedSector(sector_t sector, size_t size); - int ReadUnalignedSector(sector_t sector, size_t size, - std::vector>::iterator& it); - void RespondIOError(); - // Processing COW operations - bool ProcessCowOp(const CowOperation* cow_op); bool ProcessReplaceOp(const CowOperation* cow_op); bool ProcessZeroOp(); - // Handles Copy and Xor - bool ProcessCopyOp(const CowOperation* cow_op); - bool ProcessXorOp(const CowOperation* cow_op); - bool ProcessOrderedOp(const CowOperation* cow_op); - sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; } chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; } std::unique_ptr reader_; BufferSink bufsink_; - XorSink xorsink_; std::string cow_device_; std::string backing_store_device_; @@ -162,7 +146,6 @@ class Worker { unique_fd backing_store_fd_; unique_fd base_path_merge_fd_; unique_fd ctrl_fd_; - bool header_response_ = false; std::unique_ptr cowop_iter_; @@ -286,7 +269,7 @@ class SnapshotHandler : public std::enable_shared_from_this { void* mapped_addr_; size_t total_mapped_addr_length_; - std::vector> worker_threads_; + std::vector> worker_threads_; // Read-ahead related bool populate_data_from_cow_ = false; bool ra_thread_ = false; From ab57c8a5774a5ba59e6144e06ecb33d9df690ea3 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 23 Jun 2023 13:00:34 -0700 Subject: [PATCH 0188/1487] snapuserd: Split more methods out of Worker. This moves ReadWorker-specific methods out of Worker, and moves remaining Worker methods into a separate worker.cpp file. Bug: 288273605 Test: snapuserd_test Change-Id: I59c31318e127db61a5f3a673956865dac97a6e5f --- fs_mgr/libsnapshot/snapuserd/Android.bp | 1 + .../user-space-merge/read_worker.cpp | 76 +-------------- .../snapuserd/user-space-merge/read_worker.h | 7 +- .../user-space-merge/snapuserd_core.h | 53 ----------- .../user-space-merge/snapuserd_merge.h | 4 +- .../snapuserd/user-space-merge/worker.cpp | 95 +++++++++++++++++++ .../snapuserd/user-space-merge/worker.h | 86 +++++++++++++++++ 7 files changed, 193 insertions(+), 129 deletions(-) create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.cpp create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 38ec23fc6d63..78a3b9bf28ea 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -69,6 +69,7 @@ cc_library_static { "user-space-merge/snapuserd_readahead.cpp", "user-space-merge/snapuserd_transitions.cpp", "user-space-merge/snapuserd_verify.cpp", + "user-space-merge/worker.cpp", ], static_libs: [ "libbase", diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp index 49a83608e290..c47abe3fd57a 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp @@ -25,61 +25,12 @@ using namespace android; using namespace android::dm; using android::base::unique_fd; -Worker::Worker(const std::string& cow_device, const std::string& backing_device, - const std::string& control_device, const std::string& misc_name, - const std::string& base_path_merge, std::shared_ptr snapuserd) { - cow_device_ = cow_device; - backing_store_device_ = backing_device; - control_device_ = control_device; - misc_name_ = misc_name; - base_path_merge_ = base_path_merge; - snapuserd_ = snapuserd; -} - ReadWorker::ReadWorker(const std::string& cow_device, const std::string& backing_device, const std::string& control_device, const std::string& misc_name, const std::string& base_path_merge, std::shared_ptr snapuserd) : Worker(cow_device, backing_device, control_device, misc_name, base_path_merge, snapuserd) {} -bool Worker::InitializeFds() { - backing_store_fd_.reset(open(backing_store_device_.c_str(), O_RDONLY)); - if (backing_store_fd_ < 0) { - SNAP_PLOG(ERROR) << "Open Failed: " << backing_store_device_; - return false; - } - - cow_fd_.reset(open(cow_device_.c_str(), O_RDWR)); - if (cow_fd_ < 0) { - SNAP_PLOG(ERROR) << "Open Failed: " << cow_device_; - return false; - } - - ctrl_fd_.reset(open(control_device_.c_str(), O_RDWR)); - if (ctrl_fd_ < 0) { - SNAP_PLOG(ERROR) << "Unable to open " << control_device_; - return false; - } - - // Base device used by merge thread - base_path_merge_fd_.reset(open(base_path_merge_.c_str(), O_RDWR)); - if (base_path_merge_fd_ < 0) { - SNAP_PLOG(ERROR) << "Open Failed: " << base_path_merge_; - return false; - } - - return true; -} - -bool Worker::InitReader() { - reader_ = snapuserd_->CloneReaderForWorker(); - - if (!reader_->InitForMerge(std::move(cow_fd_))) { - return false; - } - return true; -} - // Start the replace operation. This will read the // internal COW format and if the block is compressed, // it will be de-compressed. @@ -96,7 +47,7 @@ bool Worker::ProcessReplaceOp(const CowOperation* cow_op) { return true; } -bool Worker::ReadFromSourceDevice(const CowOperation* cow_op) { +bool ReadWorker::ReadFromSourceDevice(const CowOperation* cow_op) { void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ); if (buffer == nullptr) { SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get payload buffer"; @@ -254,29 +205,6 @@ bool ReadWorker::ProcessCowOp(const CowOperation* cow_op) { return false; } -void Worker::InitializeBufsink() { - // Allocate the buffer which is used to communicate between - // daemon and dm-user. The buffer comprises of header and a fixed payload. - // If the dm-user requests a big IO, the IO will be broken into chunks - // of PAYLOAD_BUFFER_SZ. - size_t buf_size = sizeof(struct dm_user_header) + PAYLOAD_BUFFER_SZ; - bufsink_.Initialize(buf_size); -} - -bool Worker::Init() { - InitializeBufsink(); - - if (!InitializeFds()) { - return false; - } - - if (!InitReader()) { - return false; - } - - return true; -} - bool ReadWorker::Init() { if (!Worker::Init()) { return false; @@ -325,7 +253,7 @@ bool ReadWorker::WriteDmUserPayload(size_t size) { return true; } -bool Worker::ReadDataFromBaseDevice(sector_t sector, size_t read_size) { +bool ReadWorker::ReadDataFromBaseDevice(sector_t sector, size_t read_size) { CHECK(read_size <= BLOCK_SZ); void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ); diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h index 262f8adfe26f..b12dab24ca77 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h @@ -14,7 +14,10 @@ #pragma once -#include "snapuserd_core.h" +#include +#include + +#include "worker.h" namespace android { namespace snapshot { @@ -44,6 +47,8 @@ class ReadWorker : public Worker { bool ReadUnalignedSector(sector_t sector, size_t size); int ReadUnalignedSector(sector_t sector, size_t size, std::vector>::iterator& it); + bool ReadFromSourceDevice(const CowOperation* cow_op); + bool ReadDataFromBaseDevice(sector_t sector, size_t read_size); XorSink xorsink_; bool header_response_ = false; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index 0c30eac75821..cdc38c01665e 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -77,7 +77,6 @@ enum class MERGE_IO_TRANSITION { class MergeWorker; class ReadWorker; -class SnapshotHandler; enum class MERGE_GROUP_STATE { GROUP_MERGE_PENDING, @@ -100,58 +99,6 @@ struct MergeGroupState { : merge_state_(state), num_ios_in_progress(n_ios) {} }; -class Worker { - public: - Worker(const std::string& cow_device, const std::string& backing_device, - const std::string& control_device, const std::string& misc_name, - const std::string& base_path_merge, std::shared_ptr snapuserd); - virtual ~Worker() = default; - - virtual bool Init(); - - protected: - // Initialization - void InitializeBufsink(); - bool InitializeFds(); - bool InitReader(); - void CloseFds() { - ctrl_fd_ = {}; - backing_store_fd_ = {}; - base_path_merge_fd_ = {}; - } - - // IO Path - bool IsBlockAligned(size_t size) { return ((size & (BLOCK_SZ - 1)) == 0); } - - bool ReadDataFromBaseDevice(sector_t sector, size_t read_size); - bool ReadFromSourceDevice(const CowOperation* cow_op); - - // Processing COW operations - bool ProcessReplaceOp(const CowOperation* cow_op); - bool ProcessZeroOp(); - - sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; } - chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; } - - std::unique_ptr reader_; - BufferSink bufsink_; - - std::string cow_device_; - std::string backing_store_device_; - std::string control_device_; - std::string misc_name_; - std::string base_path_merge_; - - unique_fd cow_fd_; - unique_fd backing_store_fd_; - unique_fd base_path_merge_fd_; - unique_fd ctrl_fd_; - - std::unique_ptr cowop_iter_; - - std::shared_ptr snapuserd_; -}; - class SnapshotHandler : public std::enable_shared_from_this { public: SnapshotHandler(std::string misc_name, std::string cow_device, std::string backing_device, diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h index 08192a0ef3b7..3da73c24d001 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h @@ -13,7 +13,9 @@ // limitations under the License. #pragma once -#include "snapuserd_core.h" +#include "worker.h" + +#include namespace android { namespace snapshot { diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.cpp new file mode 100644 index 000000000000..ef6781a61feb --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.cpp @@ -0,0 +1,95 @@ +// Copyright (C) 2023 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 "worker.h" + +#include "snapuserd_core.h" + +namespace android { +namespace snapshot { + +Worker::Worker(const std::string& cow_device, const std::string& backing_device, + const std::string& control_device, const std::string& misc_name, + const std::string& base_path_merge, std::shared_ptr snapuserd) { + cow_device_ = cow_device; + backing_store_device_ = backing_device; + control_device_ = control_device; + misc_name_ = misc_name; + base_path_merge_ = base_path_merge; + snapuserd_ = snapuserd; +} + +void Worker::InitializeBufsink() { + // Allocate the buffer which is used to communicate between + // daemon and dm-user. The buffer comprises of header and a fixed payload. + // If the dm-user requests a big IO, the IO will be broken into chunks + // of PAYLOAD_BUFFER_SZ. + size_t buf_size = sizeof(struct dm_user_header) + PAYLOAD_BUFFER_SZ; + bufsink_.Initialize(buf_size); +} + +bool Worker::Init() { + InitializeBufsink(); + + if (!InitializeFds()) { + return false; + } + + if (!InitReader()) { + return false; + } + + return true; +} + +bool Worker::InitReader() { + reader_ = snapuserd_->CloneReaderForWorker(); + + if (!reader_->InitForMerge(std::move(cow_fd_))) { + return false; + } + return true; +} + +bool Worker::InitializeFds() { + backing_store_fd_.reset(open(backing_store_device_.c_str(), O_RDONLY)); + if (backing_store_fd_ < 0) { + SNAP_PLOG(ERROR) << "Open Failed: " << backing_store_device_; + return false; + } + + cow_fd_.reset(open(cow_device_.c_str(), O_RDWR)); + if (cow_fd_ < 0) { + SNAP_PLOG(ERROR) << "Open Failed: " << cow_device_; + return false; + } + + ctrl_fd_.reset(open(control_device_.c_str(), O_RDWR)); + if (ctrl_fd_ < 0) { + SNAP_PLOG(ERROR) << "Unable to open " << control_device_; + return false; + } + + // Base device used by merge thread + base_path_merge_fd_.reset(open(base_path_merge_.c_str(), O_RDWR)); + if (base_path_merge_fd_ < 0) { + SNAP_PLOG(ERROR) << "Open Failed: " << base_path_merge_; + return false; + } + + return true; +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h new file mode 100644 index 000000000000..d38ce5d1895c --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h @@ -0,0 +1,86 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include + +#include +#include + +#include +#include +#include +#include + +namespace android { +namespace snapshot { + +using android::base::unique_fd; + +class SnapshotHandler; + +class Worker { + public: + Worker(const std::string& cow_device, const std::string& backing_device, + const std::string& control_device, const std::string& misc_name, + const std::string& base_path_merge, std::shared_ptr snapuserd); + virtual ~Worker() = default; + + virtual bool Init(); + + protected: + // Initialization + void InitializeBufsink(); + bool InitializeFds(); + bool InitReader(); + void CloseFds() { + ctrl_fd_ = {}; + backing_store_fd_ = {}; + base_path_merge_fd_ = {}; + } + + // IO Path + bool IsBlockAligned(size_t size) { return ((size & (BLOCK_SZ - 1)) == 0); } + + bool ReadDataFromBaseDevice(sector_t sector, size_t read_size); + + // Processing COW operations + bool ProcessReplaceOp(const CowOperation* cow_op); + bool ProcessZeroOp(); + + sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; } + chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; } + + std::unique_ptr reader_; + BufferSink bufsink_; + + std::string cow_device_; + std::string backing_store_device_; + std::string control_device_; + std::string misc_name_; + std::string base_path_merge_; + + unique_fd cow_fd_; + unique_fd backing_store_fd_; + unique_fd base_path_merge_fd_; + unique_fd ctrl_fd_; + + std::unique_ptr cowop_iter_; + + std::shared_ptr snapuserd_; +}; + +} // namespace snapshot +} // namespace android From c2d5a19d269bfcde34f4e4ea5db9733f437305f6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 23 Jun 2023 13:30:00 -0700 Subject: [PATCH 0189/1487] snapuserd: Move more fields out of Worker. These fields are specific to either ReadWorker or MergeWorker, but not both. Bug: 288273605 Test: snapuserd_test Change-Id: I2db9cfa2a8f034249879517bd90a40babe97bc64 --- .../user-space-merge/read_worker.cpp | 23 +++++++++++++- .../snapuserd/user-space-merge/read_worker.h | 10 ++++++ .../user-space-merge/snapuserd_core.cpp | 5 ++- .../user-space-merge/snapuserd_merge.cpp | 5 ++- .../user-space-merge/snapuserd_merge.h | 4 +-- .../snapuserd/user-space-merge/worker.cpp | 17 +--------- .../snapuserd/user-space-merge/worker.h | 31 +++++-------------- 7 files changed, 47 insertions(+), 48 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp index c47abe3fd57a..4c8223f1e913 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp @@ -25,11 +25,19 @@ using namespace android; using namespace android::dm; using android::base::unique_fd; +void ReadWorker::CloseFds() { + ctrl_fd_ = {}; + backing_store_fd_ = {}; + Worker::CloseFds(); +} + ReadWorker::ReadWorker(const std::string& cow_device, const std::string& backing_device, const std::string& control_device, const std::string& misc_name, const std::string& base_path_merge, std::shared_ptr snapuserd) - : Worker(cow_device, backing_device, control_device, misc_name, base_path_merge, snapuserd) {} + : Worker(cow_device, misc_name, base_path_merge, snapuserd), + backing_store_device_(backing_device), + control_device_(control_device) {} // Start the replace operation. This will read the // internal COW format and if the block is compressed, @@ -209,6 +217,19 @@ bool ReadWorker::Init() { if (!Worker::Init()) { return false; } + + backing_store_fd_.reset(open(backing_store_device_.c_str(), O_RDONLY)); + if (backing_store_fd_ < 0) { + SNAP_PLOG(ERROR) << "Open Failed: " << backing_store_device_; + return false; + } + + ctrl_fd_.reset(open(control_device_.c_str(), O_RDWR)); + if (ctrl_fd_ < 0) { + SNAP_PLOG(ERROR) << "Unable to open " << control_device_; + return false; + } + xorsink_.Initialize(&bufsink_, BLOCK_SZ); return true; } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h index b12dab24ca77..bc0474f4bba7 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h @@ -30,6 +30,7 @@ class ReadWorker : public Worker { bool Run(); bool Init() override; + void CloseFds() override; private: // Functions interacting with dm-user @@ -50,6 +51,15 @@ class ReadWorker : public Worker { bool ReadFromSourceDevice(const CowOperation* cow_op); bool ReadDataFromBaseDevice(sector_t sector, size_t read_size); + constexpr bool IsBlockAligned(size_t size) { return ((size & (BLOCK_SZ - 1)) == 0); } + constexpr sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; } + + std::string backing_store_device_; + unique_fd backing_store_fd_; + + std::string control_device_; + unique_fd ctrl_fd_; + XorSink xorsink_; bool header_response_ = false; }; 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 baf06b393c05..e52d752a0eb9 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -59,9 +59,8 @@ bool SnapshotHandler::InitializeWorkers() { worker_threads_.push_back(std::move(wt)); } - merge_thread_ = - std::make_unique(cow_device_, backing_store_device_, control_device_, - misc_name_, base_path_merge_, GetSharedPtr()); + merge_thread_ = std::make_unique(cow_device_, misc_name_, base_path_merge_, + GetSharedPtr()); read_ahead_thread_ = std::make_unique(cow_device_, backing_store_device_, misc_name_, GetSharedPtr()); diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp index ee7101129dbc..510e27d29eea 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp @@ -24,11 +24,10 @@ using namespace android; using namespace android::dm; using android::base::unique_fd; -MergeWorker::MergeWorker(const std::string& cow_device, const std::string& backing_device, - const std::string& control_device, const std::string& misc_name, +MergeWorker::MergeWorker(const std::string& cow_device, const std::string& misc_name, const std::string& base_path_merge, std::shared_ptr snapuserd) - : Worker(cow_device, backing_device, control_device, misc_name, base_path_merge, snapuserd) {} + : Worker(cow_device, misc_name, base_path_merge, snapuserd) {} int MergeWorker::PrepareMerge(uint64_t* source_offset, int* pending_ops, std::vector* replace_zero_vec) { diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h index 3da73c24d001..f35147f2beb6 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h @@ -22,8 +22,7 @@ namespace snapshot { class MergeWorker : public Worker { public: - MergeWorker(const std::string& cow_device, const std::string& backing_device, - const std::string& control_device, const std::string& misc_name, + MergeWorker(const std::string& cow_device, const std::string& misc_name, const std::string& base_path_merge, std::shared_ptr snapuserd); bool Run(); @@ -40,6 +39,7 @@ class MergeWorker : public Worker { void FinalizeIouring(); private: + std::unique_ptr cowop_iter_; std::unique_ptr ring_; size_t ra_block_index_ = 0; uint64_t blocks_merged_in_group_ = 0; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.cpp index ef6781a61feb..aa156301fa3b 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.cpp @@ -19,12 +19,9 @@ namespace android { namespace snapshot { -Worker::Worker(const std::string& cow_device, const std::string& backing_device, - const std::string& control_device, const std::string& misc_name, +Worker::Worker(const std::string& cow_device, const std::string& misc_name, const std::string& base_path_merge, std::shared_ptr snapuserd) { cow_device_ = cow_device; - backing_store_device_ = backing_device; - control_device_ = control_device; misc_name_ = misc_name; base_path_merge_ = base_path_merge; snapuserd_ = snapuserd; @@ -63,24 +60,12 @@ bool Worker::InitReader() { } bool Worker::InitializeFds() { - backing_store_fd_.reset(open(backing_store_device_.c_str(), O_RDONLY)); - if (backing_store_fd_ < 0) { - SNAP_PLOG(ERROR) << "Open Failed: " << backing_store_device_; - return false; - } - cow_fd_.reset(open(cow_device_.c_str(), O_RDWR)); if (cow_fd_ < 0) { SNAP_PLOG(ERROR) << "Open Failed: " << cow_device_; return false; } - ctrl_fd_.reset(open(control_device_.c_str(), O_RDWR)); - if (ctrl_fd_ < 0) { - SNAP_PLOG(ERROR) << "Unable to open " << control_device_; - return false; - } - // Base device used by merge thread base_path_merge_fd_.reset(open(base_path_merge_.c_str(), O_RDWR)); if (base_path_merge_fd_ < 0) { diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h index d38ce5d1895c..1175ab714b7e 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h @@ -33,8 +33,7 @@ class SnapshotHandler; class Worker { public: - Worker(const std::string& cow_device, const std::string& backing_device, - const std::string& control_device, const std::string& misc_name, + Worker(const std::string& cow_device, const std::string& misc_name, const std::string& base_path_merge, std::shared_ptr snapuserd); virtual ~Worker() = default; @@ -45,14 +44,7 @@ class Worker { void InitializeBufsink(); bool InitializeFds(); bool InitReader(); - void CloseFds() { - ctrl_fd_ = {}; - backing_store_fd_ = {}; - base_path_merge_fd_ = {}; - } - - // IO Path - bool IsBlockAligned(size_t size) { return ((size & (BLOCK_SZ - 1)) == 0); } + virtual void CloseFds() { base_path_merge_fd_ = {}; } bool ReadDataFromBaseDevice(sector_t sector, size_t read_size); @@ -60,26 +52,19 @@ class Worker { bool ProcessReplaceOp(const CowOperation* cow_op); bool ProcessZeroOp(); - sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; } - chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; } - std::unique_ptr reader_; BufferSink bufsink_; - std::string cow_device_; - std::string backing_store_device_; - std::string control_device_; - std::string misc_name_; - std::string base_path_merge_; + std::string misc_name_; // Needed for SNAP_LOG. - unique_fd cow_fd_; - unique_fd backing_store_fd_; unique_fd base_path_merge_fd_; - unique_fd ctrl_fd_; - - std::unique_ptr cowop_iter_; std::shared_ptr snapuserd_; + + private: + std::string cow_device_; + std::string base_path_merge_; + unique_fd cow_fd_; }; } // namespace snapshot From 77280caed16ecc3b2744fa1b38e08765c852e08d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 12 Jul 2023 11:49:40 -0700 Subject: [PATCH 0190/1487] snapuserd: Fix bool/int return value mismatches. Bug: 288273605 Test: snapuserd_test, ota Change-Id: I06d641d3255711dd51583ea9bd9fd6a1acdc7bb2 --- .../snapuserd/user-space-merge/snapuserd_dm_user.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp index 1b17698a3e1a..2b9d14e9c19c 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp @@ -585,7 +585,7 @@ bool Worker::DmuserReadRequest() { // Unaligned I/O request if (!IsBlockAligned(header->sector << SECTOR_SHIFT)) { - return ReadUnalignedSector(header->sector, header->len) != -1; + return ReadUnalignedSector(header->sector, header->len); } return ReadAlignedSector(header->sector, header->len); From 8bc625e9cae82c798e0d2ef8233902663a638744 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 23 Jun 2023 13:52:44 -0700 Subject: [PATCH 0191/1487] snapuserd: Move Process ops out of Worker. These are so small they can be inlined into MergeWorker. Sharing these methods will be difficult after decoupling from dm-user, since acquisition of buffers will change. Bug: 288273605 Test: snapuserd_test Change-Id: I1625d1a6e55bcb2041f73453ca15a01f98263e8a --- .../snapuserd/user-space-merge/read_worker.cpp | 4 ++-- .../snapuserd/user-space-merge/read_worker.h | 2 ++ .../user-space-merge/snapuserd_merge.cpp | 15 +++++++++------ .../snapuserd/user-space-merge/worker.h | 6 ------ 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp index 4c8223f1e913..dd2996b783a0 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp @@ -42,7 +42,7 @@ ReadWorker::ReadWorker(const std::string& cow_device, const std::string& backing // Start the replace operation. This will read the // internal COW format and if the block is compressed, // it will be de-compressed. -bool Worker::ProcessReplaceOp(const CowOperation* cow_op) { +bool ReadWorker::ProcessReplaceOp(const CowOperation* cow_op) { void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ); if (!buffer) { SNAP_LOG(ERROR) << "ProcessReplaceOp failed to allocate buffer"; @@ -120,7 +120,7 @@ bool ReadWorker::ProcessXorOp(const CowOperation* cow_op) { return true; } -bool Worker::ProcessZeroOp() { +bool ReadWorker::ProcessZeroOp() { // Zero out the entire block void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ); if (buffer == nullptr) { diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h index bc0474f4bba7..c3a4c346ebfd 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h @@ -43,6 +43,8 @@ class ReadWorker : public Worker { bool ProcessXorOp(const CowOperation* cow_op); bool ProcessOrderedOp(const CowOperation* cow_op); bool ProcessCopyOp(const CowOperation* cow_op); + bool ProcessReplaceOp(const CowOperation* cow_op); + bool ProcessZeroOp(); bool ReadAlignedSector(sector_t sector, size_t sz); bool ReadUnalignedSector(sector_t sector, size_t size); diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp index 510e27d29eea..563f6ad427cc 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp @@ -105,17 +105,20 @@ bool MergeWorker::MergeReplaceZeroOps() { for (size_t i = 0; i < replace_zero_vec.size(); i++) { const CowOperation* cow_op = replace_zero_vec[i]; + + void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ); + if (!buffer) { + SNAP_LOG(ERROR) << "Failed to acquire buffer in merge"; + return false; + } if (cow_op->type == kCowReplaceOp) { - if (!ProcessReplaceOp(cow_op)) { - SNAP_LOG(ERROR) << "Merge - ReplaceOp failed for block: " << cow_op->new_block; + if (!reader_->ReadData(cow_op, buffer, BLOCK_SZ)) { + SNAP_LOG(ERROR) << "Failed to read COW in merge"; return false; } } else { CHECK(cow_op->type == kCowZeroOp); - if (!ProcessZeroOp()) { - SNAP_LOG(ERROR) << "Merge ZeroOp failed."; - return false; - } + memset(buffer, 0, BLOCK_SZ); } bufsink_.UpdateBufferOffset(BLOCK_SZ); diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h index 1175ab714b7e..813b159eaee3 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h @@ -46,12 +46,6 @@ class Worker { bool InitReader(); virtual void CloseFds() { base_path_merge_fd_ = {}; } - bool ReadDataFromBaseDevice(sector_t sector, size_t read_size); - - // Processing COW operations - bool ProcessReplaceOp(const CowOperation* cow_op); - bool ProcessZeroOp(); - std::unique_ptr reader_; BufferSink bufsink_; From f8f3b627aed47167b2a5d557601c8fa06367eaee Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 13 Jul 2023 09:25:11 -0700 Subject: [PATCH 0192/1487] fs_mgr: Split fs_mgr_overlayfs into two separate files. One of the paint points for fs_mgr_overlayfs is that mounting and scratch management code are somewhat unrelated but very intertwined in the same file. Split it into two files: fs_mgr_overlayfs_mount, which is only for mount-related code, and fs_mgr_overlayfs_control, which is only for setup/teardown code. The code removed from fs_mgr_overlayfs_control.cpp is code that moved to fs_mgr_overlayfs_mount.cpp. This converts a bunch of functions to "static", and splits fs_mgr_priv_overlayfs.h into two new files (fs_mgr_overlayfs_mount.h and fs_mgr_overlayfs_control.h). Bug: N/A Test: remount Change-Id: I83da43652b4787f344da75a1d30177df1d7f63b2 --- fs_mgr/Android.bp | 3 +- ...layfs.cpp => fs_mgr_overlayfs_control.cpp} | 669 +-------------- ...overlayfs.h => fs_mgr_overlayfs_control.h} | 33 +- fs_mgr/fs_mgr_overlayfs_mount.cpp | 802 ++++++++++++++++++ fs_mgr/fs_mgr_overlayfs_mount.h | 62 ++ fs_mgr/fs_mgr_remount.cpp | 3 +- 6 files changed, 894 insertions(+), 678 deletions(-) rename fs_mgr/{fs_mgr_overlayfs.cpp => fs_mgr_overlayfs_control.cpp} (61%) rename fs_mgr/{fs_mgr_priv_overlayfs.h => fs_mgr_overlayfs_control.h} (53%) create mode 100644 fs_mgr/fs_mgr_overlayfs_mount.cpp create mode 100644 fs_mgr/fs_mgr_overlayfs_mount.h diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp index bbd068bacc19..15600fd403eb 100644 --- a/fs_mgr/Android.bp +++ b/fs_mgr/Android.bp @@ -70,8 +70,9 @@ cc_defaults { "fs_mgr.cpp", "fs_mgr_format.cpp", "fs_mgr_dm_linear.cpp", - "fs_mgr_overlayfs.cpp", "fs_mgr_roots.cpp", + "fs_mgr_overlayfs_control.cpp", + "fs_mgr_overlayfs_mount.cpp", "fs_mgr_vendor_overlay.cpp", ":libfiemap_srcs", ], diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs_control.cpp similarity index 61% rename from fs_mgr/fs_mgr_overlayfs.cpp rename to fs_mgr/fs_mgr_overlayfs_control.cpp index 82a8b8b233c9..69a2ac028c6c 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs_control.cpp @@ -55,8 +55,9 @@ #include #include +#include "fs_mgr_overlayfs_control.h" +#include "fs_mgr_overlayfs_mount.h" #include "fs_mgr_priv.h" -#include "fs_mgr_priv_overlayfs.h" #include "libfiemap/utility.h" using namespace std::literals; @@ -69,100 +70,18 @@ using android::fiemap::IImageManager; namespace { constexpr char kDataScratchSizeMbProp[] = "fs_mgr.overlayfs.data_scratch_size_mb"; -constexpr char kPreferCacheBackingStorageProp[] = "fs_mgr.overlayfs.prefer_cache_backing_storage"; - -bool fs_mgr_access(const std::string& path) { - return access(path.c_str(), F_OK) == 0; -} - -const auto kLowerdirOption = "lowerdir="; -const auto kUpperdirOption = "upperdir="; - -bool fs_mgr_in_recovery() { - // Check the existence of recovery binary instead of using the compile time - // __ANDROID_RECOVERY__ macro. - // If BOARD_USES_RECOVERY_AS_BOOT is true, both normal and recovery boot - // mode would use the same init binary, which would mean during normal boot - // the '/init' binary is actually a symlink pointing to - // init_second_stage.recovery, which would be compiled with - // __ANDROID_RECOVERY__ defined. - return fs_mgr_access("/system/bin/recovery"); -} - -bool fs_mgr_is_dsu_running() { - // Since android::gsi::CanBootIntoGsi() or android::gsi::MarkSystemAsGsi() is - // never called in recovery, the return value of android::gsi::IsGsiRunning() - // is not well-defined. In this case, just return false as being in recovery - // implies not running a DSU system. - if (fs_mgr_in_recovery()) return false; - return android::gsi::IsGsiRunning(); -} - -// list of acceptable overlayfs backing storage -const auto kScratchMountPoint = "/mnt/scratch"; -const auto kCacheMountPoint = "/cache"; - -bool IsABDevice() { - return !android::base::GetProperty("ro.boot.slot_suffix", "").empty(); -} - -std::vector OverlayMountPoints() { - // Never fallback to legacy cache mount point if within a DSU system, - // because running a DSU system implies the device supports dynamic - // partitions, which means legacy cache mustn't be used. - if (fs_mgr_is_dsu_running()) { - return {kScratchMountPoint}; - } - - // For non-A/B devices prefer cache backing storage if - // kPreferCacheBackingStorageProp property set. - if (!IsABDevice() && android::base::GetBoolProperty(kPreferCacheBackingStorageProp, false) && - android::base::GetIntProperty("ro.vendor.api_level", -1) < __ANDROID_API_T__) { - return {kCacheMountPoint, kScratchMountPoint}; - } - - return {kScratchMountPoint, kCacheMountPoint}; -} // Return true if everything is mounted, but before adb is started. Right // after 'trigger load_persist_props_action' is done. -bool fs_mgr_boot_completed() { +static bool fs_mgr_boot_completed() { return android::base::GetBoolProperty("ro.persistent_properties.ready", false); } -bool fs_mgr_is_dir(const std::string& path) { - struct stat st; - return !stat(path.c_str(), &st) && S_ISDIR(st.st_mode); -} - -bool fs_mgr_rw_access(const std::string& path) { - if (path.empty()) return false; - return access(path.c_str(), R_OK | W_OK) == 0; -} - -// At less than 1% or 8MB of free space return value of false, -// means we will try to wrap with overlayfs. -bool fs_mgr_filesystem_has_space(const std::string& mount_point) { - // If we have access issues to find out space remaining, return true - // to prevent us trying to override with overlayfs. - struct statvfs vst; - if (statvfs(mount_point.c_str(), &vst)) { - PLOG(ERROR) << "statvfs " << mount_point; - return true; - } - - static constexpr int kPercentThreshold = 1; // 1% - static constexpr unsigned long kSizeThreshold = 8 * 1024 * 1024; // 8MB - - return (vst.f_bfree >= (vst.f_blocks * kPercentThreshold / 100)) && - (static_cast(vst.f_bfree) * vst.f_frsize) >= kSizeThreshold; -} - -const auto kPhysicalDevice = "/dev/block/by-name/"; +constexpr auto kPhysicalDevice = "/dev/block/by-name/"; constexpr char kScratchImageMetadata[] = "/metadata/gsi/remount/lp_metadata"; // Note: this is meant only for recovery/first-stage init. -bool ScratchIsOnData() { +static bool ScratchIsOnData() { // The scratch partition of DSU is managed by gsid. if (fs_mgr_is_dsu_running()) { return false; @@ -170,97 +89,7 @@ bool ScratchIsOnData() { return fs_mgr_access(kScratchImageMetadata); } -bool fs_mgr_update_blk_device(FstabEntry* entry) { - if (entry->fs_mgr_flags.logical) { - fs_mgr_update_logical_partition(entry); - } - if (fs_mgr_access(entry->blk_device)) { - return true; - } - if (entry->blk_device != "/dev/root") { - return false; - } - - // special case for system-as-root (taimen and others) - auto blk_device = std::string(kPhysicalDevice) + "system"; - if (!fs_mgr_access(blk_device)) { - blk_device += fs_mgr_get_slot_suffix(); - if (!fs_mgr_access(blk_device)) { - return false; - } - } - entry->blk_device = blk_device; - return true; -} - -bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev) { - struct statfs fs; - if ((statfs((mount_point + "/lost+found").c_str(), &fs) == -1) || - (fs.f_type != EXT4_SUPER_MAGIC)) { - return false; - } - - android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC)); - if (fd < 0) return false; - - struct ext4_super_block sb; - if ((TEMP_FAILURE_RETRY(lseek64(fd, 1024, SEEK_SET)) < 0) || - (TEMP_FAILURE_RETRY(read(fd, &sb, sizeof(sb))) < 0)) { - return false; - } - - struct fs_info info; - if (ext4_parse_sb(&sb, &info) < 0) return false; - - return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0; -} - -#define F2FS_SUPER_OFFSET 1024 -#define F2FS_FEATURE_OFFSET 2180 -#define F2FS_FEATURE_RO 0x4000 -bool fs_mgr_is_read_only_f2fs(const std::string& dev) { - if (!fs_mgr_is_f2fs(dev)) return false; - - android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC)); - if (fd < 0) return false; - - __le32 feat; - if ((TEMP_FAILURE_RETRY(lseek64(fd, F2FS_SUPER_OFFSET + F2FS_FEATURE_OFFSET, SEEK_SET)) < 0) || - (TEMP_FAILURE_RETRY(read(fd, &feat, sizeof(feat))) < 0)) { - return false; - } - - return (feat & cpu_to_le32(F2FS_FEATURE_RO)) != 0; -} - -bool fs_mgr_overlayfs_enabled(FstabEntry* entry) { - // readonly filesystem, can not be mount -o remount,rw - // for squashfs, erofs or if free space is (near) zero making such a remount - // virtually useless, or if there are shared blocks that prevent remount,rw - if (!fs_mgr_filesystem_has_space(entry->mount_point)) { - return true; - } - - // blk_device needs to be setup so we can check superblock. - // If we fail here, because during init first stage and have doubts. - if (!fs_mgr_update_blk_device(entry)) { - return true; - } - - // f2fs read-only mode doesn't support remount,rw - if (fs_mgr_is_read_only_f2fs(entry->blk_device)) { - return true; - } - - // check if ext4 de-dupe - auto has_shared_blocks = fs_mgr_has_shared_blocks(entry->mount_point, entry->blk_device); - if (!has_shared_blocks && (entry->mount_point == "/system")) { - has_shared_blocks = fs_mgr_has_shared_blocks("/", entry->blk_device); - } - return has_shared_blocks; -} - -bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int level = 0) { +static bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int level = 0) { std::unique_ptr dir(opendir(path.c_str()), closedir); if (!dir) { if (errno == ENOENT) { @@ -301,96 +130,6 @@ bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int level = return ret; } -const auto kUpperName = "upper"; -const auto kWorkName = "work"; -const auto kOverlayTopDir = "/overlay"; - -std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point) { - if (!fs_mgr_is_dir(mount_point)) return ""; - const auto base = android::base::Basename(mount_point) + "/"; - for (const auto& overlay_mount_point : OverlayMountPoints()) { - auto dir = overlay_mount_point + kOverlayTopDir + "/" + base; - auto upper = dir + kUpperName; - if (!fs_mgr_is_dir(upper)) continue; - auto work = dir + kWorkName; - if (!fs_mgr_is_dir(work)) continue; - if (!fs_mgr_rw_access(work)) continue; - return dir; - } - return ""; -} - -static inline bool KernelSupportsUserXattrs() { - struct utsname uts; - uname(&uts); - - int major, minor; - if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) { - return false; - } - return major > 5 || (major == 5 && minor >= 15); -} - -const std::string fs_mgr_mount_point(const std::string& mount_point) { - if ("/"s != mount_point) return mount_point; - return "/system"; -} - -// default options for mount_point, returns empty string for none available. -std::string fs_mgr_get_overlayfs_options(const FstabEntry& entry) { - const auto mount_point = fs_mgr_mount_point(entry.mount_point); - auto candidate = fs_mgr_get_overlayfs_candidate(mount_point); - if (candidate.empty()) return ""; - auto ret = kLowerdirOption + mount_point + "," + kUpperdirOption + candidate + kUpperName + - ",workdir=" + candidate + kWorkName; - if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kOverrideCredsRequired) { - ret += ",override_creds=off"; - } - if (KernelSupportsUserXattrs()) { - ret += ",userxattr"; - } - for (const auto& flag : android::base::Split(entry.fs_options, ",")) { - if (android::base::StartsWith(flag, "context=")) { - ret += "," + flag; - } - } - return ret; -} - -constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0"; - -class AutoSetFsCreateCon final { - public: - AutoSetFsCreateCon() {} - AutoSetFsCreateCon(const std::string& context) { Set(context); } - ~AutoSetFsCreateCon() { Restore(); } - - bool Ok() const { return ok_; } - bool Set(const std::string& context) { - if (setfscreatecon(context.c_str())) { - PLOG(ERROR) << "setfscreatecon " << context; - return false; - } - ok_ = true; - return true; - } - bool Restore() { - if (restored_ || !ok_) { - return true; - } - if (setfscreatecon(nullptr)) { - PLOG(ERROR) << "setfscreatecon null"; - return false; - } - restored_ = true; - return true; - } - - private: - bool ok_ = false; - bool restored_ = false; -}; - std::string fs_mgr_overlayfs_setup_dir(const std::string& dir) { auto top = dir + kOverlayTopDir; @@ -452,15 +191,15 @@ bool fs_mgr_overlayfs_setup_one(const std::string& overlay, const std::string& m return true; } -uint32_t fs_mgr_overlayfs_slot_number() { +static uint32_t fs_mgr_overlayfs_slot_number() { return SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix()); } -std::string fs_mgr_overlayfs_super_device(uint32_t slot_number) { +static std::string fs_mgr_overlayfs_super_device(uint32_t slot_number) { return kPhysicalDevice + fs_mgr_get_super_partition_name(slot_number); } -bool fs_mgr_overlayfs_has_logical(const Fstab& fstab) { +static bool fs_mgr_overlayfs_has_logical(const Fstab& fstab) { for (const auto& entry : fstab) { if (entry.fs_mgr_flags.logical) { return true; @@ -469,18 +208,6 @@ bool fs_mgr_overlayfs_has_logical(const Fstab& fstab) { return false; } -// Returns true if immediate unmount succeeded and the scratch mount point was -// removed. -bool fs_mgr_overlayfs_umount_scratch() { - if (umount(kScratchMountPoint) != 0) { - return false; - } - if (rmdir(kScratchMountPoint) != 0 && errno != ENOENT) { - PLOG(ERROR) << "rmdir " << kScratchMountPoint; - } - return true; -} - OverlayfsTeardownResult TeardownDataScratch(IImageManager* images, const std::string& partition_name, bool was_mounted) { if (!images) { @@ -619,214 +346,6 @@ bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string return ret; } -bool fs_mgr_overlayfs_set_shared_mount(const std::string& mount_point, bool shared_flag) { - auto ret = mount(nullptr, mount_point.c_str(), nullptr, shared_flag ? MS_SHARED : MS_PRIVATE, - nullptr); - if (ret) { - PERROR << "__mount(target=" << mount_point - << ",flag=" << (shared_flag ? "MS_SHARED" : "MS_PRIVATE") << ")=" << ret; - // If "/system" doesn't look like a mountpoint, retry with "/". - if (errno == EINVAL && mount_point == "/system") { - return fs_mgr_overlayfs_set_shared_mount("/", shared_flag); - } - return false; - } - return true; -} - -bool fs_mgr_overlayfs_move_mount(const std::string& source, const std::string& target) { - auto ret = mount(source.c_str(), target.c_str(), nullptr, MS_MOVE, nullptr); - if (ret) { - PERROR << "__mount(source=" << source << ",target=" << target << ",flag=MS_MOVE)=" << ret; - return false; - } - return true; -} - -struct mount_info { - std::string mount_point; - bool shared_flag; -}; - -std::vector ReadMountinfoFromFile(const std::string& path) { - std::vector info; - - auto file = std::unique_ptr{fopen(path.c_str(), "re"), fclose}; - if (!file) { - PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'"; - return info; - } - - ssize_t len; - size_t alloc_len = 0; - char* line = nullptr; - while ((len = getline(&line, &alloc_len, file.get())) != -1) { - /* if the last character is a newline, shorten the string by 1 byte */ - if (line[len - 1] == '\n') { - line[len - 1] = '\0'; - } - - static constexpr char delim[] = " \t"; - char* save_ptr; - if (!strtok_r(line, delim, &save_ptr)) { - LERROR << "Error parsing mount ID"; - break; - } - if (!strtok_r(nullptr, delim, &save_ptr)) { - LERROR << "Error parsing parent ID"; - break; - } - if (!strtok_r(nullptr, delim, &save_ptr)) { - LERROR << "Error parsing mount source"; - break; - } - if (!strtok_r(nullptr, delim, &save_ptr)) { - LERROR << "Error parsing root"; - break; - } - - char* p; - if (!(p = strtok_r(nullptr, delim, &save_ptr))) { - LERROR << "Error parsing mount_point"; - break; - } - mount_info entry = {p, false}; - - if (!strtok_r(nullptr, delim, &save_ptr)) { - LERROR << "Error parsing mount_flags"; - break; - } - - while ((p = strtok_r(nullptr, delim, &save_ptr))) { - if ((p[0] == '-') && (p[1] == '\0')) break; - if (android::base::StartsWith(p, "shared:")) entry.shared_flag = true; - } - if (!p) { - LERROR << "Error parsing fields"; - break; - } - info.emplace_back(std::move(entry)); - } - - free(line); - if (info.empty()) { - LERROR << __FUNCTION__ << "(): failed to load mountinfo from : '" << path << "'"; - } - return info; -} - -bool fs_mgr_overlayfs_mount(const FstabEntry& entry) { - const auto mount_point = fs_mgr_mount_point(entry.mount_point); - const auto options = fs_mgr_get_overlayfs_options(entry); - if (options.empty()) return false; - - auto retval = true; - - struct move_entry { - std::string mount_point; - std::string dir; - bool shared_flag; - }; - std::vector move; - auto parent_private = false; - auto parent_made_private = false; - auto dev_private = false; - auto dev_made_private = false; - for (auto& entry : ReadMountinfoFromFile("/proc/self/mountinfo")) { - if ((entry.mount_point == mount_point) && !entry.shared_flag) { - parent_private = true; - } - if ((entry.mount_point == "/dev") && !entry.shared_flag) { - dev_private = true; - } - - if (!android::base::StartsWith(entry.mount_point, mount_point + "/")) { - continue; - } - if (std::find_if(move.begin(), move.end(), [&entry](const auto& it) { - return android::base::StartsWith(entry.mount_point, it.mount_point + "/"); - }) != move.end()) { - continue; - } - - // use as the bound directory in /dev. - AutoSetFsCreateCon createcon; - auto new_context = fs_mgr_get_context(entry.mount_point); - if (new_context.empty() || !createcon.Set(new_context)) { - continue; - } - move_entry new_entry = {std::move(entry.mount_point), "/dev/TemporaryDir-XXXXXX", - entry.shared_flag}; - const auto target = mkdtemp(new_entry.dir.data()); - if (!createcon.Restore()) { - return false; - } - if (!target) { - retval = false; - PERROR << "temporary directory for MS_BIND"; - continue; - } - - if (!parent_private && !parent_made_private) { - parent_made_private = fs_mgr_overlayfs_set_shared_mount(mount_point, false); - } - if (new_entry.shared_flag) { - new_entry.shared_flag = fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, false); - } - if (!fs_mgr_overlayfs_move_mount(new_entry.mount_point, new_entry.dir)) { - retval = false; - if (new_entry.shared_flag) { - fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, true); - } - continue; - } - move.emplace_back(std::move(new_entry)); - } - - // hijack __mount() report format to help triage - auto report = "__mount(source=overlay,target="s + mount_point + ",type=overlay"; - const auto opt_list = android::base::Split(options, ","); - for (const auto& opt : opt_list) { - if (android::base::StartsWith(opt, kUpperdirOption)) { - report = report + "," + opt; - break; - } - } - report = report + ")="; - - auto ret = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME, - options.c_str()); - if (ret) { - retval = false; - PERROR << report << ret; - } else { - LINFO << report << ret; - } - - // Move submounts back. - for (const auto& entry : move) { - if (!dev_private && !dev_made_private) { - dev_made_private = fs_mgr_overlayfs_set_shared_mount("/dev", false); - } - - if (!fs_mgr_overlayfs_move_mount(entry.dir, entry.mount_point)) { - retval = false; - } else if (entry.shared_flag && - !fs_mgr_overlayfs_set_shared_mount(entry.mount_point, true)) { - retval = false; - } - rmdir(entry.dir.c_str()); - } - if (dev_made_private) { - fs_mgr_overlayfs_set_shared_mount("/dev", true); - } - if (parent_made_private) { - fs_mgr_overlayfs_set_shared_mount(mount_point, true); - } - - return retval; -} - // Mount kScratchMountPoint bool MountScratch(const std::string& device_path, bool readonly = false) { if (readonly) { @@ -1010,21 +529,7 @@ static bool CreateDynamicScratch(std::string* scratch_device, bool* partition_ex auto partition_size = builder->AllocatableSpace() - builder->UsedSpace() + partition->size(); if ((partition_size > kMinimumSize) || !partition->size()) { - // Leave some space for free space jitter of a few erase - // blocks, in case they are needed for any individual updates - // to any other partition that needs to be flashed while - // overlayfs is in force. Of course if margin_size is not - // enough could normally get a flash failure, so - // ResizePartition() will delete the scratch partition in - // order to fulfill. Deleting scratch will destroy all of - // the adb remount overrides :-( . - auto margin_size = uint64_t(3 * 256 * 1024); - BlockDeviceInfo info; - if (builder->GetBlockDeviceInfo(fs_mgr_get_super_partition_name(slot_number), &info)) { - margin_size = 3 * info.logical_block_size; - } - partition_size = std::max(std::min(kMinimumSize, partition_size - margin_size), - partition_size / 2); + partition_size = std::max(std::min(kMinimumSize, partition_size), partition_size / 2); if (partition_size > partition->size()) { if (!builder->ResizePartition(partition, partition_size)) { // Try to free up space by deallocating partitions in the other slot. @@ -1032,8 +537,8 @@ static bool CreateDynamicScratch(std::string* scratch_device, bool* partition_ex partition_size = builder->AllocatableSpace() - builder->UsedSpace() + partition->size(); - partition_size = std::max(std::min(kMinimumSize, partition_size - margin_size), - partition_size / 2); + partition_size = + std::max(std::min(kMinimumSize, partition_size), partition_size / 2); if (!builder->ResizePartition(partition, partition_size)) { LERROR << "resize " << partition_name; return false; @@ -1212,12 +717,6 @@ bool fs_mgr_overlayfs_setup_scratch(const Fstab& fstab) { return MountScratch(scratch_device); } -#if ALLOW_ADBD_DISABLE_VERITY -constexpr bool kAllowOverlayfs = true; -#else -constexpr bool kAllowOverlayfs = false; -#endif - // NOTE: OverlayfsSetupAllowed() must be "stricter" than OverlayfsTeardownAllowed(). // Setup is allowed only if teardown is also allowed. bool OverlayfsSetupAllowed(bool verbose = false) { @@ -1251,114 +750,6 @@ constexpr bool OverlayfsTeardownAllowed() { } // namespace -bool fs_mgr_wants_overlayfs(FstabEntry* entry) { - // Don't check entries that are managed by vold. - if (entry->fs_mgr_flags.vold_managed || entry->fs_mgr_flags.recovery_only) return false; - - // *_other doesn't want overlayfs. - if (entry->fs_mgr_flags.slot_select_other) return false; - - // Only concerned with readonly partitions. - if (!(entry->flags & MS_RDONLY)) return false; - - // If unbindable, do not allow overlayfs as this could expose us to - // security issues. On Android, this could also be used to turn off - // the ability to overlay an otherwise acceptable filesystem since - // /system and /vendor are never bound(sic) to. - if (entry->flags & MS_UNBINDABLE) return false; - - if (!fs_mgr_overlayfs_enabled(entry)) return false; - - return true; -} - -Fstab fs_mgr_overlayfs_candidate_list(const Fstab& fstab) { - android::fs_mgr::Fstab mounts; - if (!android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts)) { - PLOG(ERROR) << "Failed to read /proc/mounts"; - return {}; - } - - Fstab candidates; - for (const auto& entry : fstab) { - // Filter out partitions whose type doesn't match what's mounted. - // This avoids spammy behavior on devices which can mount different - // filesystems for each partition. - auto proc_mount_point = (entry.mount_point == "/system") ? "/" : entry.mount_point; - auto mounted = GetEntryForMountPoint(&mounts, proc_mount_point); - if (!mounted || mounted->fs_type != entry.fs_type) { - continue; - } - - FstabEntry new_entry = entry; - if (!fs_mgr_overlayfs_already_mounted(entry.mount_point) && - !fs_mgr_wants_overlayfs(&new_entry)) { - continue; - } - auto new_mount_point = fs_mgr_mount_point(entry.mount_point); - auto duplicate_or_more_specific = false; - for (auto it = candidates.begin(); it != candidates.end();) { - auto it_mount_point = fs_mgr_mount_point(it->mount_point); - if ((it_mount_point == new_mount_point) || - (android::base::StartsWith(new_mount_point, it_mount_point + "/"))) { - duplicate_or_more_specific = true; - break; - } - if (android::base::StartsWith(it_mount_point, new_mount_point + "/")) { - it = candidates.erase(it); - } else { - ++it; - } - } - if (!duplicate_or_more_specific) candidates.emplace_back(std::move(new_entry)); - } - return candidates; -} - -static void TryMountScratch() { - // Note we get the boot scratch device here, which means if scratch was - // just created through ImageManager, this could fail. In practice this - // should not happen because "remount" detects this scenario (by checking - // if verity is still disabled, i.e. no reboot occurred), and skips calling - // fs_mgr_overlayfs_mount_all(). - auto scratch_device = GetBootScratchDevice(); - if (!fs_mgr_rw_access(scratch_device)) { - return; - } - if (!WaitForFile(scratch_device, 10s)) { - return; - } - if (!MountScratch(scratch_device, true /* readonly */)) { - return; - } - auto has_overlayfs_dir = fs_mgr_access(std::string(kScratchMountPoint) + kOverlayTopDir); - fs_mgr_overlayfs_umount_scratch(); - if (has_overlayfs_dir) { - MountScratch(scratch_device); - } -} - -bool fs_mgr_overlayfs_mount_all(Fstab* fstab) { - if (!OverlayfsSetupAllowed()) { - return false; - } - auto ret = true; - auto scratch_can_be_mounted = true; - for (const auto& entry : fs_mgr_overlayfs_candidate_list(*fstab)) { - if (fs_mgr_is_verity_enabled(entry)) continue; - auto mount_point = fs_mgr_mount_point(entry.mount_point); - if (fs_mgr_overlayfs_already_mounted(mount_point)) { - continue; - } - if (scratch_can_be_mounted) { - scratch_can_be_mounted = false; - TryMountScratch(); - } - ret &= fs_mgr_overlayfs_mount(entry); - } - return ret; -} - bool fs_mgr_overlayfs_setup(const Fstab& fstab, const char* mount_point, bool* want_reboot, bool just_disabled_verity) { if (!OverlayfsSetupAllowed(/*verbose=*/true)) { @@ -1582,22 +973,6 @@ OverlayfsTeardownResult fs_mgr_overlayfs_teardown(const char* mount_point, bool* return rv; } -bool fs_mgr_overlayfs_is_setup() { - if (!OverlayfsSetupAllowed()) { - return false; - } - if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true; - Fstab fstab; - if (!ReadDefaultFstab(&fstab)) { - return false; - } - for (const auto& entry : fs_mgr_overlayfs_candidate_list(fstab)) { - if (fs_mgr_is_verity_enabled(entry)) continue; - if (fs_mgr_overlayfs_already_mounted(fs_mgr_mount_point(entry.mount_point))) return true; - } - return false; -} - namespace android { namespace fs_mgr { @@ -1714,23 +1089,3 @@ void TeardownAllOverlayForMountPoint(const std::string& mount_point) { } // namespace fs_mgr } // namespace android - -bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only) { - Fstab fstab; - if (!ReadFstabFromFile("/proc/mounts", &fstab)) { - return false; - } - const auto lowerdir = kLowerdirOption + mount_point; - for (const auto& entry : fstab) { - if (overlay_only && "overlay" != entry.fs_type && "overlayfs" != entry.fs_type) continue; - if (mount_point != entry.mount_point) continue; - if (!overlay_only) return true; - const auto options = android::base::Split(entry.fs_options, ","); - for (const auto& opt : options) { - if (opt == lowerdir) { - return true; - } - } - } - return false; -} diff --git a/fs_mgr/fs_mgr_priv_overlayfs.h b/fs_mgr/fs_mgr_overlayfs_control.h similarity index 53% rename from fs_mgr/fs_mgr_priv_overlayfs.h rename to fs_mgr/fs_mgr_overlayfs_control.h index 2033701d9a58..50e83e8a30ef 100644 --- a/fs_mgr/fs_mgr_priv_overlayfs.h +++ b/fs_mgr/fs_mgr_overlayfs_control.h @@ -1,18 +1,16 @@ -/* - * Copyright (C) 2022 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. - */ +// Copyright (C) 2023 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. #pragma once @@ -20,11 +18,8 @@ #include -bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true); -bool fs_mgr_wants_overlayfs(android::fs_mgr::FstabEntry* entry); -android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab); - // If "mount_point" is non-null, set up exactly one overlay. +// // If "mount_point" is null, setup any overlays. // // If |want_reboot| is non-null, and a reboot is needed to apply overlays, then diff --git a/fs_mgr/fs_mgr_overlayfs_mount.cpp b/fs_mgr/fs_mgr_overlayfs_mount.cpp new file mode 100644 index 000000000000..c057c2bc1369 --- /dev/null +++ b/fs_mgr/fs_mgr_overlayfs_mount.cpp @@ -0,0 +1,802 @@ +/* + * Copyright (C) 2018 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fs_mgr_overlayfs_mount.h" +#include "fs_mgr_priv.h" + +using namespace std::literals; +using namespace android::dm; +using namespace android::fs_mgr; +using namespace android::storage_literals; + +constexpr char kPreferCacheBackingStorageProp[] = "fs_mgr.overlayfs.prefer_cache_backing_storage"; + +bool fs_mgr_access(const std::string& path) { + return access(path.c_str(), F_OK) == 0; +} + +const auto kLowerdirOption = "lowerdir="; +const auto kUpperdirOption = "upperdir="; + +bool fs_mgr_in_recovery() { + // Check the existence of recovery binary instead of using the compile time + // __ANDROID_RECOVERY__ macro. + // If BOARD_USES_RECOVERY_AS_BOOT is true, both normal and recovery boot + // mode would use the same init binary, which would mean during normal boot + // the '/init' binary is actually a symlink pointing to + // init_second_stage.recovery, which would be compiled with + // __ANDROID_RECOVERY__ defined. + return fs_mgr_access("/system/bin/recovery"); +} + +bool fs_mgr_is_dsu_running() { + // Since android::gsi::CanBootIntoGsi() or android::gsi::MarkSystemAsGsi() is + // never called in recovery, the return value of android::gsi::IsGsiRunning() + // is not well-defined. In this case, just return false as being in recovery + // implies not running a DSU system. + if (fs_mgr_in_recovery()) return false; + return android::gsi::IsGsiRunning(); +} + +const auto kCacheMountPoint = "/cache"; + +static bool IsABDevice() { + return !android::base::GetProperty("ro.boot.slot_suffix", "").empty(); +} + +std::vector OverlayMountPoints() { + // Never fallback to legacy cache mount point if within a DSU system, + // because running a DSU system implies the device supports dynamic + // partitions, which means legacy cache mustn't be used. + if (fs_mgr_is_dsu_running()) { + return {kScratchMountPoint}; + } + + // For non-A/B devices prefer cache backing storage if + // kPreferCacheBackingStorageProp property set. + if (!IsABDevice() && android::base::GetBoolProperty(kPreferCacheBackingStorageProp, false) && + android::base::GetIntProperty("ro.vendor.api_level", -1) < __ANDROID_API_T__) { + return {kCacheMountPoint, kScratchMountPoint}; + } + + return {kScratchMountPoint, kCacheMountPoint}; +} + +static bool fs_mgr_is_dir(const std::string& path) { + struct stat st; + return !stat(path.c_str(), &st) && S_ISDIR(st.st_mode); +} + +bool fs_mgr_rw_access(const std::string& path) { + if (path.empty()) return false; + return access(path.c_str(), R_OK | W_OK) == 0; +} + +// At less than 1% or 8MB of free space return value of false, +// means we will try to wrap with overlayfs. +bool fs_mgr_filesystem_has_space(const std::string& mount_point) { + // If we have access issues to find out space remaining, return true + // to prevent us trying to override with overlayfs. + struct statvfs vst; + if (statvfs(mount_point.c_str(), &vst)) { + PLOG(ERROR) << "statvfs " << mount_point; + return true; + } + + static constexpr int kPercentThreshold = 1; // 1% + static constexpr unsigned long kSizeThreshold = 8 * 1024 * 1024; // 8MB + + return (vst.f_bfree >= (vst.f_blocks * kPercentThreshold / 100)) && + (static_cast(vst.f_bfree) * vst.f_frsize) >= kSizeThreshold; +} + +const auto kPhysicalDevice = "/dev/block/by-name/"; + +static bool fs_mgr_update_blk_device(FstabEntry* entry) { + if (entry->fs_mgr_flags.logical) { + fs_mgr_update_logical_partition(entry); + } + if (fs_mgr_access(entry->blk_device)) { + return true; + } + if (entry->blk_device != "/dev/root") { + return false; + } + + // special case for system-as-root (taimen and others) + auto blk_device = std::string(kPhysicalDevice) + "system"; + if (!fs_mgr_access(blk_device)) { + blk_device += fs_mgr_get_slot_suffix(); + if (!fs_mgr_access(blk_device)) { + return false; + } + } + entry->blk_device = blk_device; + return true; +} + +static bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev) { + struct statfs fs; + if ((statfs((mount_point + "/lost+found").c_str(), &fs) == -1) || + (fs.f_type != EXT4_SUPER_MAGIC)) { + return false; + } + + android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC)); + if (fd < 0) return false; + + struct ext4_super_block sb; + if ((TEMP_FAILURE_RETRY(lseek64(fd, 1024, SEEK_SET)) < 0) || + (TEMP_FAILURE_RETRY(read(fd, &sb, sizeof(sb))) < 0)) { + return false; + } + + struct fs_info info; + if (ext4_parse_sb(&sb, &info) < 0) return false; + + return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0; +} + +#define F2FS_SUPER_OFFSET 1024 +#define F2FS_FEATURE_OFFSET 2180 +#define F2FS_FEATURE_RO 0x4000 +static bool fs_mgr_is_read_only_f2fs(const std::string& dev) { + if (!fs_mgr_is_f2fs(dev)) return false; + + android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC)); + if (fd < 0) return false; + + __le32 feat; + if ((TEMP_FAILURE_RETRY(lseek64(fd, F2FS_SUPER_OFFSET + F2FS_FEATURE_OFFSET, SEEK_SET)) < 0) || + (TEMP_FAILURE_RETRY(read(fd, &feat, sizeof(feat))) < 0)) { + return false; + } + + return (feat & cpu_to_le32(F2FS_FEATURE_RO)) != 0; +} + +static bool fs_mgr_overlayfs_enabled(FstabEntry* entry) { + // readonly filesystem, can not be mount -o remount,rw + // for squashfs, erofs or if free space is (near) zero making such a remount + // virtually useless, or if there are shared blocks that prevent remount,rw + if (!fs_mgr_filesystem_has_space(entry->mount_point)) { + return true; + } + + // blk_device needs to be setup so we can check superblock. + // If we fail here, because during init first stage and have doubts. + if (!fs_mgr_update_blk_device(entry)) { + return true; + } + + // f2fs read-only mode doesn't support remount,rw + if (fs_mgr_is_read_only_f2fs(entry->blk_device)) { + return true; + } + + // check if ext4 de-dupe + auto has_shared_blocks = fs_mgr_has_shared_blocks(entry->mount_point, entry->blk_device); + if (!has_shared_blocks && (entry->mount_point == "/system")) { + has_shared_blocks = fs_mgr_has_shared_blocks("/", entry->blk_device); + } + return has_shared_blocks; +} + +static std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point) { + if (!fs_mgr_is_dir(mount_point)) return ""; + const auto base = android::base::Basename(mount_point) + "/"; + for (const auto& overlay_mount_point : OverlayMountPoints()) { + auto dir = overlay_mount_point + kOverlayTopDir + "/" + base; + auto upper = dir + kUpperName; + if (!fs_mgr_is_dir(upper)) continue; + auto work = dir + kWorkName; + if (!fs_mgr_is_dir(work)) continue; + if (!fs_mgr_rw_access(work)) continue; + return dir; + } + return ""; +} + +static inline bool KernelSupportsUserXattrs() { + struct utsname uts; + uname(&uts); + + int major, minor; + if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) { + return false; + } + return major > 5 || (major == 5 && minor >= 15); +} + +const std::string fs_mgr_mount_point(const std::string& mount_point) { + if ("/"s != mount_point) return mount_point; + return "/system"; +} + +// default options for mount_point, returns empty string for none available. +static std::string fs_mgr_get_overlayfs_options(const FstabEntry& entry) { + const auto mount_point = fs_mgr_mount_point(entry.mount_point); + auto candidate = fs_mgr_get_overlayfs_candidate(mount_point); + if (candidate.empty()) return ""; + auto ret = kLowerdirOption + mount_point + "," + kUpperdirOption + candidate + kUpperName + + ",workdir=" + candidate + kWorkName; + if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kOverrideCredsRequired) { + ret += ",override_creds=off"; + } + if (KernelSupportsUserXattrs()) { + ret += ",userxattr"; + } + for (const auto& flag : android::base::Split(entry.fs_options, ",")) { + if (android::base::StartsWith(flag, "context=")) { + ret += "," + flag; + } + } + return ret; +} + +bool AutoSetFsCreateCon::Set(const std::string& context) { + if (setfscreatecon(context.c_str())) { + PLOG(ERROR) << "setfscreatecon " << context; + return false; + } + ok_ = true; + return true; +} + +bool AutoSetFsCreateCon::Restore() { + if (restored_ || !ok_) { + return true; + } + if (setfscreatecon(nullptr)) { + PLOG(ERROR) << "setfscreatecon null"; + return false; + } + restored_ = true; + return true; +} + +// Returns true if immediate unmount succeeded and the scratch mount point was +// removed. +bool fs_mgr_overlayfs_umount_scratch() { + if (umount(kScratchMountPoint) != 0) { + return false; + } + if (rmdir(kScratchMountPoint) != 0 && errno != ENOENT) { + PLOG(ERROR) << "rmdir " << kScratchMountPoint; + } + return true; +} + +static bool fs_mgr_overlayfs_set_shared_mount(const std::string& mount_point, bool shared_flag) { + auto ret = mount(nullptr, mount_point.c_str(), nullptr, shared_flag ? MS_SHARED : MS_PRIVATE, + nullptr); + if (ret) { + PERROR << "__mount(target=" << mount_point + << ",flag=" << (shared_flag ? "MS_SHARED" : "MS_PRIVATE") << ")=" << ret; + // If "/system" doesn't look like a mountpoint, retry with "/". + if (errno == EINVAL && mount_point == "/system") { + return fs_mgr_overlayfs_set_shared_mount("/", shared_flag); + } + return false; + } + return true; +} + +static bool fs_mgr_overlayfs_move_mount(const std::string& source, const std::string& target) { + auto ret = mount(source.c_str(), target.c_str(), nullptr, MS_MOVE, nullptr); + if (ret) { + PERROR << "__mount(source=" << source << ",target=" << target << ",flag=MS_MOVE)=" << ret; + return false; + } + return true; +} + +struct mount_info { + std::string mount_point; + bool shared_flag; +}; + +static std::vector ReadMountinfoFromFile(const std::string& path) { + std::vector info; + + auto file = std::unique_ptr{fopen(path.c_str(), "re"), fclose}; + if (!file) { + PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'"; + return info; + } + + ssize_t len; + size_t alloc_len = 0; + char* line = nullptr; + while ((len = getline(&line, &alloc_len, file.get())) != -1) { + /* if the last character is a newline, shorten the string by 1 byte */ + if (line[len - 1] == '\n') { + line[len - 1] = '\0'; + } + + static constexpr char delim[] = " \t"; + char* save_ptr; + if (!strtok_r(line, delim, &save_ptr)) { + LERROR << "Error parsing mount ID"; + break; + } + if (!strtok_r(nullptr, delim, &save_ptr)) { + LERROR << "Error parsing parent ID"; + break; + } + if (!strtok_r(nullptr, delim, &save_ptr)) { + LERROR << "Error parsing mount source"; + break; + } + if (!strtok_r(nullptr, delim, &save_ptr)) { + LERROR << "Error parsing root"; + break; + } + + char* p; + if (!(p = strtok_r(nullptr, delim, &save_ptr))) { + LERROR << "Error parsing mount_point"; + break; + } + mount_info entry = {p, false}; + + if (!strtok_r(nullptr, delim, &save_ptr)) { + LERROR << "Error parsing mount_flags"; + break; + } + + while ((p = strtok_r(nullptr, delim, &save_ptr))) { + if ((p[0] == '-') && (p[1] == '\0')) break; + if (android::base::StartsWith(p, "shared:")) entry.shared_flag = true; + } + if (!p) { + LERROR << "Error parsing fields"; + break; + } + info.emplace_back(std::move(entry)); + } + + free(line); + if (info.empty()) { + LERROR << __FUNCTION__ << "(): failed to load mountinfo from : '" << path << "'"; + } + return info; +} + +static bool fs_mgr_overlayfs_mount(const FstabEntry& entry) { + const auto mount_point = fs_mgr_mount_point(entry.mount_point); + const auto options = fs_mgr_get_overlayfs_options(entry); + if (options.empty()) return false; + + auto retval = true; + + struct move_entry { + std::string mount_point; + std::string dir; + bool shared_flag; + }; + std::vector move; + auto parent_private = false; + auto parent_made_private = false; + auto dev_private = false; + auto dev_made_private = false; + for (auto& entry : ReadMountinfoFromFile("/proc/self/mountinfo")) { + if ((entry.mount_point == mount_point) && !entry.shared_flag) { + parent_private = true; + } + if ((entry.mount_point == "/dev") && !entry.shared_flag) { + dev_private = true; + } + + if (!android::base::StartsWith(entry.mount_point, mount_point + "/")) { + continue; + } + if (std::find_if(move.begin(), move.end(), [&entry](const auto& it) { + return android::base::StartsWith(entry.mount_point, it.mount_point + "/"); + }) != move.end()) { + continue; + } + + // use as the bound directory in /dev. + AutoSetFsCreateCon createcon; + auto new_context = fs_mgr_get_context(entry.mount_point); + if (new_context.empty() || !createcon.Set(new_context)) { + continue; + } + move_entry new_entry = {std::move(entry.mount_point), "/dev/TemporaryDir-XXXXXX", + entry.shared_flag}; + const auto target = mkdtemp(new_entry.dir.data()); + if (!createcon.Restore()) { + return false; + } + if (!target) { + retval = false; + PERROR << "temporary directory for MS_BIND"; + continue; + } + + if (!parent_private && !parent_made_private) { + parent_made_private = fs_mgr_overlayfs_set_shared_mount(mount_point, false); + } + if (new_entry.shared_flag) { + new_entry.shared_flag = fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, false); + } + if (!fs_mgr_overlayfs_move_mount(new_entry.mount_point, new_entry.dir)) { + retval = false; + if (new_entry.shared_flag) { + fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, true); + } + continue; + } + move.emplace_back(std::move(new_entry)); + } + + // hijack __mount() report format to help triage + auto report = "__mount(source=overlay,target="s + mount_point + ",type=overlay"; + const auto opt_list = android::base::Split(options, ","); + for (const auto& opt : opt_list) { + if (android::base::StartsWith(opt, kUpperdirOption)) { + report = report + "," + opt; + break; + } + } + report = report + ")="; + + auto ret = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME, + options.c_str()); + if (ret) { + retval = false; + PERROR << report << ret; + } else { + LINFO << report << ret; + } + + // Move submounts back. + for (const auto& entry : move) { + if (!dev_private && !dev_made_private) { + dev_made_private = fs_mgr_overlayfs_set_shared_mount("/dev", false); + } + + if (!fs_mgr_overlayfs_move_mount(entry.dir, entry.mount_point)) { + retval = false; + } else if (entry.shared_flag && + !fs_mgr_overlayfs_set_shared_mount(entry.mount_point, true)) { + retval = false; + } + rmdir(entry.dir.c_str()); + } + if (dev_made_private) { + fs_mgr_overlayfs_set_shared_mount("/dev", true); + } + if (parent_made_private) { + fs_mgr_overlayfs_set_shared_mount(mount_point, true); + } + + return retval; +} + +// Mount kScratchMountPoint +static bool MountScratch(const std::string& device_path, bool readonly = false) { + if (readonly) { + if (!fs_mgr_access(device_path)) { + LOG(ERROR) << "Path does not exist: " << device_path; + return false; + } + } else if (!fs_mgr_rw_access(device_path)) { + LOG(ERROR) << "Path does not exist or is not readwrite: " << device_path; + return false; + } + + std::vector filesystem_candidates; + if (fs_mgr_is_f2fs(device_path)) { + filesystem_candidates = {"f2fs", "ext4"}; + } else if (fs_mgr_is_ext4(device_path)) { + filesystem_candidates = {"ext4", "f2fs"}; + } else { + LOG(ERROR) << "Scratch partition is not f2fs or ext4"; + return false; + } + + AutoSetFsCreateCon createcon(kOverlayfsFileContext); + if (!createcon.Ok()) { + return false; + } + if (mkdir(kScratchMountPoint, 0755) && (errno != EEXIST)) { + PERROR << "create " << kScratchMountPoint; + return false; + } + + FstabEntry entry; + entry.blk_device = device_path; + entry.mount_point = kScratchMountPoint; + entry.flags = MS_NOATIME | MS_RDONLY; + if (!readonly) { + entry.flags &= ~MS_RDONLY; + entry.flags |= MS_SYNCHRONOUS; + entry.fs_options = "nodiscard"; + fs_mgr_set_blk_ro(device_path, false); + } + // check_fs requires apex runtime library + if (fs_mgr_overlayfs_already_mounted("/data", false)) { + entry.fs_mgr_flags.check = true; + } + bool mounted = false; + for (auto fs_type : filesystem_candidates) { + entry.fs_type = fs_type; + if (fs_mgr_do_mount_one(entry) == 0) { + mounted = true; + break; + } + } + if (!createcon.Restore()) { + return false; + } + if (!mounted) { + rmdir(kScratchMountPoint); + return false; + } + return true; +} + +const std::string kMkF2fs("/system/bin/make_f2fs"); +const std::string kMkExt4("/system/bin/mke2fs"); + +// Note: The scratch partition of DSU is managed by gsid, and should be initialized during +// first-stage-mount. Just check if the DM device for DSU scratch partition is created or not. +static std::string GetDsuScratchDevice() { + auto& dm = DeviceMapper::Instance(); + std::string device; + if (dm.GetState(android::gsi::kDsuScratch) != DmDeviceState::INVALID && + dm.GetDmDevicePathByName(android::gsi::kDsuScratch, &device)) { + return device; + } + return ""; +} + +// This returns the scratch device that was detected during early boot (first- +// stage init). If the device was created later, for example during setup for +// the adb remount command, it can return an empty string since it does not +// query ImageManager. (Note that ImageManager in first-stage init will always +// use device-mapper, since /data is not available to use loop devices.) +static std::string GetBootScratchDevice() { + // Note: fs_mgr_is_dsu_running() always returns false in recovery or fastbootd. + if (fs_mgr_is_dsu_running()) { + return GetDsuScratchDevice(); + } + + auto& dm = DeviceMapper::Instance(); + + // If there is a scratch partition allocated in /data or on super, we + // automatically prioritize that over super_other or system_other. + // Some devices, for example, have a write-protected eMMC and the + // super partition cannot be used even if it exists. + std::string device; + auto partition_name = android::base::Basename(kScratchMountPoint); + if (dm.GetState(partition_name) != DmDeviceState::INVALID && + dm.GetDmDevicePathByName(partition_name, &device)) { + return device; + } + + return ""; +} + +// NOTE: OverlayfsSetupAllowed() must be "stricter" than OverlayfsTeardownAllowed(). +// Setup is allowed only if teardown is also allowed. +bool OverlayfsSetupAllowed(bool verbose = false) { + if (!kAllowOverlayfs) { + if (verbose) { + LOG(ERROR) << "Overlayfs remounts can only be used in debuggable builds"; + } + return false; + } + // Check mandatory kernel patches. + if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) { + if (verbose) { + LOG(ERROR) << "Kernel does not support overlayfs"; + } + return false; + } + // in recovery or fastbootd, not allowed! + if (fs_mgr_in_recovery()) { + if (verbose) { + LOG(ERROR) << "Unsupported overlayfs setup from recovery"; + } + return false; + } + return true; +} + +bool fs_mgr_wants_overlayfs(FstabEntry* entry) { + // Don't check entries that are managed by vold. + if (entry->fs_mgr_flags.vold_managed || entry->fs_mgr_flags.recovery_only) return false; + + // *_other doesn't want overlayfs. + if (entry->fs_mgr_flags.slot_select_other) return false; + + // Only concerned with readonly partitions. + if (!(entry->flags & MS_RDONLY)) return false; + + // If unbindable, do not allow overlayfs as this could expose us to + // security issues. On Android, this could also be used to turn off + // the ability to overlay an otherwise acceptable filesystem since + // /system and /vendor are never bound(sic) to. + if (entry->flags & MS_UNBINDABLE) return false; + + if (!fs_mgr_overlayfs_enabled(entry)) return false; + + return true; +} + +Fstab fs_mgr_overlayfs_candidate_list(const Fstab& fstab) { + android::fs_mgr::Fstab mounts; + if (!android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts)) { + PLOG(ERROR) << "Failed to read /proc/mounts"; + return {}; + } + + Fstab candidates; + for (const auto& entry : fstab) { + // Filter out partitions whose type doesn't match what's mounted. + // This avoids spammy behavior on devices which can mount different + // filesystems for each partition. + auto proc_mount_point = (entry.mount_point == "/system") ? "/" : entry.mount_point; + auto mounted = GetEntryForMountPoint(&mounts, proc_mount_point); + if (!mounted || mounted->fs_type != entry.fs_type) { + continue; + } + + FstabEntry new_entry = entry; + if (!fs_mgr_overlayfs_already_mounted(entry.mount_point) && + !fs_mgr_wants_overlayfs(&new_entry)) { + continue; + } + auto new_mount_point = fs_mgr_mount_point(entry.mount_point); + auto duplicate_or_more_specific = false; + for (auto it = candidates.begin(); it != candidates.end();) { + auto it_mount_point = fs_mgr_mount_point(it->mount_point); + if ((it_mount_point == new_mount_point) || + (android::base::StartsWith(new_mount_point, it_mount_point + "/"))) { + duplicate_or_more_specific = true; + break; + } + if (android::base::StartsWith(it_mount_point, new_mount_point + "/")) { + it = candidates.erase(it); + } else { + ++it; + } + } + if (!duplicate_or_more_specific) candidates.emplace_back(std::move(new_entry)); + } + return candidates; +} + +static void TryMountScratch() { + // Note we get the boot scratch device here, which means if scratch was + // just created through ImageManager, this could fail. In practice this + // should not happen because "remount" detects this scenario (by checking + // if verity is still disabled, i.e. no reboot occurred), and skips calling + // fs_mgr_overlayfs_mount_all(). + auto scratch_device = GetBootScratchDevice(); + if (!fs_mgr_rw_access(scratch_device)) { + return; + } + if (!WaitForFile(scratch_device, 10s)) { + return; + } + if (!MountScratch(scratch_device, true /* readonly */)) { + return; + } + auto has_overlayfs_dir = fs_mgr_access(std::string(kScratchMountPoint) + kOverlayTopDir); + fs_mgr_overlayfs_umount_scratch(); + if (has_overlayfs_dir) { + MountScratch(scratch_device); + } +} + +bool fs_mgr_overlayfs_mount_all(Fstab* fstab) { + if (!OverlayfsSetupAllowed()) { + return false; + } + auto ret = true; + auto scratch_can_be_mounted = true; + for (const auto& entry : fs_mgr_overlayfs_candidate_list(*fstab)) { + if (fs_mgr_is_verity_enabled(entry)) continue; + auto mount_point = fs_mgr_mount_point(entry.mount_point); + if (fs_mgr_overlayfs_already_mounted(mount_point)) { + continue; + } + if (scratch_can_be_mounted) { + scratch_can_be_mounted = false; + TryMountScratch(); + } + ret &= fs_mgr_overlayfs_mount(entry); + } + return ret; +} + +bool fs_mgr_overlayfs_is_setup() { + if (!OverlayfsSetupAllowed()) { + return false; + } + if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true; + Fstab fstab; + if (!ReadDefaultFstab(&fstab)) { + return false; + } + for (const auto& entry : fs_mgr_overlayfs_candidate_list(fstab)) { + if (fs_mgr_is_verity_enabled(entry)) continue; + if (fs_mgr_overlayfs_already_mounted(fs_mgr_mount_point(entry.mount_point))) return true; + } + return false; +} + +bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only) { + Fstab fstab; + if (!ReadFstabFromFile("/proc/mounts", &fstab)) { + return false; + } + const auto lowerdir = kLowerdirOption + mount_point; + for (const auto& entry : fstab) { + if (overlay_only && "overlay" != entry.fs_type && "overlayfs" != entry.fs_type) continue; + if (mount_point != entry.mount_point) continue; + if (!overlay_only) return true; + const auto options = android::base::Split(entry.fs_options, ","); + for (const auto& opt : options) { + if (opt == lowerdir) { + return true; + } + } + } + return false; +} diff --git a/fs_mgr/fs_mgr_overlayfs_mount.h b/fs_mgr/fs_mgr_overlayfs_mount.h new file mode 100644 index 000000000000..ae3ea84edab6 --- /dev/null +++ b/fs_mgr/fs_mgr_overlayfs_mount.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 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. + */ + +#pragma once + +#include + +#include + +bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true); +bool fs_mgr_wants_overlayfs(android::fs_mgr::FstabEntry* entry); +android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab); + +#if ALLOW_ADBD_DISABLE_VERITY +constexpr bool kAllowOverlayfs = true; +#else +constexpr bool kAllowOverlayfs = false; +#endif + +class AutoSetFsCreateCon final { + public: + AutoSetFsCreateCon() {} + AutoSetFsCreateCon(const std::string& context) { Set(context); } + ~AutoSetFsCreateCon() { Restore(); } + + bool Ok() const { return ok_; } + bool Set(const std::string& context); + bool Restore(); + + private: + bool ok_ = false; + bool restored_ = false; +}; + +constexpr auto kScratchMountPoint = "/mnt/scratch"; +constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0"; + +constexpr auto kUpperName = "upper"; +constexpr auto kWorkName = "work"; +constexpr auto kOverlayTopDir = "/overlay"; + +bool fs_mgr_is_dsu_running(); +bool fs_mgr_in_recovery(); +bool fs_mgr_access(const std::string& path); +bool fs_mgr_rw_access(const std::string& path); +bool fs_mgr_filesystem_has_space(const std::string& mount_point); +const std::string fs_mgr_mount_point(const std::string& mount_point); +bool fs_mgr_overlayfs_umount_scratch(); +std::vector OverlayMountPoints(); diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp index 5a9f391a4ade..4c458283a537 100644 --- a/fs_mgr/fs_mgr_remount.cpp +++ b/fs_mgr/fs_mgr_remount.cpp @@ -43,7 +43,8 @@ #include #include -#include "fs_mgr_priv_overlayfs.h" +#include "fs_mgr_overlayfs_control.h" +#include "fs_mgr_overlayfs_mount.h" using namespace std::literals; using android::fs_mgr::Fstab; From edeae250c9f9f73212529b8717f440dc7b6dea94 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 14 Jul 2023 08:56:46 -0700 Subject: [PATCH 0193/1487] libsnapshot: Move export_include_dirs to correct location. Bug: 291083311 Test: builds Change-Id: I7a547bb0b2c06f312f83a6b8659a4e30e97c8438 --- fs_mgr/libsnapshot/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index 9d1ce7db9b79..8f353818ce08 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -166,7 +166,6 @@ cc_defaults { header_libs: [ "libupdate_engine_headers", ], - export_include_dirs: ["include"], } cc_library_static { @@ -184,6 +183,7 @@ cc_library_static { "libsnapshot_cow/writer_base.cpp", "libsnapshot_cow/writer_v2.cpp", ], + export_include_dirs: ["include"], host_supported: true, recovery_available: true, ramdisk_available: true, From a71faae86f3ff23c4400f0b1d0452b2d6d7fbe10 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 14 Jul 2023 08:57:30 -0700 Subject: [PATCH 0194/1487] Allow processes in the "system" group to read /metadata/ota. lpdumpd runs as "system", not "root". Adjust the DAC permissions of /metadata/ota so it can call SnapshotManager::Dump. Bug: 291083311 Test: lpdump Change-Id: I97fd7eb2055cf6d31fd42f1021e2f99edbdb838a --- rootdir/init.rc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 4f3959f7cdca..be03489a6d0e 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -604,8 +604,8 @@ on post-fs chmod 0700 /metadata/vold mkdir /metadata/password_slots 0771 root system mkdir /metadata/bootstat 0750 system log - mkdir /metadata/ota 0700 root system - mkdir /metadata/ota/snapshots 0700 root system + mkdir /metadata/ota 0750 root system + mkdir /metadata/ota/snapshots 0750 root system mkdir /metadata/userspacereboot 0770 root system mkdir /metadata/watchdog 0770 root system From 01cd7285ee9c6baa9954cade128e9d334e3084f2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 17 Feb 2023 01:20:52 -0800 Subject: [PATCH 0195/1487] snapuserd: Split the server into two classes. This splits server into two classes: one that handles the IPC requests, and one that managers snapshot handlers. This will allow embedding of the snapshot handling code, without booting up a server. It'll also make testing much easier. The handler code has been further placed behind a virtual interface, though this is likely unnecessary unless we start testing the server logic itself (or attempt to unify the S and T+ versions of snapuserd). Bug: 269361087 Test: ota Ignore-AOSP-First: cherry-pick from aosp (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:8bb751dc8a1499f24add9e0831ab347feb2c3878) Merged-In: I3ca3ad9c8c1fb910a1c7bf9f44165e2f44c930c9 Change-Id: I3ca3ad9c8c1fb910a1c7bf9f44165e2f44c930c9 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 1 + .../snapuserd/snapuserd_daemon.cpp | 2 +- .../user-space-merge/handler_manager.cpp | 371 ++++++++++++++++++ .../user-space-merge/handler_manager.h | 131 +++++++ .../user-space-merge/snapuserd_server.cpp | 338 +--------------- .../user-space-merge/snapuserd_server.h | 58 +-- 6 files changed, 526 insertions(+), 375 deletions(-) create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index dd11a33daf28..65f3d6d297ed 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -62,6 +62,7 @@ cc_library_static { "dm-snapshot-merge/snapuserd_worker.cpp", "dm-snapshot-merge/snapuserd_readahead.cpp", "snapuserd_buffer.cpp", + "user-space-merge/handler_manager.cpp", "user-space-merge/snapuserd_core.cpp", "user-space-merge/snapuserd_dm_user.cpp", "user-space-merge/snapuserd_merge.cpp", diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp index ae20e1fa479e..36dad3343d3e 100644 --- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp +++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp @@ -114,7 +114,7 @@ bool Daemon::StartServerForUserspaceSnapshots(int arg_start, int argc, char** ar return false; } auto handler = user_server_.AddHandler(parts[0], parts[1], parts[2], parts[3]); - if (!handler || !user_server_.StartHandler(handler)) { + if (!handler || !user_server_.StartHandler(parts[0])) { return false; } } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp new file mode 100644 index 000000000000..c5150c411d02 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp @@ -0,0 +1,371 @@ +// Copyright (C) 2023 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 "handler_manager.h" + +#include + +#include + +#include "snapuserd_core.h" + +namespace android { +namespace snapshot { + +static constexpr uint8_t kMaxMergeThreads = 2; + +void HandlerThread::FreeResources() { + // Each worker thread holds a reference to snapuserd. + // Clear them so that all the resources + // held by snapuserd is released + if (snapuserd_) { + snapuserd_->FreeResources(); + snapuserd_ = nullptr; + } +} + +SnapshotHandlerManager::SnapshotHandlerManager() { + monitor_merge_event_fd_.reset(eventfd(0, EFD_CLOEXEC)); + if (monitor_merge_event_fd_ == -1) { + PLOG(FATAL) << "monitor_merge_event_fd_: failed to create eventfd"; + } +} + +std::shared_ptr SnapshotHandlerManager::AddHandler( + const std::string& misc_name, const std::string& cow_device_path, + const std::string& backing_device, const std::string& base_path_merge, + int num_worker_threads, bool use_iouring, bool perform_verification) { + auto snapuserd = std::make_shared(misc_name, cow_device_path, backing_device, + base_path_merge, num_worker_threads, + use_iouring, perform_verification); + if (!snapuserd->InitCowDevice()) { + LOG(ERROR) << "Failed to initialize Snapuserd"; + return nullptr; + } + + if (!snapuserd->InitializeWorkers()) { + LOG(ERROR) << "Failed to initialize workers"; + return nullptr; + } + + auto handler = std::make_shared(snapuserd); + { + std::lock_guard lock(lock_); + if (FindHandler(&lock, misc_name) != dm_users_.end()) { + LOG(ERROR) << "Handler already exists: " << misc_name; + return nullptr; + } + dm_users_.push_back(handler); + } + return handler; +} + +bool SnapshotHandlerManager::StartHandler(const std::string& misc_name) { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + LOG(ERROR) << "Could not find handler: " << misc_name; + return false; + } + if (!(*iter)->snapuserd() || (*iter)->snapuserd()->IsAttached()) { + LOG(ERROR) << "Tried to re-attach control device: " << misc_name; + return false; + } + if (!StartHandler(*iter)) { + return false; + } + return true; +} + +bool SnapshotHandlerManager::StartHandler(const std::shared_ptr& handler) { + if (handler->snapuserd()->IsAttached()) { + LOG(ERROR) << "Handler already attached"; + return false; + } + + handler->snapuserd()->AttachControlDevice(); + + handler->thread() = std::thread(std::bind(&SnapshotHandlerManager::RunThread, this, handler)); + return true; +} + +bool SnapshotHandlerManager::DeleteHandler(const std::string& misc_name) { + { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + // After merge is completed, we swap dm-user table with + // the underlying dm-linear base device. Hence, worker + // threads would have terminted and was removed from + // the list. + LOG(DEBUG) << "Could not find handler: " << misc_name; + return true; + } + + if (!(*iter)->ThreadTerminated()) { + (*iter)->snapuserd()->NotifyIOTerminated(); + } + } + if (!RemoveAndJoinHandler(misc_name)) { + return false; + } + return true; +} + +void SnapshotHandlerManager::RunThread(std::shared_ptr handler) { + LOG(INFO) << "Entering thread for handler: " << handler->misc_name(); + + if (!handler->snapuserd()->Start()) { + LOG(ERROR) << " Failed to launch all worker threads"; + } + + handler->snapuserd()->CloseFds(); + bool merge_completed = handler->snapuserd()->CheckMergeCompletionStatus(); + handler->snapuserd()->UnmapBufferRegion(); + + auto misc_name = handler->misc_name(); + LOG(INFO) << "Handler thread about to exit: " << misc_name; + + { + std::lock_guard lock(lock_); + if (merge_completed) { + num_partitions_merge_complete_ += 1; + active_merge_threads_ -= 1; + WakeupMonitorMergeThread(); + } + handler->SetThreadTerminated(); + auto iter = FindHandler(&lock, handler->misc_name()); + if (iter == dm_users_.end()) { + // RemoveAndJoinHandler() already removed us from the list, and is + // now waiting on a join(), so just return. Additionally, release + // all the resources held by snapuserd object which are shared + // by worker threads. This should be done when the last reference + // of "handler" is released; but we will explicitly release here + // to make sure snapuserd object is freed as it is the biggest + // consumer of memory in the daemon. + handler->FreeResources(); + LOG(INFO) << "Exiting handler thread to allow for join: " << misc_name; + return; + } + + LOG(INFO) << "Exiting handler thread and freeing resources: " << misc_name; + + if (handler->snapuserd()->IsAttached()) { + handler->thread().detach(); + } + + // Important: free resources within the lock. This ensures that if + // WaitForDelete() is called, the handler is either in the list, or + // it's not and its resources are guaranteed to be freed. + handler->FreeResources(); + dm_users_.erase(iter); + } +} + +bool SnapshotHandlerManager::InitiateMerge(const std::string& misc_name) { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + LOG(ERROR) << "Could not find handler: " << misc_name; + return false; + } + + return StartMerge(&lock, *iter); +} + +bool SnapshotHandlerManager::StartMerge(std::lock_guard* proof_of_lock, + const std::shared_ptr& handler) { + CHECK(proof_of_lock); + + if (!handler->snapuserd()->IsAttached()) { + LOG(ERROR) << "Handler not attached to dm-user - Merge thread cannot be started"; + return false; + } + + handler->snapuserd()->MonitorMerge(); + + if (!is_merge_monitor_started_) { + std::thread(&SnapshotHandlerManager::MonitorMerge, this).detach(); + is_merge_monitor_started_ = true; + } + + merge_handlers_.push(handler); + WakeupMonitorMergeThread(); + return true; +} + +void SnapshotHandlerManager::WakeupMonitorMergeThread() { + uint64_t notify = 1; + ssize_t rc = TEMP_FAILURE_RETRY(write(monitor_merge_event_fd_.get(), ¬ify, sizeof(notify))); + if (rc < 0) { + PLOG(FATAL) << "failed to notify monitor merge thread"; + } +} + +void SnapshotHandlerManager::MonitorMerge() { + while (!stop_monitor_merge_thread_) { + uint64_t testVal; + ssize_t ret = + TEMP_FAILURE_RETRY(read(monitor_merge_event_fd_.get(), &testVal, sizeof(testVal))); + if (ret == -1) { + PLOG(FATAL) << "Failed to read from eventfd"; + } else if (ret == 0) { + LOG(FATAL) << "Hit EOF on eventfd"; + } + + LOG(INFO) << "MonitorMerge: active-merge-threads: " << active_merge_threads_; + { + std::lock_guard lock(lock_); + while (active_merge_threads_ < kMaxMergeThreads && merge_handlers_.size() > 0) { + auto handler = merge_handlers_.front(); + merge_handlers_.pop(); + + if (!handler->snapuserd()) { + LOG(INFO) << "MonitorMerge: skipping deleted handler: " << handler->misc_name(); + continue; + } + + LOG(INFO) << "Starting merge for partition: " + << handler->snapuserd()->GetMiscName(); + handler->snapuserd()->InitiateMerge(); + active_merge_threads_ += 1; + } + } + } + + LOG(INFO) << "Exiting MonitorMerge: size: " << merge_handlers_.size(); +} + +std::string SnapshotHandlerManager::GetMergeStatus(const std::string& misc_name) { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + LOG(ERROR) << "Could not find handler: " << misc_name; + return {}; + } + + return (*iter)->snapuserd()->GetMergeStatus(); +} + +double SnapshotHandlerManager::GetMergePercentage() { + std::lock_guard lock(lock_); + + double percentage = 0.0; + int n = 0; + + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + auto& th = (*iter)->thread(); + if (th.joinable()) { + // Merge percentage by individual partitions wherein merge is still + // in-progress + percentage += (*iter)->snapuserd()->GetMergePercentage(); + n += 1; + } + } + + // Calculate final merge including those partitions where merge was already + // completed - num_partitions_merge_complete_ will track them when each + // thread exists in RunThread. + int total_partitions = n + num_partitions_merge_complete_; + + if (total_partitions) { + percentage = ((num_partitions_merge_complete_ * 100.0) + percentage) / total_partitions; + } + + LOG(DEBUG) << "Merge %: " << percentage + << " num_partitions_merge_complete_: " << num_partitions_merge_complete_ + << " total_partitions: " << total_partitions << " n: " << n; + return percentage; +} + +bool SnapshotHandlerManager::GetVerificationStatus() { + std::lock_guard lock(lock_); + + bool status = true; + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + auto& th = (*iter)->thread(); + if (th.joinable() && status) { + status = (*iter)->snapuserd()->CheckPartitionVerification() && status; + } else { + // return immediately if there is a failure + return false; + } + } + + return status; +} + +bool SnapshotHandlerManager::RemoveAndJoinHandler(const std::string& misc_name) { + std::shared_ptr handler; + { + std::lock_guard lock(lock_); + + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + // Client already deleted. + return true; + } + handler = std::move(*iter); + dm_users_.erase(iter); + } + + auto& th = handler->thread(); + if (th.joinable()) { + th.join(); + } + return true; +} + +void SnapshotHandlerManager::TerminateMergeThreads() { + std::lock_guard guard(lock_); + + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + if (!(*iter)->ThreadTerminated()) { + (*iter)->snapuserd()->NotifyIOTerminated(); + } + } +} + +void SnapshotHandlerManager::JoinAllThreads() { + // Acquire the thread list within the lock. + std::vector> dm_users; + { + std::lock_guard guard(lock_); + dm_users = std::move(dm_users_); + } + + for (auto& client : dm_users) { + auto& th = client->thread(); + + if (th.joinable()) th.join(); + } + + stop_monitor_merge_thread_ = true; + WakeupMonitorMergeThread(); +} + +auto SnapshotHandlerManager::FindHandler(std::lock_guard* proof_of_lock, + const std::string& misc_name) -> HandlerList::iterator { + CHECK(proof_of_lock); + + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + if ((*iter)->misc_name() == misc_name) { + return iter; + } + } + return dm_users_.end(); +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h new file mode 100644 index 000000000000..b7ddac19f28a --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h @@ -0,0 +1,131 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace android { +namespace snapshot { + +class SnapshotHandler; + +class HandlerThread { + public: + explicit HandlerThread(std::shared_ptr snapuserd); + + void FreeResources(); + const std::shared_ptr& snapuserd() const { return snapuserd_; } + std::thread& thread() { return thread_; } + + const std::string& misc_name() const { return misc_name_; } + bool ThreadTerminated() { return thread_terminated_; } + void SetThreadTerminated() { thread_terminated_ = true; } + + private: + std::thread thread_; + std::shared_ptr snapuserd_; + std::string misc_name_; + bool thread_terminated_ = false; +}; + +class ISnapshotHandlerManager { + public: + virtual ~ISnapshotHandlerManager() {} + + // Add a new snapshot handler but do not start serving requests yet. + virtual std::shared_ptr AddHandler(const std::string& misc_name, + const std::string& cow_device_path, + const std::string& backing_device, + const std::string& base_path_merge, + int num_worker_threads, bool use_iouring, + bool perform_verification) = 0; + + // Start serving requests on a snapshot handler. + virtual bool StartHandler(const std::string& misc_name) = 0; + + // Stop serving requests on a snapshot handler and remove it. + virtual bool DeleteHandler(const std::string& misc_name) = 0; + + // Begin merging blocks on the given snapshot handler. + virtual bool InitiateMerge(const std::string& misc_name) = 0; + + // Return a string containing a status code indicating the merge status + // on the handler. Returns empty on error. + virtual std::string GetMergeStatus(const std::string& misc_name) = 0; + + // Wait until all handlers have terminated. + virtual void JoinAllThreads() = 0; + + // Stop any in-progress merge threads. + virtual void TerminateMergeThreads() = 0; + + // Returns the merge progress across all merging snapshot handlers. + virtual double GetMergePercentage() = 0; + + // Returns whether all snapshots have verified. + virtual bool GetVerificationStatus() = 0; +}; + +class SnapshotHandlerManager final : public ISnapshotHandlerManager { + public: + SnapshotHandlerManager(); + std::shared_ptr AddHandler(const std::string& misc_name, + const std::string& cow_device_path, + const std::string& backing_device, + const std::string& base_path_merge, + int num_worker_threads, bool use_iouring, + bool perform_verification) override; + bool StartHandler(const std::string& misc_name) override; + bool DeleteHandler(const std::string& misc_name) override; + bool InitiateMerge(const std::string& misc_name) override; + std::string GetMergeStatus(const std::string& misc_name) override; + void JoinAllThreads() override; + void TerminateMergeThreads() override; + double GetMergePercentage() override; + bool GetVerificationStatus() override; + + private: + bool StartHandler(const std::shared_ptr& handler); + void RunThread(std::shared_ptr handler); + bool StartMerge(std::lock_guard* proof_of_lock, + const std::shared_ptr& handler); + void MonitorMerge(); + void WakeupMonitorMergeThread(); + bool RemoveAndJoinHandler(const std::string& misc_name); + + // Find a HandlerThread within a lock. + using HandlerList = std::vector>; + HandlerList::iterator FindHandler(std::lock_guard* proof_of_lock, + const std::string& misc_name); + + std::mutex lock_; + HandlerList dm_users_; + + bool is_merge_monitor_started_ = false; + bool stop_monitor_merge_thread_ = false; + int active_merge_threads_ = 0; + int num_partitions_merge_complete_ = 0; + std::queue> merge_handlers_; + android::base::unique_fd monitor_merge_event_fd_; +}; + +} // namespace snapshot +} // namespace android 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 b7ce2109adfe..cc8115f5f800 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp @@ -62,11 +62,8 @@ DaemonOps UserSnapshotServer::Resolveop(std::string& input) { } UserSnapshotServer::UserSnapshotServer() { - monitor_merge_event_fd_.reset(eventfd(0, EFD_CLOEXEC)); - if (monitor_merge_event_fd_ == -1) { - PLOG(FATAL) << "monitor_merge_event_fd_: failed to create eventfd"; - } terminating_ = false; + handlers_ = std::make_unique(); } UserSnapshotServer::~UserSnapshotServer() { @@ -99,7 +96,7 @@ void UserSnapshotServer::Parsemsg(std::string const& msg, const char delim, void UserSnapshotServer::ShutdownThreads() { terminating_ = true; - JoinAllThreads(); + handlers_->JoinAllThreads(); } HandlerThread::HandlerThread(std::shared_ptr snapuserd) @@ -166,17 +163,7 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st return Sendmsg(fd, "fail"); } - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - LOG(ERROR) << "Could not find handler: " << out[1]; - return Sendmsg(fd, "fail"); - } - if (!(*iter)->snapuserd() || (*iter)->snapuserd()->IsAttached()) { - LOG(ERROR) << "Tried to re-attach control device: " << out[1]; - return Sendmsg(fd, "fail"); - } - if (!StartHandler(*iter)) { + if (!handlers_->StartHandler(out[1])) { return Sendmsg(fd, "fail"); } return Sendmsg(fd, "success"); @@ -209,30 +196,13 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; return Sendmsg(fd, "fail"); } - { - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - // After merge is completed, we swap dm-user table with - // the underlying dm-linear base device. Hence, worker - // threads would have terminted and was removed from - // the list. - LOG(DEBUG) << "Could not find handler: " << out[1]; - return Sendmsg(fd, "success"); - } - - if (!(*iter)->ThreadTerminated()) { - (*iter)->snapuserd()->NotifyIOTerminated(); - } - } - if (!RemoveAndJoinHandler(out[1])) { + if (!handlers_->DeleteHandler(out[1])) { return Sendmsg(fd, "fail"); } return Sendmsg(fd, "success"); } case DaemonOps::DETACH: { - std::lock_guard lock(lock_); - TerminateMergeThreads(&lock); + handlers_->TerminateMergeThreads(); terminating_ = true; return true; } @@ -252,24 +222,15 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st return Sendmsg(fd, "fail"); } if (out[0] == "initiate_merge") { - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - LOG(ERROR) << "Could not find handler: " << out[1]; + if (!handlers_->InitiateMerge(out[1])) { return Sendmsg(fd, "fail"); } - - if (!StartMerge(&lock, *iter)) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); } return Sendmsg(fd, "fail"); } case DaemonOps::PERCENTAGE: { - std::lock_guard lock(lock_); - double percentage = GetMergePercentage(&lock); + double percentage = handlers_->GetMergePercentage(); return Sendmsg(fd, std::to_string(percentage)); } @@ -280,24 +241,16 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; return Sendmsg(fd, "snapshot-merge-failed"); } - { - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - LOG(ERROR) << "Could not find handler: " << out[1]; - return Sendmsg(fd, "snapshot-merge-failed"); - } - - std::string merge_status = GetMergeStatus(*iter); - return Sendmsg(fd, merge_status); + auto status = handlers_->GetMergeStatus(out[1]); + if (status.empty()) { + return Sendmsg(fd, "snapshot-merge-failed"); } + return Sendmsg(fd, status); } case DaemonOps::UPDATE_VERIFY: { - std::lock_guard lock(lock_); - if (!UpdateVerification(&lock)) { + if (!handlers_->GetVerificationStatus()) { return Sendmsg(fd, "fail"); } - return Sendmsg(fd, "success"); } default: { @@ -308,56 +261,6 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st } } -void UserSnapshotServer::RunThread(std::shared_ptr handler) { - LOG(INFO) << "Entering thread for handler: " << handler->misc_name(); - - if (!handler->snapuserd()->Start()) { - LOG(ERROR) << " Failed to launch all worker threads"; - } - - handler->snapuserd()->CloseFds(); - bool merge_completed = handler->snapuserd()->CheckMergeCompletionStatus(); - handler->snapuserd()->UnmapBufferRegion(); - - auto misc_name = handler->misc_name(); - LOG(INFO) << "Handler thread about to exit: " << misc_name; - - { - std::lock_guard lock(lock_); - if (merge_completed) { - num_partitions_merge_complete_ += 1; - active_merge_threads_ -= 1; - WakeupMonitorMergeThread(); - } - handler->SetThreadTerminated(); - auto iter = FindHandler(&lock, handler->misc_name()); - if (iter == dm_users_.end()) { - // RemoveAndJoinHandler() already removed us from the list, and is - // now waiting on a join(), so just return. Additionally, release - // all the resources held by snapuserd object which are shared - // by worker threads. This should be done when the last reference - // of "handler" is released; but we will explicitly release here - // to make sure snapuserd object is freed as it is the biggest - // consumer of memory in the daemon. - handler->FreeResources(); - LOG(INFO) << "Exiting handler thread to allow for join: " << misc_name; - return; - } - - LOG(INFO) << "Exiting handler thread and freeing resources: " << misc_name; - - if (handler->snapuserd()->IsAttached()) { - handler->thread().detach(); - } - - // Important: free resources within the lock. This ensures that if - // WaitForDelete() is called, the handler is either in the list, or - // it's not and its resources are guaranteed to be freed. - handler->FreeResources(); - dm_users_.erase(iter); - } -} - bool UserSnapshotServer::Start(const std::string& socketname) { bool start_listening = true; @@ -423,28 +326,10 @@ bool UserSnapshotServer::Run() { } } - JoinAllThreads(); + handlers_->JoinAllThreads(); return true; } -void UserSnapshotServer::JoinAllThreads() { - // Acquire the thread list within the lock. - std::vector> dm_users; - { - std::lock_guard guard(lock_); - dm_users = std::move(dm_users_); - } - - for (auto& client : dm_users) { - auto& th = client->thread(); - - if (th.joinable()) th.join(); - } - - stop_monitor_merge_thread_ = true; - WakeupMonitorMergeThread(); -} - void UserSnapshotServer::AddWatchedFd(android::base::borrowed_fd fd, int events) { struct pollfd p = {}; p.fd = fd.get(); @@ -506,185 +391,13 @@ std::shared_ptr UserSnapshotServer::AddHandler(const std::string& perform_verification = false; } - auto snapuserd = std::make_shared(misc_name, cow_device_path, backing_device, - base_path_merge, num_worker_threads, - io_uring_enabled_, perform_verification); - if (!snapuserd->InitCowDevice()) { - LOG(ERROR) << "Failed to initialize Snapuserd"; - return nullptr; - } - - if (!snapuserd->InitializeWorkers()) { - LOG(ERROR) << "Failed to initialize workers"; - return nullptr; - } - - auto handler = std::make_shared(snapuserd); - { - std::lock_guard lock(lock_); - if (FindHandler(&lock, misc_name) != dm_users_.end()) { - LOG(ERROR) << "Handler already exists: " << misc_name; - return nullptr; - } - dm_users_.push_back(handler); - } - return handler; -} - -bool UserSnapshotServer::StartHandler(const std::shared_ptr& handler) { - if (handler->snapuserd()->IsAttached()) { - LOG(ERROR) << "Handler already attached"; - return false; - } - - handler->snapuserd()->AttachControlDevice(); - - handler->thread() = std::thread(std::bind(&UserSnapshotServer::RunThread, this, handler)); - return true; -} - -bool UserSnapshotServer::StartMerge(std::lock_guard* proof_of_lock, - const std::shared_ptr& handler) { - CHECK(proof_of_lock); - - if (!handler->snapuserd()->IsAttached()) { - LOG(ERROR) << "Handler not attached to dm-user - Merge thread cannot be started"; - return false; - } - - handler->snapuserd()->MonitorMerge(); - - if (!is_merge_monitor_started_.has_value()) { - std::thread(&UserSnapshotServer::MonitorMerge, this).detach(); - is_merge_monitor_started_ = true; - } - - merge_handlers_.push(handler); - WakeupMonitorMergeThread(); - return true; -} - -auto UserSnapshotServer::FindHandler(std::lock_guard* proof_of_lock, - const std::string& misc_name) -> HandlerList::iterator { - CHECK(proof_of_lock); - - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - if ((*iter)->misc_name() == misc_name) { - return iter; - } - } - return dm_users_.end(); -} - -void UserSnapshotServer::TerminateMergeThreads(std::lock_guard* proof_of_lock) { - CHECK(proof_of_lock); - - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - if (!(*iter)->ThreadTerminated()) { - (*iter)->snapuserd()->NotifyIOTerminated(); - } - } -} - -std::string UserSnapshotServer::GetMergeStatus(const std::shared_ptr& handler) { - return handler->snapuserd()->GetMergeStatus(); -} - -double UserSnapshotServer::GetMergePercentage(std::lock_guard* proof_of_lock) { - CHECK(proof_of_lock); - double percentage = 0.0; - int n = 0; - - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - auto& th = (*iter)->thread(); - if (th.joinable()) { - // Merge percentage by individual partitions wherein merge is still - // in-progress - percentage += (*iter)->snapuserd()->GetMergePercentage(); - n += 1; - } - } - - // Calculate final merge including those partitions where merge was already - // completed - num_partitions_merge_complete_ will track them when each - // thread exists in RunThread. - int total_partitions = n + num_partitions_merge_complete_; - - if (total_partitions) { - percentage = ((num_partitions_merge_complete_ * 100.0) + percentage) / total_partitions; - } - - LOG(DEBUG) << "Merge %: " << percentage - << " num_partitions_merge_complete_: " << num_partitions_merge_complete_ - << " total_partitions: " << total_partitions << " n: " << n; - return percentage; -} - -bool UserSnapshotServer::RemoveAndJoinHandler(const std::string& misc_name) { - std::shared_ptr handler; - { - std::lock_guard lock(lock_); - - auto iter = FindHandler(&lock, misc_name); - if (iter == dm_users_.end()) { - // Client already deleted. - return true; - } - handler = std::move(*iter); - dm_users_.erase(iter); - } - - auto& th = handler->thread(); - if (th.joinable()) { - th.join(); - } - return true; -} - -void UserSnapshotServer::WakeupMonitorMergeThread() { - uint64_t notify = 1; - ssize_t rc = TEMP_FAILURE_RETRY(write(monitor_merge_event_fd_.get(), ¬ify, sizeof(notify))); - if (rc < 0) { - PLOG(FATAL) << "failed to notify monitor merge thread"; - } -} - -void UserSnapshotServer::MonitorMerge() { - while (!stop_monitor_merge_thread_) { - uint64_t testVal; - ssize_t ret = - TEMP_FAILURE_RETRY(read(monitor_merge_event_fd_.get(), &testVal, sizeof(testVal))); - if (ret == -1) { - PLOG(FATAL) << "Failed to read from eventfd"; - } else if (ret == 0) { - LOG(FATAL) << "Hit EOF on eventfd"; - } - - LOG(INFO) << "MonitorMerge: active-merge-threads: " << active_merge_threads_; - { - std::lock_guard lock(lock_); - while (active_merge_threads_ < kMaxMergeThreads && merge_handlers_.size() > 0) { - auto handler = merge_handlers_.front(); - merge_handlers_.pop(); - - if (!handler->snapuserd()) { - LOG(INFO) << "MonitorMerge: skipping deleted handler: " << handler->misc_name(); - continue; - } - - LOG(INFO) << "Starting merge for partition: " - << handler->snapuserd()->GetMiscName(); - handler->snapuserd()->InitiateMerge(); - active_merge_threads_ += 1; - } - } - } - - LOG(INFO) << "Exiting MonitorMerge: size: " << merge_handlers_.size(); + return handlers_->AddHandler(misc_name, cow_device_path, backing_device, base_path_merge, + num_worker_threads, io_uring_enabled_, perform_verification); } bool UserSnapshotServer::WaitForSocket() { - auto scope_guard = android::base::make_scope_guard([this]() -> void { JoinAllThreads(); }); + auto scope_guard = + android::base::make_scope_guard([this]() -> void { handlers_->JoinAllThreads(); }); auto socket_path = ANDROID_SOCKET_DIR "/"s + kSnapuserdSocketProxy; @@ -781,21 +494,8 @@ bool UserSnapshotServer::RunForSocketHandoff() { return true; } -bool UserSnapshotServer::UpdateVerification(std::lock_guard* proof_of_lock) { - CHECK(proof_of_lock); - - bool status = true; - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - auto& th = (*iter)->thread(); - if (th.joinable() && status) { - status = (*iter)->snapuserd()->CheckPartitionVerification() && status; - } else { - // return immediately if there is a failure - return false; - } - } - - return status; +bool UserSnapshotServer::StartHandler(const std::string& misc_name) { + return handlers_->StartHandler(misc_name); } } // namespace snapshot diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h index 12c3903c495c..ae5190391dfa 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h @@ -31,6 +31,7 @@ #include #include +#include "handler_manager.h" #include "snapuserd_core.h" namespace android { @@ -54,33 +55,6 @@ enum class DaemonOps { INVALID, }; -class HandlerThread { - public: - explicit HandlerThread(std::shared_ptr snapuserd); - - void FreeResources() { - // Each worker thread holds a reference to snapuserd. - // Clear them so that all the resources - // held by snapuserd is released - if (snapuserd_) { - snapuserd_->FreeResources(); - snapuserd_ = nullptr; - } - } - const std::shared_ptr& snapuserd() const { return snapuserd_; } - std::thread& thread() { return thread_; } - - const std::string& misc_name() const { return misc_name_; } - bool ThreadTerminated() { return thread_terminated_; } - void SetThreadTerminated() { thread_terminated_ = true; } - - private: - std::thread thread_; - std::shared_ptr snapuserd_; - std::string misc_name_; - bool thread_terminated_ = false; -}; - class UserSnapshotServer { private: android::base::unique_fd sockfd_; @@ -88,21 +62,12 @@ class UserSnapshotServer { volatile bool received_socket_signal_ = false; std::vector watched_fds_; bool is_socket_present_ = false; - int num_partitions_merge_complete_ = 0; - int active_merge_threads_ = 0; - bool stop_monitor_merge_thread_ = false; bool is_server_running_ = false; bool io_uring_enabled_ = false; - std::optional is_merge_monitor_started_; - - android::base::unique_fd monitor_merge_event_fd_; + std::unique_ptr handlers_; std::mutex lock_; - using HandlerList = std::vector>; - HandlerList dm_users_; - std::queue> merge_handlers_; - void AddWatchedFd(android::base::borrowed_fd fd, int events); void AcceptClient(); bool HandleClient(android::base::borrowed_fd fd, int revents); @@ -111,28 +76,15 @@ class UserSnapshotServer { bool Receivemsg(android::base::borrowed_fd fd, const std::string& str); void ShutdownThreads(); - bool RemoveAndJoinHandler(const std::string& control_device); DaemonOps Resolveop(std::string& input); std::string GetDaemonStatus(); void Parsemsg(std::string const& msg, const char delim, std::vector& out); bool IsTerminating() { return terminating_; } - void RunThread(std::shared_ptr handler); - void MonitorMerge(); - void JoinAllThreads(); bool StartWithSocket(bool start_listening); - // Find a HandlerThread within a lock. - HandlerList::iterator FindHandler(std::lock_guard* proof_of_lock, - const std::string& misc_name); - - double GetMergePercentage(std::lock_guard* proof_of_lock); - void TerminateMergeThreads(std::lock_guard* proof_of_lock); - - bool UpdateVerification(std::lock_guard* proof_of_lock); - public: UserSnapshotServer(); ~UserSnapshotServer(); @@ -147,12 +99,8 @@ class UserSnapshotServer { const std::string& cow_device_path, const std::string& backing_device, const std::string& base_path_merge); - bool StartHandler(const std::shared_ptr& handler); - bool StartMerge(std::lock_guard* proof_of_lock, - const std::shared_ptr& handler); - std::string GetMergeStatus(const std::shared_ptr& handler); + bool StartHandler(const std::string& misc_name); - void WakeupMonitorMergeThread(); void SetTerminating() { terminating_ = true; } void ReceivedSocketSignal() { received_socket_signal_ = true; } void SetServerRunning() { is_server_running_ = true; } From 395edf8460ca6c6079ea4f73136c902c0de6fc71 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 17 Feb 2023 01:20:52 -0800 Subject: [PATCH 0196/1487] snapuserd: Split the server into two classes. This splits server into two classes: one that handles the IPC requests, and one that managers snapshot handlers. This will allow embedding of the snapshot handling code, without booting up a server. It'll also make testing much easier. The handler code has been further placed behind a virtual interface, though this is likely unnecessary unless we start testing the server logic itself (or attempt to unify the S and T+ versions of snapuserd). Bug: 269361087 Test: ota Ignore-AOSP-First: cherry-pick from aosp (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:8bb751dc8a1499f24add9e0831ab347feb2c3878) Merged-In: I3ca3ad9c8c1fb910a1c7bf9f44165e2f44c930c9 Change-Id: I3ca3ad9c8c1fb910a1c7bf9f44165e2f44c930c9 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 1 + .../snapuserd/snapuserd_daemon.cpp | 2 +- .../user-space-merge/handler_manager.cpp | 371 ++++++++++++++++++ .../user-space-merge/handler_manager.h | 131 +++++++ .../user-space-merge/snapuserd_server.cpp | 338 +--------------- .../user-space-merge/snapuserd_server.h | 58 +-- 6 files changed, 526 insertions(+), 375 deletions(-) create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index dd11a33daf28..65f3d6d297ed 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -62,6 +62,7 @@ cc_library_static { "dm-snapshot-merge/snapuserd_worker.cpp", "dm-snapshot-merge/snapuserd_readahead.cpp", "snapuserd_buffer.cpp", + "user-space-merge/handler_manager.cpp", "user-space-merge/snapuserd_core.cpp", "user-space-merge/snapuserd_dm_user.cpp", "user-space-merge/snapuserd_merge.cpp", diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp index ae20e1fa479e..36dad3343d3e 100644 --- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp +++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp @@ -114,7 +114,7 @@ bool Daemon::StartServerForUserspaceSnapshots(int arg_start, int argc, char** ar return false; } auto handler = user_server_.AddHandler(parts[0], parts[1], parts[2], parts[3]); - if (!handler || !user_server_.StartHandler(handler)) { + if (!handler || !user_server_.StartHandler(parts[0])) { return false; } } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp new file mode 100644 index 000000000000..c5150c411d02 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp @@ -0,0 +1,371 @@ +// Copyright (C) 2023 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 "handler_manager.h" + +#include + +#include + +#include "snapuserd_core.h" + +namespace android { +namespace snapshot { + +static constexpr uint8_t kMaxMergeThreads = 2; + +void HandlerThread::FreeResources() { + // Each worker thread holds a reference to snapuserd. + // Clear them so that all the resources + // held by snapuserd is released + if (snapuserd_) { + snapuserd_->FreeResources(); + snapuserd_ = nullptr; + } +} + +SnapshotHandlerManager::SnapshotHandlerManager() { + monitor_merge_event_fd_.reset(eventfd(0, EFD_CLOEXEC)); + if (monitor_merge_event_fd_ == -1) { + PLOG(FATAL) << "monitor_merge_event_fd_: failed to create eventfd"; + } +} + +std::shared_ptr SnapshotHandlerManager::AddHandler( + const std::string& misc_name, const std::string& cow_device_path, + const std::string& backing_device, const std::string& base_path_merge, + int num_worker_threads, bool use_iouring, bool perform_verification) { + auto snapuserd = std::make_shared(misc_name, cow_device_path, backing_device, + base_path_merge, num_worker_threads, + use_iouring, perform_verification); + if (!snapuserd->InitCowDevice()) { + LOG(ERROR) << "Failed to initialize Snapuserd"; + return nullptr; + } + + if (!snapuserd->InitializeWorkers()) { + LOG(ERROR) << "Failed to initialize workers"; + return nullptr; + } + + auto handler = std::make_shared(snapuserd); + { + std::lock_guard lock(lock_); + if (FindHandler(&lock, misc_name) != dm_users_.end()) { + LOG(ERROR) << "Handler already exists: " << misc_name; + return nullptr; + } + dm_users_.push_back(handler); + } + return handler; +} + +bool SnapshotHandlerManager::StartHandler(const std::string& misc_name) { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + LOG(ERROR) << "Could not find handler: " << misc_name; + return false; + } + if (!(*iter)->snapuserd() || (*iter)->snapuserd()->IsAttached()) { + LOG(ERROR) << "Tried to re-attach control device: " << misc_name; + return false; + } + if (!StartHandler(*iter)) { + return false; + } + return true; +} + +bool SnapshotHandlerManager::StartHandler(const std::shared_ptr& handler) { + if (handler->snapuserd()->IsAttached()) { + LOG(ERROR) << "Handler already attached"; + return false; + } + + handler->snapuserd()->AttachControlDevice(); + + handler->thread() = std::thread(std::bind(&SnapshotHandlerManager::RunThread, this, handler)); + return true; +} + +bool SnapshotHandlerManager::DeleteHandler(const std::string& misc_name) { + { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + // After merge is completed, we swap dm-user table with + // the underlying dm-linear base device. Hence, worker + // threads would have terminted and was removed from + // the list. + LOG(DEBUG) << "Could not find handler: " << misc_name; + return true; + } + + if (!(*iter)->ThreadTerminated()) { + (*iter)->snapuserd()->NotifyIOTerminated(); + } + } + if (!RemoveAndJoinHandler(misc_name)) { + return false; + } + return true; +} + +void SnapshotHandlerManager::RunThread(std::shared_ptr handler) { + LOG(INFO) << "Entering thread for handler: " << handler->misc_name(); + + if (!handler->snapuserd()->Start()) { + LOG(ERROR) << " Failed to launch all worker threads"; + } + + handler->snapuserd()->CloseFds(); + bool merge_completed = handler->snapuserd()->CheckMergeCompletionStatus(); + handler->snapuserd()->UnmapBufferRegion(); + + auto misc_name = handler->misc_name(); + LOG(INFO) << "Handler thread about to exit: " << misc_name; + + { + std::lock_guard lock(lock_); + if (merge_completed) { + num_partitions_merge_complete_ += 1; + active_merge_threads_ -= 1; + WakeupMonitorMergeThread(); + } + handler->SetThreadTerminated(); + auto iter = FindHandler(&lock, handler->misc_name()); + if (iter == dm_users_.end()) { + // RemoveAndJoinHandler() already removed us from the list, and is + // now waiting on a join(), so just return. Additionally, release + // all the resources held by snapuserd object which are shared + // by worker threads. This should be done when the last reference + // of "handler" is released; but we will explicitly release here + // to make sure snapuserd object is freed as it is the biggest + // consumer of memory in the daemon. + handler->FreeResources(); + LOG(INFO) << "Exiting handler thread to allow for join: " << misc_name; + return; + } + + LOG(INFO) << "Exiting handler thread and freeing resources: " << misc_name; + + if (handler->snapuserd()->IsAttached()) { + handler->thread().detach(); + } + + // Important: free resources within the lock. This ensures that if + // WaitForDelete() is called, the handler is either in the list, or + // it's not and its resources are guaranteed to be freed. + handler->FreeResources(); + dm_users_.erase(iter); + } +} + +bool SnapshotHandlerManager::InitiateMerge(const std::string& misc_name) { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + LOG(ERROR) << "Could not find handler: " << misc_name; + return false; + } + + return StartMerge(&lock, *iter); +} + +bool SnapshotHandlerManager::StartMerge(std::lock_guard* proof_of_lock, + const std::shared_ptr& handler) { + CHECK(proof_of_lock); + + if (!handler->snapuserd()->IsAttached()) { + LOG(ERROR) << "Handler not attached to dm-user - Merge thread cannot be started"; + return false; + } + + handler->snapuserd()->MonitorMerge(); + + if (!is_merge_monitor_started_) { + std::thread(&SnapshotHandlerManager::MonitorMerge, this).detach(); + is_merge_monitor_started_ = true; + } + + merge_handlers_.push(handler); + WakeupMonitorMergeThread(); + return true; +} + +void SnapshotHandlerManager::WakeupMonitorMergeThread() { + uint64_t notify = 1; + ssize_t rc = TEMP_FAILURE_RETRY(write(monitor_merge_event_fd_.get(), ¬ify, sizeof(notify))); + if (rc < 0) { + PLOG(FATAL) << "failed to notify monitor merge thread"; + } +} + +void SnapshotHandlerManager::MonitorMerge() { + while (!stop_monitor_merge_thread_) { + uint64_t testVal; + ssize_t ret = + TEMP_FAILURE_RETRY(read(monitor_merge_event_fd_.get(), &testVal, sizeof(testVal))); + if (ret == -1) { + PLOG(FATAL) << "Failed to read from eventfd"; + } else if (ret == 0) { + LOG(FATAL) << "Hit EOF on eventfd"; + } + + LOG(INFO) << "MonitorMerge: active-merge-threads: " << active_merge_threads_; + { + std::lock_guard lock(lock_); + while (active_merge_threads_ < kMaxMergeThreads && merge_handlers_.size() > 0) { + auto handler = merge_handlers_.front(); + merge_handlers_.pop(); + + if (!handler->snapuserd()) { + LOG(INFO) << "MonitorMerge: skipping deleted handler: " << handler->misc_name(); + continue; + } + + LOG(INFO) << "Starting merge for partition: " + << handler->snapuserd()->GetMiscName(); + handler->snapuserd()->InitiateMerge(); + active_merge_threads_ += 1; + } + } + } + + LOG(INFO) << "Exiting MonitorMerge: size: " << merge_handlers_.size(); +} + +std::string SnapshotHandlerManager::GetMergeStatus(const std::string& misc_name) { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + LOG(ERROR) << "Could not find handler: " << misc_name; + return {}; + } + + return (*iter)->snapuserd()->GetMergeStatus(); +} + +double SnapshotHandlerManager::GetMergePercentage() { + std::lock_guard lock(lock_); + + double percentage = 0.0; + int n = 0; + + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + auto& th = (*iter)->thread(); + if (th.joinable()) { + // Merge percentage by individual partitions wherein merge is still + // in-progress + percentage += (*iter)->snapuserd()->GetMergePercentage(); + n += 1; + } + } + + // Calculate final merge including those partitions where merge was already + // completed - num_partitions_merge_complete_ will track them when each + // thread exists in RunThread. + int total_partitions = n + num_partitions_merge_complete_; + + if (total_partitions) { + percentage = ((num_partitions_merge_complete_ * 100.0) + percentage) / total_partitions; + } + + LOG(DEBUG) << "Merge %: " << percentage + << " num_partitions_merge_complete_: " << num_partitions_merge_complete_ + << " total_partitions: " << total_partitions << " n: " << n; + return percentage; +} + +bool SnapshotHandlerManager::GetVerificationStatus() { + std::lock_guard lock(lock_); + + bool status = true; + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + auto& th = (*iter)->thread(); + if (th.joinable() && status) { + status = (*iter)->snapuserd()->CheckPartitionVerification() && status; + } else { + // return immediately if there is a failure + return false; + } + } + + return status; +} + +bool SnapshotHandlerManager::RemoveAndJoinHandler(const std::string& misc_name) { + std::shared_ptr handler; + { + std::lock_guard lock(lock_); + + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + // Client already deleted. + return true; + } + handler = std::move(*iter); + dm_users_.erase(iter); + } + + auto& th = handler->thread(); + if (th.joinable()) { + th.join(); + } + return true; +} + +void SnapshotHandlerManager::TerminateMergeThreads() { + std::lock_guard guard(lock_); + + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + if (!(*iter)->ThreadTerminated()) { + (*iter)->snapuserd()->NotifyIOTerminated(); + } + } +} + +void SnapshotHandlerManager::JoinAllThreads() { + // Acquire the thread list within the lock. + std::vector> dm_users; + { + std::lock_guard guard(lock_); + dm_users = std::move(dm_users_); + } + + for (auto& client : dm_users) { + auto& th = client->thread(); + + if (th.joinable()) th.join(); + } + + stop_monitor_merge_thread_ = true; + WakeupMonitorMergeThread(); +} + +auto SnapshotHandlerManager::FindHandler(std::lock_guard* proof_of_lock, + const std::string& misc_name) -> HandlerList::iterator { + CHECK(proof_of_lock); + + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + if ((*iter)->misc_name() == misc_name) { + return iter; + } + } + return dm_users_.end(); +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h new file mode 100644 index 000000000000..b7ddac19f28a --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h @@ -0,0 +1,131 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace android { +namespace snapshot { + +class SnapshotHandler; + +class HandlerThread { + public: + explicit HandlerThread(std::shared_ptr snapuserd); + + void FreeResources(); + const std::shared_ptr& snapuserd() const { return snapuserd_; } + std::thread& thread() { return thread_; } + + const std::string& misc_name() const { return misc_name_; } + bool ThreadTerminated() { return thread_terminated_; } + void SetThreadTerminated() { thread_terminated_ = true; } + + private: + std::thread thread_; + std::shared_ptr snapuserd_; + std::string misc_name_; + bool thread_terminated_ = false; +}; + +class ISnapshotHandlerManager { + public: + virtual ~ISnapshotHandlerManager() {} + + // Add a new snapshot handler but do not start serving requests yet. + virtual std::shared_ptr AddHandler(const std::string& misc_name, + const std::string& cow_device_path, + const std::string& backing_device, + const std::string& base_path_merge, + int num_worker_threads, bool use_iouring, + bool perform_verification) = 0; + + // Start serving requests on a snapshot handler. + virtual bool StartHandler(const std::string& misc_name) = 0; + + // Stop serving requests on a snapshot handler and remove it. + virtual bool DeleteHandler(const std::string& misc_name) = 0; + + // Begin merging blocks on the given snapshot handler. + virtual bool InitiateMerge(const std::string& misc_name) = 0; + + // Return a string containing a status code indicating the merge status + // on the handler. Returns empty on error. + virtual std::string GetMergeStatus(const std::string& misc_name) = 0; + + // Wait until all handlers have terminated. + virtual void JoinAllThreads() = 0; + + // Stop any in-progress merge threads. + virtual void TerminateMergeThreads() = 0; + + // Returns the merge progress across all merging snapshot handlers. + virtual double GetMergePercentage() = 0; + + // Returns whether all snapshots have verified. + virtual bool GetVerificationStatus() = 0; +}; + +class SnapshotHandlerManager final : public ISnapshotHandlerManager { + public: + SnapshotHandlerManager(); + std::shared_ptr AddHandler(const std::string& misc_name, + const std::string& cow_device_path, + const std::string& backing_device, + const std::string& base_path_merge, + int num_worker_threads, bool use_iouring, + bool perform_verification) override; + bool StartHandler(const std::string& misc_name) override; + bool DeleteHandler(const std::string& misc_name) override; + bool InitiateMerge(const std::string& misc_name) override; + std::string GetMergeStatus(const std::string& misc_name) override; + void JoinAllThreads() override; + void TerminateMergeThreads() override; + double GetMergePercentage() override; + bool GetVerificationStatus() override; + + private: + bool StartHandler(const std::shared_ptr& handler); + void RunThread(std::shared_ptr handler); + bool StartMerge(std::lock_guard* proof_of_lock, + const std::shared_ptr& handler); + void MonitorMerge(); + void WakeupMonitorMergeThread(); + bool RemoveAndJoinHandler(const std::string& misc_name); + + // Find a HandlerThread within a lock. + using HandlerList = std::vector>; + HandlerList::iterator FindHandler(std::lock_guard* proof_of_lock, + const std::string& misc_name); + + std::mutex lock_; + HandlerList dm_users_; + + bool is_merge_monitor_started_ = false; + bool stop_monitor_merge_thread_ = false; + int active_merge_threads_ = 0; + int num_partitions_merge_complete_ = 0; + std::queue> merge_handlers_; + android::base::unique_fd monitor_merge_event_fd_; +}; + +} // namespace snapshot +} // namespace android 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 b7ce2109adfe..cc8115f5f800 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp @@ -62,11 +62,8 @@ DaemonOps UserSnapshotServer::Resolveop(std::string& input) { } UserSnapshotServer::UserSnapshotServer() { - monitor_merge_event_fd_.reset(eventfd(0, EFD_CLOEXEC)); - if (monitor_merge_event_fd_ == -1) { - PLOG(FATAL) << "monitor_merge_event_fd_: failed to create eventfd"; - } terminating_ = false; + handlers_ = std::make_unique(); } UserSnapshotServer::~UserSnapshotServer() { @@ -99,7 +96,7 @@ void UserSnapshotServer::Parsemsg(std::string const& msg, const char delim, void UserSnapshotServer::ShutdownThreads() { terminating_ = true; - JoinAllThreads(); + handlers_->JoinAllThreads(); } HandlerThread::HandlerThread(std::shared_ptr snapuserd) @@ -166,17 +163,7 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st return Sendmsg(fd, "fail"); } - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - LOG(ERROR) << "Could not find handler: " << out[1]; - return Sendmsg(fd, "fail"); - } - if (!(*iter)->snapuserd() || (*iter)->snapuserd()->IsAttached()) { - LOG(ERROR) << "Tried to re-attach control device: " << out[1]; - return Sendmsg(fd, "fail"); - } - if (!StartHandler(*iter)) { + if (!handlers_->StartHandler(out[1])) { return Sendmsg(fd, "fail"); } return Sendmsg(fd, "success"); @@ -209,30 +196,13 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; return Sendmsg(fd, "fail"); } - { - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - // After merge is completed, we swap dm-user table with - // the underlying dm-linear base device. Hence, worker - // threads would have terminted and was removed from - // the list. - LOG(DEBUG) << "Could not find handler: " << out[1]; - return Sendmsg(fd, "success"); - } - - if (!(*iter)->ThreadTerminated()) { - (*iter)->snapuserd()->NotifyIOTerminated(); - } - } - if (!RemoveAndJoinHandler(out[1])) { + if (!handlers_->DeleteHandler(out[1])) { return Sendmsg(fd, "fail"); } return Sendmsg(fd, "success"); } case DaemonOps::DETACH: { - std::lock_guard lock(lock_); - TerminateMergeThreads(&lock); + handlers_->TerminateMergeThreads(); terminating_ = true; return true; } @@ -252,24 +222,15 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st return Sendmsg(fd, "fail"); } if (out[0] == "initiate_merge") { - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - LOG(ERROR) << "Could not find handler: " << out[1]; + if (!handlers_->InitiateMerge(out[1])) { return Sendmsg(fd, "fail"); } - - if (!StartMerge(&lock, *iter)) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); } return Sendmsg(fd, "fail"); } case DaemonOps::PERCENTAGE: { - std::lock_guard lock(lock_); - double percentage = GetMergePercentage(&lock); + double percentage = handlers_->GetMergePercentage(); return Sendmsg(fd, std::to_string(percentage)); } @@ -280,24 +241,16 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; return Sendmsg(fd, "snapshot-merge-failed"); } - { - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - LOG(ERROR) << "Could not find handler: " << out[1]; - return Sendmsg(fd, "snapshot-merge-failed"); - } - - std::string merge_status = GetMergeStatus(*iter); - return Sendmsg(fd, merge_status); + auto status = handlers_->GetMergeStatus(out[1]); + if (status.empty()) { + return Sendmsg(fd, "snapshot-merge-failed"); } + return Sendmsg(fd, status); } case DaemonOps::UPDATE_VERIFY: { - std::lock_guard lock(lock_); - if (!UpdateVerification(&lock)) { + if (!handlers_->GetVerificationStatus()) { return Sendmsg(fd, "fail"); } - return Sendmsg(fd, "success"); } default: { @@ -308,56 +261,6 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st } } -void UserSnapshotServer::RunThread(std::shared_ptr handler) { - LOG(INFO) << "Entering thread for handler: " << handler->misc_name(); - - if (!handler->snapuserd()->Start()) { - LOG(ERROR) << " Failed to launch all worker threads"; - } - - handler->snapuserd()->CloseFds(); - bool merge_completed = handler->snapuserd()->CheckMergeCompletionStatus(); - handler->snapuserd()->UnmapBufferRegion(); - - auto misc_name = handler->misc_name(); - LOG(INFO) << "Handler thread about to exit: " << misc_name; - - { - std::lock_guard lock(lock_); - if (merge_completed) { - num_partitions_merge_complete_ += 1; - active_merge_threads_ -= 1; - WakeupMonitorMergeThread(); - } - handler->SetThreadTerminated(); - auto iter = FindHandler(&lock, handler->misc_name()); - if (iter == dm_users_.end()) { - // RemoveAndJoinHandler() already removed us from the list, and is - // now waiting on a join(), so just return. Additionally, release - // all the resources held by snapuserd object which are shared - // by worker threads. This should be done when the last reference - // of "handler" is released; but we will explicitly release here - // to make sure snapuserd object is freed as it is the biggest - // consumer of memory in the daemon. - handler->FreeResources(); - LOG(INFO) << "Exiting handler thread to allow for join: " << misc_name; - return; - } - - LOG(INFO) << "Exiting handler thread and freeing resources: " << misc_name; - - if (handler->snapuserd()->IsAttached()) { - handler->thread().detach(); - } - - // Important: free resources within the lock. This ensures that if - // WaitForDelete() is called, the handler is either in the list, or - // it's not and its resources are guaranteed to be freed. - handler->FreeResources(); - dm_users_.erase(iter); - } -} - bool UserSnapshotServer::Start(const std::string& socketname) { bool start_listening = true; @@ -423,28 +326,10 @@ bool UserSnapshotServer::Run() { } } - JoinAllThreads(); + handlers_->JoinAllThreads(); return true; } -void UserSnapshotServer::JoinAllThreads() { - // Acquire the thread list within the lock. - std::vector> dm_users; - { - std::lock_guard guard(lock_); - dm_users = std::move(dm_users_); - } - - for (auto& client : dm_users) { - auto& th = client->thread(); - - if (th.joinable()) th.join(); - } - - stop_monitor_merge_thread_ = true; - WakeupMonitorMergeThread(); -} - void UserSnapshotServer::AddWatchedFd(android::base::borrowed_fd fd, int events) { struct pollfd p = {}; p.fd = fd.get(); @@ -506,185 +391,13 @@ std::shared_ptr UserSnapshotServer::AddHandler(const std::string& perform_verification = false; } - auto snapuserd = std::make_shared(misc_name, cow_device_path, backing_device, - base_path_merge, num_worker_threads, - io_uring_enabled_, perform_verification); - if (!snapuserd->InitCowDevice()) { - LOG(ERROR) << "Failed to initialize Snapuserd"; - return nullptr; - } - - if (!snapuserd->InitializeWorkers()) { - LOG(ERROR) << "Failed to initialize workers"; - return nullptr; - } - - auto handler = std::make_shared(snapuserd); - { - std::lock_guard lock(lock_); - if (FindHandler(&lock, misc_name) != dm_users_.end()) { - LOG(ERROR) << "Handler already exists: " << misc_name; - return nullptr; - } - dm_users_.push_back(handler); - } - return handler; -} - -bool UserSnapshotServer::StartHandler(const std::shared_ptr& handler) { - if (handler->snapuserd()->IsAttached()) { - LOG(ERROR) << "Handler already attached"; - return false; - } - - handler->snapuserd()->AttachControlDevice(); - - handler->thread() = std::thread(std::bind(&UserSnapshotServer::RunThread, this, handler)); - return true; -} - -bool UserSnapshotServer::StartMerge(std::lock_guard* proof_of_lock, - const std::shared_ptr& handler) { - CHECK(proof_of_lock); - - if (!handler->snapuserd()->IsAttached()) { - LOG(ERROR) << "Handler not attached to dm-user - Merge thread cannot be started"; - return false; - } - - handler->snapuserd()->MonitorMerge(); - - if (!is_merge_monitor_started_.has_value()) { - std::thread(&UserSnapshotServer::MonitorMerge, this).detach(); - is_merge_monitor_started_ = true; - } - - merge_handlers_.push(handler); - WakeupMonitorMergeThread(); - return true; -} - -auto UserSnapshotServer::FindHandler(std::lock_guard* proof_of_lock, - const std::string& misc_name) -> HandlerList::iterator { - CHECK(proof_of_lock); - - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - if ((*iter)->misc_name() == misc_name) { - return iter; - } - } - return dm_users_.end(); -} - -void UserSnapshotServer::TerminateMergeThreads(std::lock_guard* proof_of_lock) { - CHECK(proof_of_lock); - - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - if (!(*iter)->ThreadTerminated()) { - (*iter)->snapuserd()->NotifyIOTerminated(); - } - } -} - -std::string UserSnapshotServer::GetMergeStatus(const std::shared_ptr& handler) { - return handler->snapuserd()->GetMergeStatus(); -} - -double UserSnapshotServer::GetMergePercentage(std::lock_guard* proof_of_lock) { - CHECK(proof_of_lock); - double percentage = 0.0; - int n = 0; - - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - auto& th = (*iter)->thread(); - if (th.joinable()) { - // Merge percentage by individual partitions wherein merge is still - // in-progress - percentage += (*iter)->snapuserd()->GetMergePercentage(); - n += 1; - } - } - - // Calculate final merge including those partitions where merge was already - // completed - num_partitions_merge_complete_ will track them when each - // thread exists in RunThread. - int total_partitions = n + num_partitions_merge_complete_; - - if (total_partitions) { - percentage = ((num_partitions_merge_complete_ * 100.0) + percentage) / total_partitions; - } - - LOG(DEBUG) << "Merge %: " << percentage - << " num_partitions_merge_complete_: " << num_partitions_merge_complete_ - << " total_partitions: " << total_partitions << " n: " << n; - return percentage; -} - -bool UserSnapshotServer::RemoveAndJoinHandler(const std::string& misc_name) { - std::shared_ptr handler; - { - std::lock_guard lock(lock_); - - auto iter = FindHandler(&lock, misc_name); - if (iter == dm_users_.end()) { - // Client already deleted. - return true; - } - handler = std::move(*iter); - dm_users_.erase(iter); - } - - auto& th = handler->thread(); - if (th.joinable()) { - th.join(); - } - return true; -} - -void UserSnapshotServer::WakeupMonitorMergeThread() { - uint64_t notify = 1; - ssize_t rc = TEMP_FAILURE_RETRY(write(monitor_merge_event_fd_.get(), ¬ify, sizeof(notify))); - if (rc < 0) { - PLOG(FATAL) << "failed to notify monitor merge thread"; - } -} - -void UserSnapshotServer::MonitorMerge() { - while (!stop_monitor_merge_thread_) { - uint64_t testVal; - ssize_t ret = - TEMP_FAILURE_RETRY(read(monitor_merge_event_fd_.get(), &testVal, sizeof(testVal))); - if (ret == -1) { - PLOG(FATAL) << "Failed to read from eventfd"; - } else if (ret == 0) { - LOG(FATAL) << "Hit EOF on eventfd"; - } - - LOG(INFO) << "MonitorMerge: active-merge-threads: " << active_merge_threads_; - { - std::lock_guard lock(lock_); - while (active_merge_threads_ < kMaxMergeThreads && merge_handlers_.size() > 0) { - auto handler = merge_handlers_.front(); - merge_handlers_.pop(); - - if (!handler->snapuserd()) { - LOG(INFO) << "MonitorMerge: skipping deleted handler: " << handler->misc_name(); - continue; - } - - LOG(INFO) << "Starting merge for partition: " - << handler->snapuserd()->GetMiscName(); - handler->snapuserd()->InitiateMerge(); - active_merge_threads_ += 1; - } - } - } - - LOG(INFO) << "Exiting MonitorMerge: size: " << merge_handlers_.size(); + return handlers_->AddHandler(misc_name, cow_device_path, backing_device, base_path_merge, + num_worker_threads, io_uring_enabled_, perform_verification); } bool UserSnapshotServer::WaitForSocket() { - auto scope_guard = android::base::make_scope_guard([this]() -> void { JoinAllThreads(); }); + auto scope_guard = + android::base::make_scope_guard([this]() -> void { handlers_->JoinAllThreads(); }); auto socket_path = ANDROID_SOCKET_DIR "/"s + kSnapuserdSocketProxy; @@ -781,21 +494,8 @@ bool UserSnapshotServer::RunForSocketHandoff() { return true; } -bool UserSnapshotServer::UpdateVerification(std::lock_guard* proof_of_lock) { - CHECK(proof_of_lock); - - bool status = true; - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - auto& th = (*iter)->thread(); - if (th.joinable() && status) { - status = (*iter)->snapuserd()->CheckPartitionVerification() && status; - } else { - // return immediately if there is a failure - return false; - } - } - - return status; +bool UserSnapshotServer::StartHandler(const std::string& misc_name) { + return handlers_->StartHandler(misc_name); } } // namespace snapshot diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h index 12c3903c495c..ae5190391dfa 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h @@ -31,6 +31,7 @@ #include #include +#include "handler_manager.h" #include "snapuserd_core.h" namespace android { @@ -54,33 +55,6 @@ enum class DaemonOps { INVALID, }; -class HandlerThread { - public: - explicit HandlerThread(std::shared_ptr snapuserd); - - void FreeResources() { - // Each worker thread holds a reference to snapuserd. - // Clear them so that all the resources - // held by snapuserd is released - if (snapuserd_) { - snapuserd_->FreeResources(); - snapuserd_ = nullptr; - } - } - const std::shared_ptr& snapuserd() const { return snapuserd_; } - std::thread& thread() { return thread_; } - - const std::string& misc_name() const { return misc_name_; } - bool ThreadTerminated() { return thread_terminated_; } - void SetThreadTerminated() { thread_terminated_ = true; } - - private: - std::thread thread_; - std::shared_ptr snapuserd_; - std::string misc_name_; - bool thread_terminated_ = false; -}; - class UserSnapshotServer { private: android::base::unique_fd sockfd_; @@ -88,21 +62,12 @@ class UserSnapshotServer { volatile bool received_socket_signal_ = false; std::vector watched_fds_; bool is_socket_present_ = false; - int num_partitions_merge_complete_ = 0; - int active_merge_threads_ = 0; - bool stop_monitor_merge_thread_ = false; bool is_server_running_ = false; bool io_uring_enabled_ = false; - std::optional is_merge_monitor_started_; - - android::base::unique_fd monitor_merge_event_fd_; + std::unique_ptr handlers_; std::mutex lock_; - using HandlerList = std::vector>; - HandlerList dm_users_; - std::queue> merge_handlers_; - void AddWatchedFd(android::base::borrowed_fd fd, int events); void AcceptClient(); bool HandleClient(android::base::borrowed_fd fd, int revents); @@ -111,28 +76,15 @@ class UserSnapshotServer { bool Receivemsg(android::base::borrowed_fd fd, const std::string& str); void ShutdownThreads(); - bool RemoveAndJoinHandler(const std::string& control_device); DaemonOps Resolveop(std::string& input); std::string GetDaemonStatus(); void Parsemsg(std::string const& msg, const char delim, std::vector& out); bool IsTerminating() { return terminating_; } - void RunThread(std::shared_ptr handler); - void MonitorMerge(); - void JoinAllThreads(); bool StartWithSocket(bool start_listening); - // Find a HandlerThread within a lock. - HandlerList::iterator FindHandler(std::lock_guard* proof_of_lock, - const std::string& misc_name); - - double GetMergePercentage(std::lock_guard* proof_of_lock); - void TerminateMergeThreads(std::lock_guard* proof_of_lock); - - bool UpdateVerification(std::lock_guard* proof_of_lock); - public: UserSnapshotServer(); ~UserSnapshotServer(); @@ -147,12 +99,8 @@ class UserSnapshotServer { const std::string& cow_device_path, const std::string& backing_device, const std::string& base_path_merge); - bool StartHandler(const std::shared_ptr& handler); - bool StartMerge(std::lock_guard* proof_of_lock, - const std::shared_ptr& handler); - std::string GetMergeStatus(const std::shared_ptr& handler); + bool StartHandler(const std::string& misc_name); - void WakeupMonitorMergeThread(); void SetTerminating() { terminating_ = true; } void ReceivedSocketSignal() { received_socket_signal_ = true; } void SetServerRunning() { is_server_running_ = true; } From 1c29014458a0b47c92b46e39c99db6c3482054d7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 14 Mar 2023 09:09:48 -0700 Subject: [PATCH 0197/1487] snapuserd: Remove DaemonOps. These are only used for a single switch statement. Just compare the input strings instead. Bug: 269361087 Test: builds, ota applies Ignore-AOSP-First: cherry-pick from aosp (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:f84f9c319e5a05fa6bfed9730ea6b9d28407a84b) Merged-In: Ib90ae55309ea99c181585c64ed2ac814e5ed6c72 Change-Id: Ib90ae55309ea99c181585c64ed2ac814e5ed6c72 --- .../user-space-merge/snapuserd_server.cpp | 218 ++++++++---------- .../user-space-merge/snapuserd_server.h | 16 -- 2 files changed, 94 insertions(+), 140 deletions(-) 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 cc8115f5f800..d87990aca2a8 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp @@ -45,22 +45,6 @@ using namespace std::string_literals; using android::base::borrowed_fd; using android::base::unique_fd; -DaemonOps UserSnapshotServer::Resolveop(std::string& input) { - if (input == "init") return DaemonOps::INIT; - if (input == "start") return DaemonOps::START; - if (input == "stop") return DaemonOps::STOP; - if (input == "query") return DaemonOps::QUERY; - if (input == "delete") return DaemonOps::DELETE; - if (input == "detach") return DaemonOps::DETACH; - if (input == "supports") return DaemonOps::SUPPORTS; - if (input == "initiate_merge") return DaemonOps::INITIATE; - if (input == "merge_percent") return DaemonOps::PERCENTAGE; - if (input == "getstatus") return DaemonOps::GETSTATUS; - if (input == "update-verify") return DaemonOps::UPDATE_VERIFY; - - return DaemonOps::INVALID; -} - UserSnapshotServer::UserSnapshotServer() { terminating_ = false; handlers_ = std::make_unique(); @@ -132,132 +116,118 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st std::vector out; Parsemsg(str, delim, out); - DaemonOps op = Resolveop(out[0]); - - switch (op) { - case DaemonOps::INIT: { - // Message format: - // init,,,, - // - // Reads the metadata and send the number of sectors - if (out.size() != 5) { - LOG(ERROR) << "Malformed init message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - auto handler = AddHandler(out[1], out[2], out[3], out[4]); - if (!handler) { - return Sendmsg(fd, "fail"); - } - - auto retval = "success," + std::to_string(handler->snapuserd()->GetNumSectors()); - return Sendmsg(fd, retval); + const auto& cmd = out[0]; + if (cmd == "init") { + // Message format: + // init,,,, + // + // Reads the metadata and send the number of sectors + if (out.size() != 5) { + LOG(ERROR) << "Malformed init message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::START: { - // Message format: - // start, - // - // Start the new thread which binds to dm-user misc device - if (out.size() != 2) { - LOG(ERROR) << "Malformed start message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (!handlers_->StartHandler(out[1])) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); - } - case DaemonOps::STOP: { - // Message format: stop - // - // Stop all the threads gracefully and then shutdown the - // main thread - SetTerminating(); - ShutdownThreads(); - return true; + auto handler = AddHandler(out[1], out[2], out[3], out[4]); + if (!handler) { + return Sendmsg(fd, "fail"); } - case DaemonOps::QUERY: { - // Message format: query - // - // As part of transition, Second stage daemon will be - // created before terminating the first stage daemon. Hence, - // for a brief period client may have to distiguish between - // first stage daemon and second stage daemon. - // - // Second stage daemon is marked as active and hence will - // be ready to receive control message. - return Sendmsg(fd, GetDaemonStatus()); + + auto retval = "success," + std::to_string(handler->snapuserd()->GetNumSectors()); + return Sendmsg(fd, retval); + } else if (cmd == "start") { + // Message format: + // start, + // + // Start the new thread which binds to dm-user misc device + if (out.size() != 2) { + LOG(ERROR) << "Malformed start message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::DELETE: { - // Message format: - // delete, - if (out.size() != 2) { - LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (!handlers_->DeleteHandler(out[1])) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); + + if (!handlers_->StartHandler(out[1])) { + return Sendmsg(fd, "fail"); } - case DaemonOps::DETACH: { - handlers_->TerminateMergeThreads(); - terminating_ = true; - return true; + return Sendmsg(fd, "success"); + } else if (cmd == "stop") { + // Message format: stop + // + // Stop all the threads gracefully and then shutdown the + // main thread + SetTerminating(); + ShutdownThreads(); + return true; + } else if (cmd == "query") { + // Message format: query + // + // As part of transition, Second stage daemon will be + // created before terminating the first stage daemon. Hence, + // for a brief period client may have to distiguish between + // first stage daemon and second stage daemon. + // + // Second stage daemon is marked as active and hence will + // be ready to receive control message. + return Sendmsg(fd, GetDaemonStatus()); + } else if (cmd == "delete") { + // Message format: + // delete, + if (out.size() != 2) { + LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::SUPPORTS: { - if (out.size() != 2) { - LOG(ERROR) << "Malformed supports message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (out[1] == "second_stage_socket_handoff") { - return Sendmsg(fd, "success"); - } + if (!handlers_->DeleteHandler(out[1])) { return Sendmsg(fd, "fail"); } - case DaemonOps::INITIATE: { - if (out.size() != 2) { - LOG(ERROR) << "Malformed initiate-merge message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (out[0] == "initiate_merge") { - if (!handlers_->InitiateMerge(out[1])) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); - } + return Sendmsg(fd, "success"); + } else if (cmd == "detach") { + handlers_->TerminateMergeThreads(); + terminating_ = true; + return true; + } else if (cmd == "supports") { + if (out.size() != 2) { + LOG(ERROR) << "Malformed supports message, " << out.size() << " parts"; return Sendmsg(fd, "fail"); } - case DaemonOps::PERCENTAGE: { - double percentage = handlers_->GetMergePercentage(); - - return Sendmsg(fd, std::to_string(percentage)); + if (out[1] == "second_stage_socket_handoff") { + return Sendmsg(fd, "success"); } - case DaemonOps::GETSTATUS: { - // Message format: - // getstatus, - if (out.size() != 2) { - LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; - return Sendmsg(fd, "snapshot-merge-failed"); - } - auto status = handlers_->GetMergeStatus(out[1]); - if (status.empty()) { - return Sendmsg(fd, "snapshot-merge-failed"); - } - return Sendmsg(fd, status); + return Sendmsg(fd, "fail"); + } else if (cmd == "initiate_merge") { + if (out.size() != 2) { + LOG(ERROR) << "Malformed initiate-merge message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::UPDATE_VERIFY: { - if (!handlers_->GetVerificationStatus()) { + if (out[0] == "initiate_merge") { + if (!handlers_->InitiateMerge(out[1])) { return Sendmsg(fd, "fail"); } return Sendmsg(fd, "success"); } - default: { - LOG(ERROR) << "Received unknown message type from client"; - Sendmsg(fd, "fail"); - return false; + return Sendmsg(fd, "fail"); + } else if (cmd == "merge_percent") { + double percentage = handlers_->GetMergePercentage(); + return Sendmsg(fd, std::to_string(percentage)); + } else if (cmd == "getstatus") { + // Message format: + // getstatus, + if (out.size() != 2) { + LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; + return Sendmsg(fd, "snapshot-merge-failed"); + } + auto status = handlers_->GetMergeStatus(out[1]); + if (status.empty()) { + return Sendmsg(fd, "snapshot-merge-failed"); } + return Sendmsg(fd, status); + } else if (cmd == "update-verify") { + if (!handlers_->GetVerificationStatus()) { + return Sendmsg(fd, "fail"); + } + return Sendmsg(fd, "success"); + } else { + LOG(ERROR) << "Received unknown message type from client"; + Sendmsg(fd, "fail"); + return false; } } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h index ae5190391dfa..988c01a99ba3 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h @@ -40,21 +40,6 @@ namespace snapshot { static constexpr uint32_t kMaxPacketSize = 512; static constexpr uint8_t kMaxMergeThreads = 2; -enum class DaemonOps { - INIT, - START, - QUERY, - STOP, - DELETE, - DETACH, - SUPPORTS, - INITIATE, - PERCENTAGE, - GETSTATUS, - UPDATE_VERIFY, - INVALID, -}; - class UserSnapshotServer { private: android::base::unique_fd sockfd_; @@ -76,7 +61,6 @@ class UserSnapshotServer { bool Receivemsg(android::base::borrowed_fd fd, const std::string& str); void ShutdownThreads(); - DaemonOps Resolveop(std::string& input); std::string GetDaemonStatus(); void Parsemsg(std::string const& msg, const char delim, std::vector& out); From 06d9d8745407256f47e51415b26cd77dcb7f9752 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 14 Mar 2023 10:57:47 -0700 Subject: [PATCH 0198/1487] snapuserd: Run snapuserd threads in-process. This removes the temporary daemon and socket and instead directly embeds SnapshotHandlerManager. We can also remove the test flags for io_uring as with this they're no longer necessary. Bug: 269361087 Test: snapuserd_test Ignore-AOSP-First: cherry-pick from aosp (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:269e99f9558ae332e10329451fc51dc6698375a0) Merged-In: I728186d9bc90c98fabd76d3f86569840488ada96 Change-Id: I728186d9bc90c98fabd76d3f86569840488ada96 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 15 ++-- .../user-space-merge/handler_manager.cpp | 3 + .../user-space-merge/snapuserd_core.cpp | 5 -- .../user-space-merge/snapuserd_server.cpp | 3 - .../user-space-merge/snapuserd_test.cpp | 75 ++++++------------- 5 files changed, 33 insertions(+), 68 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 65f3d6d297ed..9fe567acbc7e 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -165,7 +165,7 @@ cc_binary { } cc_test { - name: "cow_snapuserd_test", + name: "snapuserd_test_legacy", defaults: [ "fs_mgr_defaults", "libsnapshot_cow_defaults", @@ -217,16 +217,17 @@ cc_test { ], static_libs: [ "libbrotli", - "libgtest", - "libsnapshot_cow", - "libsnapshot_snapuserd", "libcutils_sockets", - "libz", - "libfs_mgr", "libdm", "libext4_utils", - "liburing", + "libfs_mgr", "libgflags", + "libgtest", + "libsnapshot_cow", + "libsnapshot_snapuserd", + "libsnapuserd", + "liburing", + "libz", ], include_dirs: ["bionic/libc/kernel"], header_libs: [ 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 c5150c411d02..bdba5c0cc3ab 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 @@ namespace snapshot { static constexpr uint8_t kMaxMergeThreads = 2; +HandlerThread::HandlerThread(std::shared_ptr 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 c8a5cc584a28..8e1212b7b3ce 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -421,11 +421,6 @@ bool SnapshotHandler::IsIouringSupported() { 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 d87990aca2a8..c953f1a053bd 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 @@ void UserSnapshotServer::ShutdownThreads() { handlers_->JoinAllThreads(); } -HandlerThread::HandlerThread(std::shared_ptr 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 ef3689f61f6b..efe0c1443215 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 #include #include -#include #include +#include "handler_manager.h" #include "snapuserd_core.h" DEFINE_string(force_config, "", "Force testing mode with iouring disabled"); @@ -54,8 +54,6 @@ using namespace std::chrono_literals; 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 @@ class Tempdevice { } ~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_; } @@ -139,7 +137,6 @@ class SnapuserdTest : public ::testing::Test { void SetDeviceControlName(); void InitDaemon(); void CreateDmUserDevice(); - void StartSnapuserdDaemon(); unique_ptr base_loop_; unique_ptr dmuser_dev_; @@ -149,9 +146,9 @@ class SnapuserdTest : public ::testing::Test { unique_fd base_fd_; std::unique_ptr cow_system_; - std::unique_ptr client_; std::unique_ptr orig_buffer_; std::unique_ptr merged_buffer_; + SnapshotHandlerManager handlers_; bool setup_ok_ = false; bool merge_ok_ = false; size_t size_ = 100_MiB; @@ -181,9 +178,9 @@ void SnapuserdTest::Shutdown() { 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() { @@ -218,8 +215,6 @@ bool SnapuserdTest::SetupCopyOverlap_2() { bool SnapuserdTest::SetupDaemon() { SetDeviceControlName(); - StartSnapuserdDaemon(); - CreateDmUserDevice(); InitCowDevice(); InitDaemon(); @@ -229,20 +224,6 @@ bool SnapuserdTest::SetupDaemon() { 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; @@ -591,9 +572,17 @@ void SnapuserdTest::CreateCowDevice() { } 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() { @@ -631,13 +620,12 @@ void SnapuserdTest::CreateDmUserDevice() { } 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; } @@ -652,8 +640,6 @@ void SnapuserdTest::SetupImpl() { SetDeviceControlName(); - StartSnapuserdDaemon(); - CreateDmUserDevice(); InitCowDevice(); InitDaemon(); @@ -669,8 +655,7 @@ bool SnapuserdTest::Merge() { } 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() { @@ -684,7 +669,6 @@ void SnapuserdTest::SimulateDaemonRestart() { Shutdown(); std::this_thread::sleep_for(500ms); SetDeviceControlName(); - StartSnapuserdDaemon(); CreateDmUserDevice(); InitCowDevice(); InitDaemon(); @@ -844,20 +828,5 @@ int main(int argc, char** argv) { 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(); } From 7445be510f4e782a1519116f60d0ddbce613e33c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 14 Mar 2023 09:09:48 -0700 Subject: [PATCH 0199/1487] snapuserd: Remove DaemonOps. These are only used for a single switch statement. Just compare the input strings instead. Bug: 269361087 Test: builds, ota applies Ignore-AOSP-First: cherry-pick from aosp (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:f84f9c319e5a05fa6bfed9730ea6b9d28407a84b) Merged-In: Ib90ae55309ea99c181585c64ed2ac814e5ed6c72 Change-Id: Ib90ae55309ea99c181585c64ed2ac814e5ed6c72 --- .../user-space-merge/snapuserd_server.cpp | 218 ++++++++---------- .../user-space-merge/snapuserd_server.h | 16 -- 2 files changed, 94 insertions(+), 140 deletions(-) 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 cc8115f5f800..d87990aca2a8 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp @@ -45,22 +45,6 @@ using namespace std::string_literals; using android::base::borrowed_fd; using android::base::unique_fd; -DaemonOps UserSnapshotServer::Resolveop(std::string& input) { - if (input == "init") return DaemonOps::INIT; - if (input == "start") return DaemonOps::START; - if (input == "stop") return DaemonOps::STOP; - if (input == "query") return DaemonOps::QUERY; - if (input == "delete") return DaemonOps::DELETE; - if (input == "detach") return DaemonOps::DETACH; - if (input == "supports") return DaemonOps::SUPPORTS; - if (input == "initiate_merge") return DaemonOps::INITIATE; - if (input == "merge_percent") return DaemonOps::PERCENTAGE; - if (input == "getstatus") return DaemonOps::GETSTATUS; - if (input == "update-verify") return DaemonOps::UPDATE_VERIFY; - - return DaemonOps::INVALID; -} - UserSnapshotServer::UserSnapshotServer() { terminating_ = false; handlers_ = std::make_unique(); @@ -132,132 +116,118 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st std::vector out; Parsemsg(str, delim, out); - DaemonOps op = Resolveop(out[0]); - - switch (op) { - case DaemonOps::INIT: { - // Message format: - // init,,,, - // - // Reads the metadata and send the number of sectors - if (out.size() != 5) { - LOG(ERROR) << "Malformed init message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - auto handler = AddHandler(out[1], out[2], out[3], out[4]); - if (!handler) { - return Sendmsg(fd, "fail"); - } - - auto retval = "success," + std::to_string(handler->snapuserd()->GetNumSectors()); - return Sendmsg(fd, retval); + const auto& cmd = out[0]; + if (cmd == "init") { + // Message format: + // init,,,, + // + // Reads the metadata and send the number of sectors + if (out.size() != 5) { + LOG(ERROR) << "Malformed init message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::START: { - // Message format: - // start, - // - // Start the new thread which binds to dm-user misc device - if (out.size() != 2) { - LOG(ERROR) << "Malformed start message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (!handlers_->StartHandler(out[1])) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); - } - case DaemonOps::STOP: { - // Message format: stop - // - // Stop all the threads gracefully and then shutdown the - // main thread - SetTerminating(); - ShutdownThreads(); - return true; + auto handler = AddHandler(out[1], out[2], out[3], out[4]); + if (!handler) { + return Sendmsg(fd, "fail"); } - case DaemonOps::QUERY: { - // Message format: query - // - // As part of transition, Second stage daemon will be - // created before terminating the first stage daemon. Hence, - // for a brief period client may have to distiguish between - // first stage daemon and second stage daemon. - // - // Second stage daemon is marked as active and hence will - // be ready to receive control message. - return Sendmsg(fd, GetDaemonStatus()); + + auto retval = "success," + std::to_string(handler->snapuserd()->GetNumSectors()); + return Sendmsg(fd, retval); + } else if (cmd == "start") { + // Message format: + // start, + // + // Start the new thread which binds to dm-user misc device + if (out.size() != 2) { + LOG(ERROR) << "Malformed start message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::DELETE: { - // Message format: - // delete, - if (out.size() != 2) { - LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (!handlers_->DeleteHandler(out[1])) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); + + if (!handlers_->StartHandler(out[1])) { + return Sendmsg(fd, "fail"); } - case DaemonOps::DETACH: { - handlers_->TerminateMergeThreads(); - terminating_ = true; - return true; + return Sendmsg(fd, "success"); + } else if (cmd == "stop") { + // Message format: stop + // + // Stop all the threads gracefully and then shutdown the + // main thread + SetTerminating(); + ShutdownThreads(); + return true; + } else if (cmd == "query") { + // Message format: query + // + // As part of transition, Second stage daemon will be + // created before terminating the first stage daemon. Hence, + // for a brief period client may have to distiguish between + // first stage daemon and second stage daemon. + // + // Second stage daemon is marked as active and hence will + // be ready to receive control message. + return Sendmsg(fd, GetDaemonStatus()); + } else if (cmd == "delete") { + // Message format: + // delete, + if (out.size() != 2) { + LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::SUPPORTS: { - if (out.size() != 2) { - LOG(ERROR) << "Malformed supports message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (out[1] == "second_stage_socket_handoff") { - return Sendmsg(fd, "success"); - } + if (!handlers_->DeleteHandler(out[1])) { return Sendmsg(fd, "fail"); } - case DaemonOps::INITIATE: { - if (out.size() != 2) { - LOG(ERROR) << "Malformed initiate-merge message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (out[0] == "initiate_merge") { - if (!handlers_->InitiateMerge(out[1])) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); - } + return Sendmsg(fd, "success"); + } else if (cmd == "detach") { + handlers_->TerminateMergeThreads(); + terminating_ = true; + return true; + } else if (cmd == "supports") { + if (out.size() != 2) { + LOG(ERROR) << "Malformed supports message, " << out.size() << " parts"; return Sendmsg(fd, "fail"); } - case DaemonOps::PERCENTAGE: { - double percentage = handlers_->GetMergePercentage(); - - return Sendmsg(fd, std::to_string(percentage)); + if (out[1] == "second_stage_socket_handoff") { + return Sendmsg(fd, "success"); } - case DaemonOps::GETSTATUS: { - // Message format: - // getstatus, - if (out.size() != 2) { - LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; - return Sendmsg(fd, "snapshot-merge-failed"); - } - auto status = handlers_->GetMergeStatus(out[1]); - if (status.empty()) { - return Sendmsg(fd, "snapshot-merge-failed"); - } - return Sendmsg(fd, status); + return Sendmsg(fd, "fail"); + } else if (cmd == "initiate_merge") { + if (out.size() != 2) { + LOG(ERROR) << "Malformed initiate-merge message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::UPDATE_VERIFY: { - if (!handlers_->GetVerificationStatus()) { + if (out[0] == "initiate_merge") { + if (!handlers_->InitiateMerge(out[1])) { return Sendmsg(fd, "fail"); } return Sendmsg(fd, "success"); } - default: { - LOG(ERROR) << "Received unknown message type from client"; - Sendmsg(fd, "fail"); - return false; + return Sendmsg(fd, "fail"); + } else if (cmd == "merge_percent") { + double percentage = handlers_->GetMergePercentage(); + return Sendmsg(fd, std::to_string(percentage)); + } else if (cmd == "getstatus") { + // Message format: + // getstatus, + if (out.size() != 2) { + LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; + return Sendmsg(fd, "snapshot-merge-failed"); + } + auto status = handlers_->GetMergeStatus(out[1]); + if (status.empty()) { + return Sendmsg(fd, "snapshot-merge-failed"); } + return Sendmsg(fd, status); + } else if (cmd == "update-verify") { + if (!handlers_->GetVerificationStatus()) { + return Sendmsg(fd, "fail"); + } + return Sendmsg(fd, "success"); + } else { + LOG(ERROR) << "Received unknown message type from client"; + Sendmsg(fd, "fail"); + return false; } } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h index ae5190391dfa..988c01a99ba3 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h @@ -40,21 +40,6 @@ namespace snapshot { static constexpr uint32_t kMaxPacketSize = 512; static constexpr uint8_t kMaxMergeThreads = 2; -enum class DaemonOps { - INIT, - START, - QUERY, - STOP, - DELETE, - DETACH, - SUPPORTS, - INITIATE, - PERCENTAGE, - GETSTATUS, - UPDATE_VERIFY, - INVALID, -}; - class UserSnapshotServer { private: android::base::unique_fd sockfd_; @@ -76,7 +61,6 @@ class UserSnapshotServer { bool Receivemsg(android::base::borrowed_fd fd, const std::string& str); void ShutdownThreads(); - DaemonOps Resolveop(std::string& input); std::string GetDaemonStatus(); void Parsemsg(std::string const& msg, const char delim, std::vector& out); From 54d326c5e090df2b5739bb09e2ebb37bf281f0ce Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 14 Mar 2023 10:57:47 -0700 Subject: [PATCH 0200/1487] snapuserd: Run snapuserd threads in-process. This removes the temporary daemon and socket and instead directly embeds SnapshotHandlerManager. We can also remove the test flags for io_uring as with this they're no longer necessary. Bug: 269361087 Test: snapuserd_test Ignore-AOSP-First: cherry-pick from aosp (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:269e99f9558ae332e10329451fc51dc6698375a0) Merged-In: I728186d9bc90c98fabd76d3f86569840488ada96 Change-Id: I728186d9bc90c98fabd76d3f86569840488ada96 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 15 ++-- .../user-space-merge/handler_manager.cpp | 3 + .../user-space-merge/snapuserd_core.cpp | 5 -- .../user-space-merge/snapuserd_server.cpp | 3 - .../user-space-merge/snapuserd_test.cpp | 75 ++++++------------- 5 files changed, 33 insertions(+), 68 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 65f3d6d297ed..9fe567acbc7e 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -165,7 +165,7 @@ cc_binary { } cc_test { - name: "cow_snapuserd_test", + name: "snapuserd_test_legacy", defaults: [ "fs_mgr_defaults", "libsnapshot_cow_defaults", @@ -217,16 +217,17 @@ cc_test { ], static_libs: [ "libbrotli", - "libgtest", - "libsnapshot_cow", - "libsnapshot_snapuserd", "libcutils_sockets", - "libz", - "libfs_mgr", "libdm", "libext4_utils", - "liburing", + "libfs_mgr", "libgflags", + "libgtest", + "libsnapshot_cow", + "libsnapshot_snapuserd", + "libsnapuserd", + "liburing", + "libz", ], include_dirs: ["bionic/libc/kernel"], header_libs: [ 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 c5150c411d02..bdba5c0cc3ab 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 @@ namespace snapshot { static constexpr uint8_t kMaxMergeThreads = 2; +HandlerThread::HandlerThread(std::shared_ptr 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 c8a5cc584a28..8e1212b7b3ce 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -421,11 +421,6 @@ bool SnapshotHandler::IsIouringSupported() { 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 d87990aca2a8..c953f1a053bd 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 @@ void UserSnapshotServer::ShutdownThreads() { handlers_->JoinAllThreads(); } -HandlerThread::HandlerThread(std::shared_ptr 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 ef3689f61f6b..efe0c1443215 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 #include #include -#include #include +#include "handler_manager.h" #include "snapuserd_core.h" DEFINE_string(force_config, "", "Force testing mode with iouring disabled"); @@ -54,8 +54,6 @@ using namespace std::chrono_literals; 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 @@ class Tempdevice { } ~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_; } @@ -139,7 +137,6 @@ class SnapuserdTest : public ::testing::Test { void SetDeviceControlName(); void InitDaemon(); void CreateDmUserDevice(); - void StartSnapuserdDaemon(); unique_ptr base_loop_; unique_ptr dmuser_dev_; @@ -149,9 +146,9 @@ class SnapuserdTest : public ::testing::Test { unique_fd base_fd_; std::unique_ptr cow_system_; - std::unique_ptr client_; std::unique_ptr orig_buffer_; std::unique_ptr merged_buffer_; + SnapshotHandlerManager handlers_; bool setup_ok_ = false; bool merge_ok_ = false; size_t size_ = 100_MiB; @@ -181,9 +178,9 @@ void SnapuserdTest::Shutdown() { 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() { @@ -218,8 +215,6 @@ bool SnapuserdTest::SetupCopyOverlap_2() { bool SnapuserdTest::SetupDaemon() { SetDeviceControlName(); - StartSnapuserdDaemon(); - CreateDmUserDevice(); InitCowDevice(); InitDaemon(); @@ -229,20 +224,6 @@ bool SnapuserdTest::SetupDaemon() { 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; @@ -591,9 +572,17 @@ void SnapuserdTest::CreateCowDevice() { } 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() { @@ -631,13 +620,12 @@ void SnapuserdTest::CreateDmUserDevice() { } 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; } @@ -652,8 +640,6 @@ void SnapuserdTest::SetupImpl() { SetDeviceControlName(); - StartSnapuserdDaemon(); - CreateDmUserDevice(); InitCowDevice(); InitDaemon(); @@ -669,8 +655,7 @@ bool SnapuserdTest::Merge() { } 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() { @@ -684,7 +669,6 @@ void SnapuserdTest::SimulateDaemonRestart() { Shutdown(); std::this_thread::sleep_for(500ms); SetDeviceControlName(); - StartSnapuserdDaemon(); CreateDmUserDevice(); InitCowDevice(); InitDaemon(); @@ -844,20 +828,5 @@ int main(int argc, char** argv) { 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(); } From 21089f8b46f5f415fb3944bf8e774f4d09cb3f5c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 17 Feb 2023 01:20:52 -0800 Subject: [PATCH 0201/1487] snapuserd: Split the server into two classes. This splits server into two classes: one that handles the IPC requests, and one that managers snapshot handlers. This will allow embedding of the snapshot handling code, without booting up a server. It'll also make testing much easier. The handler code has been further placed behind a virtual interface, though this is likely unnecessary unless we start testing the server logic itself (or attempt to unify the S and T+ versions of snapuserd). Bug: 269361087 Test: ota Ignore-AOSP-First: cherry-pick from aosp (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:8bb751dc8a1499f24add9e0831ab347feb2c3878) Merged-In: I3ca3ad9c8c1fb910a1c7bf9f44165e2f44c930c9 Change-Id: I3ca3ad9c8c1fb910a1c7bf9f44165e2f44c930c9 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 1 + .../snapuserd/snapuserd_daemon.cpp | 2 +- .../user-space-merge/handler_manager.cpp | 371 ++++++++++++++++++ .../user-space-merge/handler_manager.h | 131 +++++++ .../user-space-merge/snapuserd_server.cpp | 338 +--------------- .../user-space-merge/snapuserd_server.h | 58 +-- 6 files changed, 526 insertions(+), 375 deletions(-) create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index dd11a33daf28..65f3d6d297ed 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -62,6 +62,7 @@ cc_library_static { "dm-snapshot-merge/snapuserd_worker.cpp", "dm-snapshot-merge/snapuserd_readahead.cpp", "snapuserd_buffer.cpp", + "user-space-merge/handler_manager.cpp", "user-space-merge/snapuserd_core.cpp", "user-space-merge/snapuserd_dm_user.cpp", "user-space-merge/snapuserd_merge.cpp", diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp index ae20e1fa479e..36dad3343d3e 100644 --- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp +++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp @@ -114,7 +114,7 @@ bool Daemon::StartServerForUserspaceSnapshots(int arg_start, int argc, char** ar return false; } auto handler = user_server_.AddHandler(parts[0], parts[1], parts[2], parts[3]); - if (!handler || !user_server_.StartHandler(handler)) { + if (!handler || !user_server_.StartHandler(parts[0])) { return false; } } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp new file mode 100644 index 000000000000..c5150c411d02 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp @@ -0,0 +1,371 @@ +// Copyright (C) 2023 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 "handler_manager.h" + +#include + +#include + +#include "snapuserd_core.h" + +namespace android { +namespace snapshot { + +static constexpr uint8_t kMaxMergeThreads = 2; + +void HandlerThread::FreeResources() { + // Each worker thread holds a reference to snapuserd. + // Clear them so that all the resources + // held by snapuserd is released + if (snapuserd_) { + snapuserd_->FreeResources(); + snapuserd_ = nullptr; + } +} + +SnapshotHandlerManager::SnapshotHandlerManager() { + monitor_merge_event_fd_.reset(eventfd(0, EFD_CLOEXEC)); + if (monitor_merge_event_fd_ == -1) { + PLOG(FATAL) << "monitor_merge_event_fd_: failed to create eventfd"; + } +} + +std::shared_ptr SnapshotHandlerManager::AddHandler( + const std::string& misc_name, const std::string& cow_device_path, + const std::string& backing_device, const std::string& base_path_merge, + int num_worker_threads, bool use_iouring, bool perform_verification) { + auto snapuserd = std::make_shared(misc_name, cow_device_path, backing_device, + base_path_merge, num_worker_threads, + use_iouring, perform_verification); + if (!snapuserd->InitCowDevice()) { + LOG(ERROR) << "Failed to initialize Snapuserd"; + return nullptr; + } + + if (!snapuserd->InitializeWorkers()) { + LOG(ERROR) << "Failed to initialize workers"; + return nullptr; + } + + auto handler = std::make_shared(snapuserd); + { + std::lock_guard lock(lock_); + if (FindHandler(&lock, misc_name) != dm_users_.end()) { + LOG(ERROR) << "Handler already exists: " << misc_name; + return nullptr; + } + dm_users_.push_back(handler); + } + return handler; +} + +bool SnapshotHandlerManager::StartHandler(const std::string& misc_name) { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + LOG(ERROR) << "Could not find handler: " << misc_name; + return false; + } + if (!(*iter)->snapuserd() || (*iter)->snapuserd()->IsAttached()) { + LOG(ERROR) << "Tried to re-attach control device: " << misc_name; + return false; + } + if (!StartHandler(*iter)) { + return false; + } + return true; +} + +bool SnapshotHandlerManager::StartHandler(const std::shared_ptr& handler) { + if (handler->snapuserd()->IsAttached()) { + LOG(ERROR) << "Handler already attached"; + return false; + } + + handler->snapuserd()->AttachControlDevice(); + + handler->thread() = std::thread(std::bind(&SnapshotHandlerManager::RunThread, this, handler)); + return true; +} + +bool SnapshotHandlerManager::DeleteHandler(const std::string& misc_name) { + { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + // After merge is completed, we swap dm-user table with + // the underlying dm-linear base device. Hence, worker + // threads would have terminted and was removed from + // the list. + LOG(DEBUG) << "Could not find handler: " << misc_name; + return true; + } + + if (!(*iter)->ThreadTerminated()) { + (*iter)->snapuserd()->NotifyIOTerminated(); + } + } + if (!RemoveAndJoinHandler(misc_name)) { + return false; + } + return true; +} + +void SnapshotHandlerManager::RunThread(std::shared_ptr handler) { + LOG(INFO) << "Entering thread for handler: " << handler->misc_name(); + + if (!handler->snapuserd()->Start()) { + LOG(ERROR) << " Failed to launch all worker threads"; + } + + handler->snapuserd()->CloseFds(); + bool merge_completed = handler->snapuserd()->CheckMergeCompletionStatus(); + handler->snapuserd()->UnmapBufferRegion(); + + auto misc_name = handler->misc_name(); + LOG(INFO) << "Handler thread about to exit: " << misc_name; + + { + std::lock_guard lock(lock_); + if (merge_completed) { + num_partitions_merge_complete_ += 1; + active_merge_threads_ -= 1; + WakeupMonitorMergeThread(); + } + handler->SetThreadTerminated(); + auto iter = FindHandler(&lock, handler->misc_name()); + if (iter == dm_users_.end()) { + // RemoveAndJoinHandler() already removed us from the list, and is + // now waiting on a join(), so just return. Additionally, release + // all the resources held by snapuserd object which are shared + // by worker threads. This should be done when the last reference + // of "handler" is released; but we will explicitly release here + // to make sure snapuserd object is freed as it is the biggest + // consumer of memory in the daemon. + handler->FreeResources(); + LOG(INFO) << "Exiting handler thread to allow for join: " << misc_name; + return; + } + + LOG(INFO) << "Exiting handler thread and freeing resources: " << misc_name; + + if (handler->snapuserd()->IsAttached()) { + handler->thread().detach(); + } + + // Important: free resources within the lock. This ensures that if + // WaitForDelete() is called, the handler is either in the list, or + // it's not and its resources are guaranteed to be freed. + handler->FreeResources(); + dm_users_.erase(iter); + } +} + +bool SnapshotHandlerManager::InitiateMerge(const std::string& misc_name) { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + LOG(ERROR) << "Could not find handler: " << misc_name; + return false; + } + + return StartMerge(&lock, *iter); +} + +bool SnapshotHandlerManager::StartMerge(std::lock_guard* proof_of_lock, + const std::shared_ptr& handler) { + CHECK(proof_of_lock); + + if (!handler->snapuserd()->IsAttached()) { + LOG(ERROR) << "Handler not attached to dm-user - Merge thread cannot be started"; + return false; + } + + handler->snapuserd()->MonitorMerge(); + + if (!is_merge_monitor_started_) { + std::thread(&SnapshotHandlerManager::MonitorMerge, this).detach(); + is_merge_monitor_started_ = true; + } + + merge_handlers_.push(handler); + WakeupMonitorMergeThread(); + return true; +} + +void SnapshotHandlerManager::WakeupMonitorMergeThread() { + uint64_t notify = 1; + ssize_t rc = TEMP_FAILURE_RETRY(write(monitor_merge_event_fd_.get(), ¬ify, sizeof(notify))); + if (rc < 0) { + PLOG(FATAL) << "failed to notify monitor merge thread"; + } +} + +void SnapshotHandlerManager::MonitorMerge() { + while (!stop_monitor_merge_thread_) { + uint64_t testVal; + ssize_t ret = + TEMP_FAILURE_RETRY(read(monitor_merge_event_fd_.get(), &testVal, sizeof(testVal))); + if (ret == -1) { + PLOG(FATAL) << "Failed to read from eventfd"; + } else if (ret == 0) { + LOG(FATAL) << "Hit EOF on eventfd"; + } + + LOG(INFO) << "MonitorMerge: active-merge-threads: " << active_merge_threads_; + { + std::lock_guard lock(lock_); + while (active_merge_threads_ < kMaxMergeThreads && merge_handlers_.size() > 0) { + auto handler = merge_handlers_.front(); + merge_handlers_.pop(); + + if (!handler->snapuserd()) { + LOG(INFO) << "MonitorMerge: skipping deleted handler: " << handler->misc_name(); + continue; + } + + LOG(INFO) << "Starting merge for partition: " + << handler->snapuserd()->GetMiscName(); + handler->snapuserd()->InitiateMerge(); + active_merge_threads_ += 1; + } + } + } + + LOG(INFO) << "Exiting MonitorMerge: size: " << merge_handlers_.size(); +} + +std::string SnapshotHandlerManager::GetMergeStatus(const std::string& misc_name) { + std::lock_guard lock(lock_); + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + LOG(ERROR) << "Could not find handler: " << misc_name; + return {}; + } + + return (*iter)->snapuserd()->GetMergeStatus(); +} + +double SnapshotHandlerManager::GetMergePercentage() { + std::lock_guard lock(lock_); + + double percentage = 0.0; + int n = 0; + + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + auto& th = (*iter)->thread(); + if (th.joinable()) { + // Merge percentage by individual partitions wherein merge is still + // in-progress + percentage += (*iter)->snapuserd()->GetMergePercentage(); + n += 1; + } + } + + // Calculate final merge including those partitions where merge was already + // completed - num_partitions_merge_complete_ will track them when each + // thread exists in RunThread. + int total_partitions = n + num_partitions_merge_complete_; + + if (total_partitions) { + percentage = ((num_partitions_merge_complete_ * 100.0) + percentage) / total_partitions; + } + + LOG(DEBUG) << "Merge %: " << percentage + << " num_partitions_merge_complete_: " << num_partitions_merge_complete_ + << " total_partitions: " << total_partitions << " n: " << n; + return percentage; +} + +bool SnapshotHandlerManager::GetVerificationStatus() { + std::lock_guard lock(lock_); + + bool status = true; + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + auto& th = (*iter)->thread(); + if (th.joinable() && status) { + status = (*iter)->snapuserd()->CheckPartitionVerification() && status; + } else { + // return immediately if there is a failure + return false; + } + } + + return status; +} + +bool SnapshotHandlerManager::RemoveAndJoinHandler(const std::string& misc_name) { + std::shared_ptr handler; + { + std::lock_guard lock(lock_); + + auto iter = FindHandler(&lock, misc_name); + if (iter == dm_users_.end()) { + // Client already deleted. + return true; + } + handler = std::move(*iter); + dm_users_.erase(iter); + } + + auto& th = handler->thread(); + if (th.joinable()) { + th.join(); + } + return true; +} + +void SnapshotHandlerManager::TerminateMergeThreads() { + std::lock_guard guard(lock_); + + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + if (!(*iter)->ThreadTerminated()) { + (*iter)->snapuserd()->NotifyIOTerminated(); + } + } +} + +void SnapshotHandlerManager::JoinAllThreads() { + // Acquire the thread list within the lock. + std::vector> dm_users; + { + std::lock_guard guard(lock_); + dm_users = std::move(dm_users_); + } + + for (auto& client : dm_users) { + auto& th = client->thread(); + + if (th.joinable()) th.join(); + } + + stop_monitor_merge_thread_ = true; + WakeupMonitorMergeThread(); +} + +auto SnapshotHandlerManager::FindHandler(std::lock_guard* proof_of_lock, + const std::string& misc_name) -> HandlerList::iterator { + CHECK(proof_of_lock); + + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + if ((*iter)->misc_name() == misc_name) { + return iter; + } + } + return dm_users_.end(); +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h new file mode 100644 index 000000000000..b7ddac19f28a --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h @@ -0,0 +1,131 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace android { +namespace snapshot { + +class SnapshotHandler; + +class HandlerThread { + public: + explicit HandlerThread(std::shared_ptr snapuserd); + + void FreeResources(); + const std::shared_ptr& snapuserd() const { return snapuserd_; } + std::thread& thread() { return thread_; } + + const std::string& misc_name() const { return misc_name_; } + bool ThreadTerminated() { return thread_terminated_; } + void SetThreadTerminated() { thread_terminated_ = true; } + + private: + std::thread thread_; + std::shared_ptr snapuserd_; + std::string misc_name_; + bool thread_terminated_ = false; +}; + +class ISnapshotHandlerManager { + public: + virtual ~ISnapshotHandlerManager() {} + + // Add a new snapshot handler but do not start serving requests yet. + virtual std::shared_ptr AddHandler(const std::string& misc_name, + const std::string& cow_device_path, + const std::string& backing_device, + const std::string& base_path_merge, + int num_worker_threads, bool use_iouring, + bool perform_verification) = 0; + + // Start serving requests on a snapshot handler. + virtual bool StartHandler(const std::string& misc_name) = 0; + + // Stop serving requests on a snapshot handler and remove it. + virtual bool DeleteHandler(const std::string& misc_name) = 0; + + // Begin merging blocks on the given snapshot handler. + virtual bool InitiateMerge(const std::string& misc_name) = 0; + + // Return a string containing a status code indicating the merge status + // on the handler. Returns empty on error. + virtual std::string GetMergeStatus(const std::string& misc_name) = 0; + + // Wait until all handlers have terminated. + virtual void JoinAllThreads() = 0; + + // Stop any in-progress merge threads. + virtual void TerminateMergeThreads() = 0; + + // Returns the merge progress across all merging snapshot handlers. + virtual double GetMergePercentage() = 0; + + // Returns whether all snapshots have verified. + virtual bool GetVerificationStatus() = 0; +}; + +class SnapshotHandlerManager final : public ISnapshotHandlerManager { + public: + SnapshotHandlerManager(); + std::shared_ptr AddHandler(const std::string& misc_name, + const std::string& cow_device_path, + const std::string& backing_device, + const std::string& base_path_merge, + int num_worker_threads, bool use_iouring, + bool perform_verification) override; + bool StartHandler(const std::string& misc_name) override; + bool DeleteHandler(const std::string& misc_name) override; + bool InitiateMerge(const std::string& misc_name) override; + std::string GetMergeStatus(const std::string& misc_name) override; + void JoinAllThreads() override; + void TerminateMergeThreads() override; + double GetMergePercentage() override; + bool GetVerificationStatus() override; + + private: + bool StartHandler(const std::shared_ptr& handler); + void RunThread(std::shared_ptr handler); + bool StartMerge(std::lock_guard* proof_of_lock, + const std::shared_ptr& handler); + void MonitorMerge(); + void WakeupMonitorMergeThread(); + bool RemoveAndJoinHandler(const std::string& misc_name); + + // Find a HandlerThread within a lock. + using HandlerList = std::vector>; + HandlerList::iterator FindHandler(std::lock_guard* proof_of_lock, + const std::string& misc_name); + + std::mutex lock_; + HandlerList dm_users_; + + bool is_merge_monitor_started_ = false; + bool stop_monitor_merge_thread_ = false; + int active_merge_threads_ = 0; + int num_partitions_merge_complete_ = 0; + std::queue> merge_handlers_; + android::base::unique_fd monitor_merge_event_fd_; +}; + +} // namespace snapshot +} // namespace android 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 b7ce2109adfe..cc8115f5f800 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp @@ -62,11 +62,8 @@ DaemonOps UserSnapshotServer::Resolveop(std::string& input) { } UserSnapshotServer::UserSnapshotServer() { - monitor_merge_event_fd_.reset(eventfd(0, EFD_CLOEXEC)); - if (monitor_merge_event_fd_ == -1) { - PLOG(FATAL) << "monitor_merge_event_fd_: failed to create eventfd"; - } terminating_ = false; + handlers_ = std::make_unique(); } UserSnapshotServer::~UserSnapshotServer() { @@ -99,7 +96,7 @@ void UserSnapshotServer::Parsemsg(std::string const& msg, const char delim, void UserSnapshotServer::ShutdownThreads() { terminating_ = true; - JoinAllThreads(); + handlers_->JoinAllThreads(); } HandlerThread::HandlerThread(std::shared_ptr snapuserd) @@ -166,17 +163,7 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st return Sendmsg(fd, "fail"); } - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - LOG(ERROR) << "Could not find handler: " << out[1]; - return Sendmsg(fd, "fail"); - } - if (!(*iter)->snapuserd() || (*iter)->snapuserd()->IsAttached()) { - LOG(ERROR) << "Tried to re-attach control device: " << out[1]; - return Sendmsg(fd, "fail"); - } - if (!StartHandler(*iter)) { + if (!handlers_->StartHandler(out[1])) { return Sendmsg(fd, "fail"); } return Sendmsg(fd, "success"); @@ -209,30 +196,13 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; return Sendmsg(fd, "fail"); } - { - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - // After merge is completed, we swap dm-user table with - // the underlying dm-linear base device. Hence, worker - // threads would have terminted and was removed from - // the list. - LOG(DEBUG) << "Could not find handler: " << out[1]; - return Sendmsg(fd, "success"); - } - - if (!(*iter)->ThreadTerminated()) { - (*iter)->snapuserd()->NotifyIOTerminated(); - } - } - if (!RemoveAndJoinHandler(out[1])) { + if (!handlers_->DeleteHandler(out[1])) { return Sendmsg(fd, "fail"); } return Sendmsg(fd, "success"); } case DaemonOps::DETACH: { - std::lock_guard lock(lock_); - TerminateMergeThreads(&lock); + handlers_->TerminateMergeThreads(); terminating_ = true; return true; } @@ -252,24 +222,15 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st return Sendmsg(fd, "fail"); } if (out[0] == "initiate_merge") { - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - LOG(ERROR) << "Could not find handler: " << out[1]; + if (!handlers_->InitiateMerge(out[1])) { return Sendmsg(fd, "fail"); } - - if (!StartMerge(&lock, *iter)) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); } return Sendmsg(fd, "fail"); } case DaemonOps::PERCENTAGE: { - std::lock_guard lock(lock_); - double percentage = GetMergePercentage(&lock); + double percentage = handlers_->GetMergePercentage(); return Sendmsg(fd, std::to_string(percentage)); } @@ -280,24 +241,16 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; return Sendmsg(fd, "snapshot-merge-failed"); } - { - std::lock_guard lock(lock_); - auto iter = FindHandler(&lock, out[1]); - if (iter == dm_users_.end()) { - LOG(ERROR) << "Could not find handler: " << out[1]; - return Sendmsg(fd, "snapshot-merge-failed"); - } - - std::string merge_status = GetMergeStatus(*iter); - return Sendmsg(fd, merge_status); + auto status = handlers_->GetMergeStatus(out[1]); + if (status.empty()) { + return Sendmsg(fd, "snapshot-merge-failed"); } + return Sendmsg(fd, status); } case DaemonOps::UPDATE_VERIFY: { - std::lock_guard lock(lock_); - if (!UpdateVerification(&lock)) { + if (!handlers_->GetVerificationStatus()) { return Sendmsg(fd, "fail"); } - return Sendmsg(fd, "success"); } default: { @@ -308,56 +261,6 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st } } -void UserSnapshotServer::RunThread(std::shared_ptr handler) { - LOG(INFO) << "Entering thread for handler: " << handler->misc_name(); - - if (!handler->snapuserd()->Start()) { - LOG(ERROR) << " Failed to launch all worker threads"; - } - - handler->snapuserd()->CloseFds(); - bool merge_completed = handler->snapuserd()->CheckMergeCompletionStatus(); - handler->snapuserd()->UnmapBufferRegion(); - - auto misc_name = handler->misc_name(); - LOG(INFO) << "Handler thread about to exit: " << misc_name; - - { - std::lock_guard lock(lock_); - if (merge_completed) { - num_partitions_merge_complete_ += 1; - active_merge_threads_ -= 1; - WakeupMonitorMergeThread(); - } - handler->SetThreadTerminated(); - auto iter = FindHandler(&lock, handler->misc_name()); - if (iter == dm_users_.end()) { - // RemoveAndJoinHandler() already removed us from the list, and is - // now waiting on a join(), so just return. Additionally, release - // all the resources held by snapuserd object which are shared - // by worker threads. This should be done when the last reference - // of "handler" is released; but we will explicitly release here - // to make sure snapuserd object is freed as it is the biggest - // consumer of memory in the daemon. - handler->FreeResources(); - LOG(INFO) << "Exiting handler thread to allow for join: " << misc_name; - return; - } - - LOG(INFO) << "Exiting handler thread and freeing resources: " << misc_name; - - if (handler->snapuserd()->IsAttached()) { - handler->thread().detach(); - } - - // Important: free resources within the lock. This ensures that if - // WaitForDelete() is called, the handler is either in the list, or - // it's not and its resources are guaranteed to be freed. - handler->FreeResources(); - dm_users_.erase(iter); - } -} - bool UserSnapshotServer::Start(const std::string& socketname) { bool start_listening = true; @@ -423,28 +326,10 @@ bool UserSnapshotServer::Run() { } } - JoinAllThreads(); + handlers_->JoinAllThreads(); return true; } -void UserSnapshotServer::JoinAllThreads() { - // Acquire the thread list within the lock. - std::vector> dm_users; - { - std::lock_guard guard(lock_); - dm_users = std::move(dm_users_); - } - - for (auto& client : dm_users) { - auto& th = client->thread(); - - if (th.joinable()) th.join(); - } - - stop_monitor_merge_thread_ = true; - WakeupMonitorMergeThread(); -} - void UserSnapshotServer::AddWatchedFd(android::base::borrowed_fd fd, int events) { struct pollfd p = {}; p.fd = fd.get(); @@ -506,185 +391,13 @@ std::shared_ptr UserSnapshotServer::AddHandler(const std::string& perform_verification = false; } - auto snapuserd = std::make_shared(misc_name, cow_device_path, backing_device, - base_path_merge, num_worker_threads, - io_uring_enabled_, perform_verification); - if (!snapuserd->InitCowDevice()) { - LOG(ERROR) << "Failed to initialize Snapuserd"; - return nullptr; - } - - if (!snapuserd->InitializeWorkers()) { - LOG(ERROR) << "Failed to initialize workers"; - return nullptr; - } - - auto handler = std::make_shared(snapuserd); - { - std::lock_guard lock(lock_); - if (FindHandler(&lock, misc_name) != dm_users_.end()) { - LOG(ERROR) << "Handler already exists: " << misc_name; - return nullptr; - } - dm_users_.push_back(handler); - } - return handler; -} - -bool UserSnapshotServer::StartHandler(const std::shared_ptr& handler) { - if (handler->snapuserd()->IsAttached()) { - LOG(ERROR) << "Handler already attached"; - return false; - } - - handler->snapuserd()->AttachControlDevice(); - - handler->thread() = std::thread(std::bind(&UserSnapshotServer::RunThread, this, handler)); - return true; -} - -bool UserSnapshotServer::StartMerge(std::lock_guard* proof_of_lock, - const std::shared_ptr& handler) { - CHECK(proof_of_lock); - - if (!handler->snapuserd()->IsAttached()) { - LOG(ERROR) << "Handler not attached to dm-user - Merge thread cannot be started"; - return false; - } - - handler->snapuserd()->MonitorMerge(); - - if (!is_merge_monitor_started_.has_value()) { - std::thread(&UserSnapshotServer::MonitorMerge, this).detach(); - is_merge_monitor_started_ = true; - } - - merge_handlers_.push(handler); - WakeupMonitorMergeThread(); - return true; -} - -auto UserSnapshotServer::FindHandler(std::lock_guard* proof_of_lock, - const std::string& misc_name) -> HandlerList::iterator { - CHECK(proof_of_lock); - - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - if ((*iter)->misc_name() == misc_name) { - return iter; - } - } - return dm_users_.end(); -} - -void UserSnapshotServer::TerminateMergeThreads(std::lock_guard* proof_of_lock) { - CHECK(proof_of_lock); - - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - if (!(*iter)->ThreadTerminated()) { - (*iter)->snapuserd()->NotifyIOTerminated(); - } - } -} - -std::string UserSnapshotServer::GetMergeStatus(const std::shared_ptr& handler) { - return handler->snapuserd()->GetMergeStatus(); -} - -double UserSnapshotServer::GetMergePercentage(std::lock_guard* proof_of_lock) { - CHECK(proof_of_lock); - double percentage = 0.0; - int n = 0; - - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - auto& th = (*iter)->thread(); - if (th.joinable()) { - // Merge percentage by individual partitions wherein merge is still - // in-progress - percentage += (*iter)->snapuserd()->GetMergePercentage(); - n += 1; - } - } - - // Calculate final merge including those partitions where merge was already - // completed - num_partitions_merge_complete_ will track them when each - // thread exists in RunThread. - int total_partitions = n + num_partitions_merge_complete_; - - if (total_partitions) { - percentage = ((num_partitions_merge_complete_ * 100.0) + percentage) / total_partitions; - } - - LOG(DEBUG) << "Merge %: " << percentage - << " num_partitions_merge_complete_: " << num_partitions_merge_complete_ - << " total_partitions: " << total_partitions << " n: " << n; - return percentage; -} - -bool UserSnapshotServer::RemoveAndJoinHandler(const std::string& misc_name) { - std::shared_ptr handler; - { - std::lock_guard lock(lock_); - - auto iter = FindHandler(&lock, misc_name); - if (iter == dm_users_.end()) { - // Client already deleted. - return true; - } - handler = std::move(*iter); - dm_users_.erase(iter); - } - - auto& th = handler->thread(); - if (th.joinable()) { - th.join(); - } - return true; -} - -void UserSnapshotServer::WakeupMonitorMergeThread() { - uint64_t notify = 1; - ssize_t rc = TEMP_FAILURE_RETRY(write(monitor_merge_event_fd_.get(), ¬ify, sizeof(notify))); - if (rc < 0) { - PLOG(FATAL) << "failed to notify monitor merge thread"; - } -} - -void UserSnapshotServer::MonitorMerge() { - while (!stop_monitor_merge_thread_) { - uint64_t testVal; - ssize_t ret = - TEMP_FAILURE_RETRY(read(monitor_merge_event_fd_.get(), &testVal, sizeof(testVal))); - if (ret == -1) { - PLOG(FATAL) << "Failed to read from eventfd"; - } else if (ret == 0) { - LOG(FATAL) << "Hit EOF on eventfd"; - } - - LOG(INFO) << "MonitorMerge: active-merge-threads: " << active_merge_threads_; - { - std::lock_guard lock(lock_); - while (active_merge_threads_ < kMaxMergeThreads && merge_handlers_.size() > 0) { - auto handler = merge_handlers_.front(); - merge_handlers_.pop(); - - if (!handler->snapuserd()) { - LOG(INFO) << "MonitorMerge: skipping deleted handler: " << handler->misc_name(); - continue; - } - - LOG(INFO) << "Starting merge for partition: " - << handler->snapuserd()->GetMiscName(); - handler->snapuserd()->InitiateMerge(); - active_merge_threads_ += 1; - } - } - } - - LOG(INFO) << "Exiting MonitorMerge: size: " << merge_handlers_.size(); + return handlers_->AddHandler(misc_name, cow_device_path, backing_device, base_path_merge, + num_worker_threads, io_uring_enabled_, perform_verification); } bool UserSnapshotServer::WaitForSocket() { - auto scope_guard = android::base::make_scope_guard([this]() -> void { JoinAllThreads(); }); + auto scope_guard = + android::base::make_scope_guard([this]() -> void { handlers_->JoinAllThreads(); }); auto socket_path = ANDROID_SOCKET_DIR "/"s + kSnapuserdSocketProxy; @@ -781,21 +494,8 @@ bool UserSnapshotServer::RunForSocketHandoff() { return true; } -bool UserSnapshotServer::UpdateVerification(std::lock_guard* proof_of_lock) { - CHECK(proof_of_lock); - - bool status = true; - for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { - auto& th = (*iter)->thread(); - if (th.joinable() && status) { - status = (*iter)->snapuserd()->CheckPartitionVerification() && status; - } else { - // return immediately if there is a failure - return false; - } - } - - return status; +bool UserSnapshotServer::StartHandler(const std::string& misc_name) { + return handlers_->StartHandler(misc_name); } } // namespace snapshot diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h index 12c3903c495c..ae5190391dfa 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h @@ -31,6 +31,7 @@ #include #include +#include "handler_manager.h" #include "snapuserd_core.h" namespace android { @@ -54,33 +55,6 @@ enum class DaemonOps { INVALID, }; -class HandlerThread { - public: - explicit HandlerThread(std::shared_ptr snapuserd); - - void FreeResources() { - // Each worker thread holds a reference to snapuserd. - // Clear them so that all the resources - // held by snapuserd is released - if (snapuserd_) { - snapuserd_->FreeResources(); - snapuserd_ = nullptr; - } - } - const std::shared_ptr& snapuserd() const { return snapuserd_; } - std::thread& thread() { return thread_; } - - const std::string& misc_name() const { return misc_name_; } - bool ThreadTerminated() { return thread_terminated_; } - void SetThreadTerminated() { thread_terminated_ = true; } - - private: - std::thread thread_; - std::shared_ptr snapuserd_; - std::string misc_name_; - bool thread_terminated_ = false; -}; - class UserSnapshotServer { private: android::base::unique_fd sockfd_; @@ -88,21 +62,12 @@ class UserSnapshotServer { volatile bool received_socket_signal_ = false; std::vector watched_fds_; bool is_socket_present_ = false; - int num_partitions_merge_complete_ = 0; - int active_merge_threads_ = 0; - bool stop_monitor_merge_thread_ = false; bool is_server_running_ = false; bool io_uring_enabled_ = false; - std::optional is_merge_monitor_started_; - - android::base::unique_fd monitor_merge_event_fd_; + std::unique_ptr handlers_; std::mutex lock_; - using HandlerList = std::vector>; - HandlerList dm_users_; - std::queue> merge_handlers_; - void AddWatchedFd(android::base::borrowed_fd fd, int events); void AcceptClient(); bool HandleClient(android::base::borrowed_fd fd, int revents); @@ -111,28 +76,15 @@ class UserSnapshotServer { bool Receivemsg(android::base::borrowed_fd fd, const std::string& str); void ShutdownThreads(); - bool RemoveAndJoinHandler(const std::string& control_device); DaemonOps Resolveop(std::string& input); std::string GetDaemonStatus(); void Parsemsg(std::string const& msg, const char delim, std::vector& out); bool IsTerminating() { return terminating_; } - void RunThread(std::shared_ptr handler); - void MonitorMerge(); - void JoinAllThreads(); bool StartWithSocket(bool start_listening); - // Find a HandlerThread within a lock. - HandlerList::iterator FindHandler(std::lock_guard* proof_of_lock, - const std::string& misc_name); - - double GetMergePercentage(std::lock_guard* proof_of_lock); - void TerminateMergeThreads(std::lock_guard* proof_of_lock); - - bool UpdateVerification(std::lock_guard* proof_of_lock); - public: UserSnapshotServer(); ~UserSnapshotServer(); @@ -147,12 +99,8 @@ class UserSnapshotServer { const std::string& cow_device_path, const std::string& backing_device, const std::string& base_path_merge); - bool StartHandler(const std::shared_ptr& handler); - bool StartMerge(std::lock_guard* proof_of_lock, - const std::shared_ptr& handler); - std::string GetMergeStatus(const std::shared_ptr& handler); + bool StartHandler(const std::string& misc_name); - void WakeupMonitorMergeThread(); void SetTerminating() { terminating_ = true; } void ReceivedSocketSignal() { received_socket_signal_ = true; } void SetServerRunning() { is_server_running_ = true; } From 338c3ae0712be50a66e3beb2c142921434d0d509 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 14 Mar 2023 09:09:48 -0700 Subject: [PATCH 0202/1487] snapuserd: Remove DaemonOps. These are only used for a single switch statement. Just compare the input strings instead. Bug: 269361087 Test: builds, ota applies Ignore-AOSP-First: cherry-pick from aosp (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:f84f9c319e5a05fa6bfed9730ea6b9d28407a84b) Merged-In: Ib90ae55309ea99c181585c64ed2ac814e5ed6c72 Change-Id: Ib90ae55309ea99c181585c64ed2ac814e5ed6c72 --- .../user-space-merge/snapuserd_server.cpp | 218 ++++++++---------- .../user-space-merge/snapuserd_server.h | 16 -- 2 files changed, 94 insertions(+), 140 deletions(-) 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 cc8115f5f800..d87990aca2a8 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp @@ -45,22 +45,6 @@ using namespace std::string_literals; using android::base::borrowed_fd; using android::base::unique_fd; -DaemonOps UserSnapshotServer::Resolveop(std::string& input) { - if (input == "init") return DaemonOps::INIT; - if (input == "start") return DaemonOps::START; - if (input == "stop") return DaemonOps::STOP; - if (input == "query") return DaemonOps::QUERY; - if (input == "delete") return DaemonOps::DELETE; - if (input == "detach") return DaemonOps::DETACH; - if (input == "supports") return DaemonOps::SUPPORTS; - if (input == "initiate_merge") return DaemonOps::INITIATE; - if (input == "merge_percent") return DaemonOps::PERCENTAGE; - if (input == "getstatus") return DaemonOps::GETSTATUS; - if (input == "update-verify") return DaemonOps::UPDATE_VERIFY; - - return DaemonOps::INVALID; -} - UserSnapshotServer::UserSnapshotServer() { terminating_ = false; handlers_ = std::make_unique(); @@ -132,132 +116,118 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st std::vector out; Parsemsg(str, delim, out); - DaemonOps op = Resolveop(out[0]); - - switch (op) { - case DaemonOps::INIT: { - // Message format: - // init,,,, - // - // Reads the metadata and send the number of sectors - if (out.size() != 5) { - LOG(ERROR) << "Malformed init message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - auto handler = AddHandler(out[1], out[2], out[3], out[4]); - if (!handler) { - return Sendmsg(fd, "fail"); - } - - auto retval = "success," + std::to_string(handler->snapuserd()->GetNumSectors()); - return Sendmsg(fd, retval); + const auto& cmd = out[0]; + if (cmd == "init") { + // Message format: + // init,,,, + // + // Reads the metadata and send the number of sectors + if (out.size() != 5) { + LOG(ERROR) << "Malformed init message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::START: { - // Message format: - // start, - // - // Start the new thread which binds to dm-user misc device - if (out.size() != 2) { - LOG(ERROR) << "Malformed start message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (!handlers_->StartHandler(out[1])) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); - } - case DaemonOps::STOP: { - // Message format: stop - // - // Stop all the threads gracefully and then shutdown the - // main thread - SetTerminating(); - ShutdownThreads(); - return true; + auto handler = AddHandler(out[1], out[2], out[3], out[4]); + if (!handler) { + return Sendmsg(fd, "fail"); } - case DaemonOps::QUERY: { - // Message format: query - // - // As part of transition, Second stage daemon will be - // created before terminating the first stage daemon. Hence, - // for a brief period client may have to distiguish between - // first stage daemon and second stage daemon. - // - // Second stage daemon is marked as active and hence will - // be ready to receive control message. - return Sendmsg(fd, GetDaemonStatus()); + + auto retval = "success," + std::to_string(handler->snapuserd()->GetNumSectors()); + return Sendmsg(fd, retval); + } else if (cmd == "start") { + // Message format: + // start, + // + // Start the new thread which binds to dm-user misc device + if (out.size() != 2) { + LOG(ERROR) << "Malformed start message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::DELETE: { - // Message format: - // delete, - if (out.size() != 2) { - LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (!handlers_->DeleteHandler(out[1])) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); + + if (!handlers_->StartHandler(out[1])) { + return Sendmsg(fd, "fail"); } - case DaemonOps::DETACH: { - handlers_->TerminateMergeThreads(); - terminating_ = true; - return true; + return Sendmsg(fd, "success"); + } else if (cmd == "stop") { + // Message format: stop + // + // Stop all the threads gracefully and then shutdown the + // main thread + SetTerminating(); + ShutdownThreads(); + return true; + } else if (cmd == "query") { + // Message format: query + // + // As part of transition, Second stage daemon will be + // created before terminating the first stage daemon. Hence, + // for a brief period client may have to distiguish between + // first stage daemon and second stage daemon. + // + // Second stage daemon is marked as active and hence will + // be ready to receive control message. + return Sendmsg(fd, GetDaemonStatus()); + } else if (cmd == "delete") { + // Message format: + // delete, + if (out.size() != 2) { + LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::SUPPORTS: { - if (out.size() != 2) { - LOG(ERROR) << "Malformed supports message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (out[1] == "second_stage_socket_handoff") { - return Sendmsg(fd, "success"); - } + if (!handlers_->DeleteHandler(out[1])) { return Sendmsg(fd, "fail"); } - case DaemonOps::INITIATE: { - if (out.size() != 2) { - LOG(ERROR) << "Malformed initiate-merge message, " << out.size() << " parts"; - return Sendmsg(fd, "fail"); - } - if (out[0] == "initiate_merge") { - if (!handlers_->InitiateMerge(out[1])) { - return Sendmsg(fd, "fail"); - } - return Sendmsg(fd, "success"); - } + return Sendmsg(fd, "success"); + } else if (cmd == "detach") { + handlers_->TerminateMergeThreads(); + terminating_ = true; + return true; + } else if (cmd == "supports") { + if (out.size() != 2) { + LOG(ERROR) << "Malformed supports message, " << out.size() << " parts"; return Sendmsg(fd, "fail"); } - case DaemonOps::PERCENTAGE: { - double percentage = handlers_->GetMergePercentage(); - - return Sendmsg(fd, std::to_string(percentage)); + if (out[1] == "second_stage_socket_handoff") { + return Sendmsg(fd, "success"); } - case DaemonOps::GETSTATUS: { - // Message format: - // getstatus, - if (out.size() != 2) { - LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; - return Sendmsg(fd, "snapshot-merge-failed"); - } - auto status = handlers_->GetMergeStatus(out[1]); - if (status.empty()) { - return Sendmsg(fd, "snapshot-merge-failed"); - } - return Sendmsg(fd, status); + return Sendmsg(fd, "fail"); + } else if (cmd == "initiate_merge") { + if (out.size() != 2) { + LOG(ERROR) << "Malformed initiate-merge message, " << out.size() << " parts"; + return Sendmsg(fd, "fail"); } - case DaemonOps::UPDATE_VERIFY: { - if (!handlers_->GetVerificationStatus()) { + if (out[0] == "initiate_merge") { + if (!handlers_->InitiateMerge(out[1])) { return Sendmsg(fd, "fail"); } return Sendmsg(fd, "success"); } - default: { - LOG(ERROR) << "Received unknown message type from client"; - Sendmsg(fd, "fail"); - return false; + return Sendmsg(fd, "fail"); + } else if (cmd == "merge_percent") { + double percentage = handlers_->GetMergePercentage(); + return Sendmsg(fd, std::to_string(percentage)); + } else if (cmd == "getstatus") { + // Message format: + // getstatus, + if (out.size() != 2) { + LOG(ERROR) << "Malformed delete message, " << out.size() << " parts"; + return Sendmsg(fd, "snapshot-merge-failed"); + } + auto status = handlers_->GetMergeStatus(out[1]); + if (status.empty()) { + return Sendmsg(fd, "snapshot-merge-failed"); } + return Sendmsg(fd, status); + } else if (cmd == "update-verify") { + if (!handlers_->GetVerificationStatus()) { + return Sendmsg(fd, "fail"); + } + return Sendmsg(fd, "success"); + } else { + LOG(ERROR) << "Received unknown message type from client"; + Sendmsg(fd, "fail"); + return false; } } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h index ae5190391dfa..988c01a99ba3 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h @@ -40,21 +40,6 @@ namespace snapshot { static constexpr uint32_t kMaxPacketSize = 512; static constexpr uint8_t kMaxMergeThreads = 2; -enum class DaemonOps { - INIT, - START, - QUERY, - STOP, - DELETE, - DETACH, - SUPPORTS, - INITIATE, - PERCENTAGE, - GETSTATUS, - UPDATE_VERIFY, - INVALID, -}; - class UserSnapshotServer { private: android::base::unique_fd sockfd_; @@ -76,7 +61,6 @@ class UserSnapshotServer { bool Receivemsg(android::base::borrowed_fd fd, const std::string& str); void ShutdownThreads(); - DaemonOps Resolveop(std::string& input); std::string GetDaemonStatus(); void Parsemsg(std::string const& msg, const char delim, std::vector& out); From 329fef34a546f0ea2da869c75e3eb750a1aed486 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 14 Mar 2023 10:57:47 -0700 Subject: [PATCH 0203/1487] snapuserd: Run snapuserd threads in-process. This removes the temporary daemon and socket and instead directly embeds SnapshotHandlerManager. We can also remove the test flags for io_uring as with this they're no longer necessary. Bug: 269361087 Test: snapuserd_test Ignore-AOSP-First: cherry-pick from aosp (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:269e99f9558ae332e10329451fc51dc6698375a0) Merged-In: I728186d9bc90c98fabd76d3f86569840488ada96 Change-Id: I728186d9bc90c98fabd76d3f86569840488ada96 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 15 ++-- .../user-space-merge/handler_manager.cpp | 3 + .../user-space-merge/snapuserd_core.cpp | 5 -- .../user-space-merge/snapuserd_server.cpp | 3 - .../user-space-merge/snapuserd_test.cpp | 75 ++++++------------- 5 files changed, 33 insertions(+), 68 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 65f3d6d297ed..9fe567acbc7e 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -165,7 +165,7 @@ cc_binary { } cc_test { - name: "cow_snapuserd_test", + name: "snapuserd_test_legacy", defaults: [ "fs_mgr_defaults", "libsnapshot_cow_defaults", @@ -217,16 +217,17 @@ cc_test { ], static_libs: [ "libbrotli", - "libgtest", - "libsnapshot_cow", - "libsnapshot_snapuserd", "libcutils_sockets", - "libz", - "libfs_mgr", "libdm", "libext4_utils", - "liburing", + "libfs_mgr", "libgflags", + "libgtest", + "libsnapshot_cow", + "libsnapshot_snapuserd", + "libsnapuserd", + "liburing", + "libz", ], include_dirs: ["bionic/libc/kernel"], header_libs: [ 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 c5150c411d02..bdba5c0cc3ab 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 @@ namespace snapshot { static constexpr uint8_t kMaxMergeThreads = 2; +HandlerThread::HandlerThread(std::shared_ptr 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 c8a5cc584a28..8e1212b7b3ce 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -421,11 +421,6 @@ bool SnapshotHandler::IsIouringSupported() { 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 d87990aca2a8..c953f1a053bd 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 @@ void UserSnapshotServer::ShutdownThreads() { handlers_->JoinAllThreads(); } -HandlerThread::HandlerThread(std::shared_ptr 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 ef3689f61f6b..efe0c1443215 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 #include #include -#include #include +#include "handler_manager.h" #include "snapuserd_core.h" DEFINE_string(force_config, "", "Force testing mode with iouring disabled"); @@ -54,8 +54,6 @@ using namespace std::chrono_literals; 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 @@ class Tempdevice { } ~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_; } @@ -139,7 +137,6 @@ class SnapuserdTest : public ::testing::Test { void SetDeviceControlName(); void InitDaemon(); void CreateDmUserDevice(); - void StartSnapuserdDaemon(); unique_ptr base_loop_; unique_ptr dmuser_dev_; @@ -149,9 +146,9 @@ class SnapuserdTest : public ::testing::Test { unique_fd base_fd_; std::unique_ptr cow_system_; - std::unique_ptr client_; std::unique_ptr orig_buffer_; std::unique_ptr merged_buffer_; + SnapshotHandlerManager handlers_; bool setup_ok_ = false; bool merge_ok_ = false; size_t size_ = 100_MiB; @@ -181,9 +178,9 @@ void SnapuserdTest::Shutdown() { 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() { @@ -218,8 +215,6 @@ bool SnapuserdTest::SetupCopyOverlap_2() { bool SnapuserdTest::SetupDaemon() { SetDeviceControlName(); - StartSnapuserdDaemon(); - CreateDmUserDevice(); InitCowDevice(); InitDaemon(); @@ -229,20 +224,6 @@ bool SnapuserdTest::SetupDaemon() { 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; @@ -591,9 +572,17 @@ void SnapuserdTest::CreateCowDevice() { } 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() { @@ -631,13 +620,12 @@ void SnapuserdTest::CreateDmUserDevice() { } 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; } @@ -652,8 +640,6 @@ void SnapuserdTest::SetupImpl() { SetDeviceControlName(); - StartSnapuserdDaemon(); - CreateDmUserDevice(); InitCowDevice(); InitDaemon(); @@ -669,8 +655,7 @@ bool SnapuserdTest::Merge() { } 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() { @@ -684,7 +669,6 @@ void SnapuserdTest::SimulateDaemonRestart() { Shutdown(); std::this_thread::sleep_for(500ms); SetDeviceControlName(); - StartSnapuserdDaemon(); CreateDmUserDevice(); InitCowDevice(); InitDaemon(); @@ -844,20 +828,5 @@ int main(int argc, char** argv) { 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(); } From 07339000d4e9d12c2f29d062c0e71395cde4ea1a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 14 Jul 2023 12:30:35 -0700 Subject: [PATCH 0204/1487] Remove local_include_dirs from fs_mgr_defaults. fs_mgr_defaults gets used in lots of places, propagate local_include_dirs to where it's needed so it doesn't cause problems on modules that don't have an "includes" directory. Bug: 291083311 Test: builds Change-Id: Ief2f6362f584b99d3e2dc7dc1b46450609ad189d --- fs_mgr/Android.bp | 3 ++- fs_mgr/libsnapshot/snapuserd/Android.bp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp index 15600fd403eb..0a836e43295f 100644 --- a/fs_mgr/Android.bp +++ b/fs_mgr/Android.bp @@ -49,7 +49,6 @@ cc_defaults { sanitize: { misc_undefined: ["integer"], }, - local_include_dirs: ["include/"], cflags: [ "-Wall", "-Werror", @@ -60,6 +59,7 @@ cc_defaults { name: "libfs_mgr_defaults", defaults: ["fs_mgr_defaults"], export_include_dirs: ["include"], + local_include_dirs: ["include/"], include_dirs: ["system/vold"], cflags: [ "-D_FILE_OFFSET_BITS=64", @@ -188,6 +188,7 @@ cc_library_static { ], host_supported: true, defaults: ["fs_mgr_defaults"], + local_include_dirs: ["include/"], srcs: [ "fs_mgr_fstab.cpp", "fs_mgr_boot_config.cpp", diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 9fe567acbc7e..e5b561b682b3 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -57,6 +57,7 @@ cc_library_static { defaults: [ "fs_mgr_defaults", ], + local_include_dirs: ["include/"], srcs: [ "dm-snapshot-merge/snapuserd.cpp", "dm-snapshot-merge/snapuserd_worker.cpp", From 74c55e94c9a0dc794747294bd06ea9034072f1f9 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Fri, 14 Jul 2023 21:44:57 -0700 Subject: [PATCH 0205/1487] libsnapshot: GetReminingTime not required after mapping dm-user After MapDmUserCow, there is no further calls in this function. Snapshot is mapped; Hence, checking remaining time is not required as it may return false if the time was exceeded. This would mean function returning false even though snapshots were successfully mapped. Bug: 291288998 Test: OTA Change-Id: I4fd8fa6ef90a48885392297f217361507268ba51 Signed-off-by: Akilesh Kailash --- fs_mgr/libsnapshot/snapshot.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index fbea79b4ad9b..09d35cff104d 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -2490,9 +2490,6 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock, } created_devices.EmplaceBack(&dm_, name); - remaining_time = GetRemainingTime(params.timeout_ms, begin); - if (remaining_time.count() < 0) return false; - cow_device = new_cow_device; } @@ -2507,6 +2504,9 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock, // the user-space will not start the merge. We have to explicitly inform the // daemon to resume the merge. Check ProcessUpdateState() call stack. if (!UpdateUsesUserSnapshots(lock)) { + remaining_time = GetRemainingTime(params.timeout_ms, begin); + if (remaining_time.count() < 0) return false; + std::string path; if (!MapSnapshot(lock, params.GetPartitionName(), base_device, cow_device, remaining_time, &path)) { From 53ed745e3ffda084d96d11766bb44bc5bef264d8 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 17 Jul 2023 20:45:44 +0000 Subject: [PATCH 0206/1487] init: avoid ERROR log due to missing SEPolicy.zip One of the first ERROR messages in logcat of a normal boot of Cuttlefish is from failure to open SEPolicy.zip. This condition is expected. Therefore don't try to load SEPolicy.zip when it doesn't exist. This replaces the following log messages: 0 0 I init : Error: Apex SEPolicy failed signature check 0 0 I init : Loading APEX Sepolicy from /system/etc/selinux/apex/SEPolicy.zip 0 0 E init : Failed to open package /system/etc/selinux/apex/SEPolicy.zip: No such file or directory ... with just: 0 0 I init : No APEX Sepolicy found Change-Id: If3a77407c35130165df5782b9ef91912e8374dbf --- init/selinux.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/init/selinux.cpp b/init/selinux.cpp index b6d483a47d6d..51093d898e8b 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -667,10 +667,16 @@ void CleanupApexSepolicy() { // void PrepareApexSepolicy() { // If apex sepolicy zip exists in /metadata/sepolicy, use that, otherwise use version on - // /system. - auto dir = (access((kSepolicyApexMetadataDir + kSepolicyZip).c_str(), F_OK) == 0) - ? kSepolicyApexMetadataDir - : kSepolicyApexSystemDir; + // /system. If neither exists, do nothing. + std::string dir; + if (access((kSepolicyApexMetadataDir + kSepolicyZip).c_str(), F_OK) == 0) { + dir = kSepolicyApexMetadataDir; + } else if (access((kSepolicyApexSystemDir + kSepolicyZip).c_str(), F_OK) == 0) { + dir = kSepolicyApexSystemDir; + } else { + LOG(INFO) << "APEX Sepolicy not found"; + return; + } auto sepolicyVerify = SepolicyVerify(dir); if (!sepolicyVerify.ok()) { From 556c46bfb9f79955b6f66c55c2581cfd38d2c7ee Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Mon, 17 Jul 2023 13:41:38 -0700 Subject: [PATCH 0207/1487] Look for radio.img and bootloader.img in ANDROID_PRODUCT_OUT Test: fastboot flash bootloader and fastboot flash radio both work Change-Id: I79674469c0df3dd592e5fcf840fef0dcc3f11d33 --- fastboot/fastboot.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 30eb7b5fcd5b..1ce4e8b2b5c6 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -119,6 +119,9 @@ fastboot::FastBootDriver* fb = nullptr; static std::vector images = { // clang-format off { "boot", "boot.img", "boot.sig", "boot", false, ImageType::BootCritical }, + { "bootloader", + "bootloader.img", "", "bootloader", + true, ImageType::Extra }, { "init_boot", "init_boot.img", "init_boot.sig", "init_boot", @@ -131,6 +134,7 @@ static std::vector images = { { "odm_dlkm", "odm_dlkm.img", "odm_dlkm.sig", "odm_dlkm", true, ImageType::Normal }, { "product", "product.img", "product.sig", "product", true, ImageType::Normal }, { "pvmfw", "pvmfw.img", "pvmfw.sig", "pvmfw", true, ImageType::BootCritical }, + { "radio", "radio.img", "", "radio", true, ImageType::Extra }, { "recovery", "recovery.img", "recovery.sig", "recovery", true, ImageType::BootCritical }, { "super", "super.img", "super.sig", "super", true, ImageType::Extra }, { "system", "system.img", "system.sig", "system", false, ImageType::Normal }, From 3930625074323af9bade13775bd28c3a0ccfcc7c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 21 Jun 2023 12:13:15 -0700 Subject: [PATCH 0208/1487] snapuserd: Refactor how buffers are managed. Currently all I/O is processed through BufferSink. However, the allocation of buffers is implicit in low-level helper functions, which have no knowledge of how much data will actually be sent. As a result, "allocation of buffers" and "tracking of how many bytes were written" is disjoint. This will make it very difficult to break dependence on dm-user, without a much more complex API. This patch refactors how BufferSink is used. First, GetPayloadBuffer has been deprecated in favor of AcquireBuffer. AcquireBuffer performs both allocation and write tracking. The number of bytes written is not necessarily the number of bytes allocated, and the new API allows for this. The "Process" helpers now take in an explicit buffer, and their callers are responsible for allocating a buffer. This allows for ReadUnalignedSector to have proper buffer offset tracking. Because write tracking is now accurate, no explicit size needs to be passed to WriteDmUserPayload. It can simply read the current watermark in BufferSink. This patch also removes XorSink, since its dependence on BufferSink made this change more difficult. Bug: 288273605 Test: snapuserd_test Change-Id: Id9ca5044f9c0386f351b250349793b6b276b01b7 --- .../include/snapuserd/snapuserd_buffer.h | 29 +-- .../snapuserd/snapuserd_buffer.cpp | 51 ++--- .../user-space-merge/read_worker.cpp | 178 +++++++----------- .../snapuserd/user-space-merge/read_worker.h | 19 +- .../user-space-merge/snapuserd_merge.cpp | 6 +- .../user-space-merge/snapuserd_readahead.cpp | 3 +- 6 files changed, 117 insertions(+), 169 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h index a6b6a7f2d9e8..c5ca2b120184 100644 --- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h +++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h @@ -36,6 +36,21 @@ class BufferSink final { struct dm_user_header* GetHeaderPtr(); void ResetBufferOffset() { buffer_offset_ = 0; } void* GetPayloadBufPtr(); + loff_t GetPayloadBytesWritten() { return buffer_offset_; } + + // Same as calling GetPayloadBuffer and then UpdateBufferOffset. + // + // This is preferred over GetPayloadBuffer as it does not require a + // separate call to UpdateBufferOffset. + void* AcquireBuffer(size_t size) { return AcquireBuffer(size, size); } + + // Same as AcquireBuffer, but separates the requested size from the buffer + // offset. This is useful for a situation where a full run of data will be + // read, but only a partial amount will be returned. + // + // If size != to_write, the excess bytes may be reallocated by the next + // call to AcquireBuffer. + void* AcquireBuffer(size_t size, size_t to_write); private: std::unique_ptr buffer_; @@ -43,19 +58,5 @@ class BufferSink final { size_t buffer_size_; }; -class XorSink final { - public: - void Initialize(BufferSink* sink, size_t size); - void Reset(); - void* GetBuffer(size_t requested, size_t* actual); - bool ReturnData(void* buffer, size_t len); - - private: - BufferSink* bufsink_; - std::unique_ptr buffer_; - size_t buffer_size_; - size_t returned_; -}; - } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp index ab763ab7e4bc..35065e61ef86 100644 --- a/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp +++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp @@ -15,6 +15,8 @@ */ #include + +#include #include namespace android { @@ -26,11 +28,23 @@ void BufferSink::Initialize(size_t size) { buffer_ = std::make_unique(size); } -void* BufferSink::GetPayloadBuffer(size_t size) { - if ((buffer_size_ - buffer_offset_) < size) return nullptr; +void* BufferSink::AcquireBuffer(size_t size, size_t to_write) { + CHECK(to_write <= size); + + void* ptr = GetPayloadBuffer(size); + if (!ptr) { + return nullptr; + } + UpdateBufferOffset(to_write); + return ptr; +} +void* BufferSink::GetPayloadBuffer(size_t size) { char* buffer = reinterpret_cast(GetBufPtr()); struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0])); + if ((buffer_size_ - buffer_offset_ - sizeof(msg->header)) < size) { + return nullptr; + } return (char*)msg->payload.buf + buffer_offset_; } @@ -59,38 +73,5 @@ void* BufferSink::GetPayloadBufPtr() { return msg->payload.buf; } -void XorSink::Initialize(BufferSink* sink, size_t size) { - bufsink_ = sink; - buffer_size_ = size; - returned_ = 0; - buffer_ = std::make_unique(size); -} - -void XorSink::Reset() { - returned_ = 0; -} - -void* XorSink::GetBuffer(size_t requested, size_t* actual) { - if (requested > buffer_size_) { - *actual = buffer_size_; - } else { - *actual = requested; - } - return buffer_.get(); -} - -bool XorSink::ReturnData(void* buffer, size_t len) { - uint8_t* xor_data = reinterpret_cast(buffer); - uint8_t* buff = reinterpret_cast(bufsink_->GetPayloadBuffer(len + returned_)); - if (buff == nullptr) { - return false; - } - for (size_t i = 0; i < len; i++) { - buff[returned_ + i] ^= xor_data[i]; - } - returned_ += len; - return true; -} - } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp index dd2996b783a0..7268fca1e1cc 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp @@ -42,12 +42,7 @@ ReadWorker::ReadWorker(const std::string& cow_device, const std::string& backing // Start the replace operation. This will read the // internal COW format and if the block is compressed, // it will be de-compressed. -bool ReadWorker::ProcessReplaceOp(const CowOperation* cow_op) { - void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ); - if (!buffer) { - SNAP_LOG(ERROR) << "ProcessReplaceOp failed to allocate buffer"; - return false; - } +bool ReadWorker::ProcessReplaceOp(const CowOperation* cow_op, void* buffer) { if (!reader_->ReadData(cow_op, buffer, BLOCK_SZ)) { SNAP_LOG(ERROR) << "ProcessReplaceOp failed for block " << cow_op->new_block; return false; @@ -55,12 +50,7 @@ bool ReadWorker::ProcessReplaceOp(const CowOperation* cow_op) { return true; } -bool ReadWorker::ReadFromSourceDevice(const CowOperation* cow_op) { - void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ); - if (buffer == nullptr) { - SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get payload buffer"; - return false; - } +bool ReadWorker::ReadFromSourceDevice(const CowOperation* cow_op, void* buffer) { uint64_t offset; if (!reader_->GetSourceOffset(cow_op, &offset)) { SNAP_LOG(ERROR) << "ReadFromSourceDevice: Failed to get source offset"; @@ -85,60 +75,43 @@ bool ReadWorker::ReadFromSourceDevice(const CowOperation* cow_op) { // Start the copy operation. This will read the backing // block device which is represented by cow_op->source. -bool ReadWorker::ProcessCopyOp(const CowOperation* cow_op) { - if (!ReadFromSourceDevice(cow_op)) { +bool ReadWorker::ProcessCopyOp(const CowOperation* cow_op, void* buffer) { + if (!ReadFromSourceDevice(cow_op, buffer)) { return false; } - return true; } -bool ReadWorker::ProcessXorOp(const CowOperation* cow_op) { - if (!ReadFromSourceDevice(cow_op)) { +bool ReadWorker::ProcessXorOp(const CowOperation* cow_op, void* buffer) { + if (!ReadFromSourceDevice(cow_op, buffer)) { return false; } - xorsink_.Reset(); - - size_t actual = 0; - void* buffer = xorsink_.GetBuffer(BLOCK_SZ, &actual); - if (!buffer || actual < BLOCK_SZ) { - SNAP_LOG(ERROR) << "ProcessXorOp failed to get buffer of " << BLOCK_SZ << " size, got " - << actual; - return false; + if (xor_buffer_.empty()) { + xor_buffer_.resize(BLOCK_SZ); } - ssize_t size = reader_->ReadData(cow_op, buffer, BLOCK_SZ); + CHECK(xor_buffer_.size() == BLOCK_SZ); + + ssize_t size = reader_->ReadData(cow_op, xor_buffer_.data(), xor_buffer_.size()); if (size != BLOCK_SZ) { SNAP_LOG(ERROR) << "ProcessXorOp failed for block " << cow_op->new_block << ", return value: " << size; return false; } - if (!xorsink_.ReturnData(buffer, size)) { - SNAP_LOG(ERROR) << "ProcessXorOp failed to return data"; - return false; + + auto xor_out = reinterpret_cast(buffer); + for (size_t i = 0; i < BLOCK_SZ; i++) { + xor_out[i] ^= xor_buffer_[i]; } return true; } -bool ReadWorker::ProcessZeroOp() { - // Zero out the entire block - void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ); - if (buffer == nullptr) { - SNAP_LOG(ERROR) << "ProcessZeroOp: Failed to get payload buffer"; - return false; - } - +bool ReadWorker::ProcessZeroOp(void* buffer) { memset(buffer, 0, BLOCK_SZ); return true; } -bool ReadWorker::ProcessOrderedOp(const CowOperation* cow_op) { - void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ); - if (buffer == nullptr) { - SNAP_LOG(ERROR) << "ProcessOrderedOp: Failed to get payload buffer"; - return false; - } - +bool ReadWorker::ProcessOrderedOp(const CowOperation* cow_op, void* buffer) { MERGE_GROUP_STATE state = snapuserd_->ProcessMergingBlock(cow_op->new_block, buffer); switch (state) { @@ -148,7 +121,7 @@ bool ReadWorker::ProcessOrderedOp(const CowOperation* cow_op) { SNAP_LOG(DEBUG) << "Merge-completed: Reading from base device sector: " << (cow_op->new_block >> SECTOR_SHIFT) << " Block-number: " << cow_op->new_block; - if (!ReadDataFromBaseDevice(ChunkToSector(cow_op->new_block), BLOCK_SZ)) { + if (!ReadDataFromBaseDevice(ChunkToSector(cow_op->new_block), buffer, BLOCK_SZ)) { SNAP_LOG(ERROR) << "ReadDataFromBaseDevice at sector: " << (cow_op->new_block >> SECTOR_SHIFT) << " after merge-complete."; return false; @@ -158,9 +131,9 @@ bool ReadWorker::ProcessOrderedOp(const CowOperation* cow_op) { case MERGE_GROUP_STATE::GROUP_MERGE_PENDING: { bool ret; if (cow_op->type == kCowCopyOp) { - ret = ProcessCopyOp(cow_op); + ret = ProcessCopyOp(cow_op, buffer); } else { - ret = ProcessXorOp(cow_op); + ret = ProcessXorOp(cow_op, buffer); } // I/O is complete - decrement the refcount irrespective of the return @@ -185,7 +158,7 @@ bool ReadWorker::ProcessOrderedOp(const CowOperation* cow_op) { return false; } -bool ReadWorker::ProcessCowOp(const CowOperation* cow_op) { +bool ReadWorker::ProcessCowOp(const CowOperation* cow_op, void* buffer) { if (cow_op == nullptr) { SNAP_LOG(ERROR) << "ProcessCowOp: Invalid cow_op"; return false; @@ -193,17 +166,17 @@ bool ReadWorker::ProcessCowOp(const CowOperation* cow_op) { switch (cow_op->type) { case kCowReplaceOp: { - return ProcessReplaceOp(cow_op); + return ProcessReplaceOp(cow_op, buffer); } case kCowZeroOp: { - return ProcessZeroOp(); + return ProcessZeroOp(buffer); } case kCowCopyOp: [[fallthrough]]; case kCowXorOp: { - return ProcessOrderedOp(cow_op); + return ProcessOrderedOp(cow_op, buffer); } default: { @@ -229,8 +202,6 @@ bool ReadWorker::Init() { SNAP_PLOG(ERROR) << "Unable to open " << control_device_; return false; } - - xorsink_.Initialize(&bufsink_, BLOCK_SZ); return true; } @@ -271,18 +242,15 @@ bool ReadWorker::WriteDmUserPayload(size_t size) { // After the first header is sent in response to a request, we cannot // send any additional headers. header_response_ = false; + + // Reset the buffer for use by the next request. + bufsink_.ResetBufferOffset(); return true; } -bool ReadWorker::ReadDataFromBaseDevice(sector_t sector, size_t read_size) { +bool ReadWorker::ReadDataFromBaseDevice(sector_t sector, void* buffer, size_t read_size) { CHECK(read_size <= BLOCK_SZ); - void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ); - if (buffer == nullptr) { - SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get payload buffer"; - return false; - } - loff_t offset = sector << SECTOR_SHIFT; if (!android::base::ReadFullyAtOffset(base_path_merge_fd_, buffer, read_size, offset)) { SNAP_PLOG(ERROR) << "ReadDataFromBaseDevice failed. fd: " << base_path_merge_fd_ @@ -303,7 +271,6 @@ bool ReadWorker::ReadAlignedSector(sector_t sector, size_t sz) { size_t read_size = std::min(PAYLOAD_BUFFER_SZ, remaining_size); size_t total_bytes_read = 0; - bufsink_.ResetBufferOffset(); while (read_size) { // We need to check every 4k block to verify if it is @@ -314,11 +281,17 @@ bool ReadWorker::ReadAlignedSector(sector_t sector, size_t sz) { std::make_pair(sector, nullptr), SnapshotHandler::compare); bool not_found = (it == chunk_vec.end() || it->first != sector); + void* buffer = bufsink_.AcquireBuffer(BLOCK_SZ, size); + if (!buffer) { + SNAP_LOG(ERROR) << "AcquireBuffer failed in ReadAlignedSector"; + return false; + } + if (not_found) { // Block not found in map - which means this block was not // changed as per the OTA. Just route the I/O to the base // device. - if (!ReadDataFromBaseDevice(sector, size)) { + if (!ReadDataFromBaseDevice(sector, buffer, size)) { SNAP_LOG(ERROR) << "ReadDataFromBaseDevice failed"; return false; } @@ -327,7 +300,7 @@ bool ReadWorker::ReadAlignedSector(sector_t sector, size_t sz) { } else { // We found the sector in mapping. Check the type of COW OP and // process it. - if (!ProcessCowOp(it->second)) { + if (!ProcessCowOp(it->second, buffer)) { SNAP_LOG(ERROR) << "ProcessCowOp failed"; return false; } @@ -338,14 +311,13 @@ bool ReadWorker::ReadAlignedSector(sector_t sector, size_t sz) { read_size -= ret; total_bytes_read += ret; sector += (ret >> SECTOR_SHIFT); - bufsink_.UpdateBufferOffset(ret); } - if (!WriteDmUserPayload(total_bytes_read)) { + if (!SendBufferedIo()) { return false; } - SNAP_LOG(DEBUG) << "WriteDmUserPayload success total_bytes_read: " << total_bytes_read + SNAP_LOG(DEBUG) << "SendBufferedIo success total_bytes_read: " << total_bytes_read << " remaining_size: " << remaining_size; remaining_size -= total_bytes_read; } while (remaining_size > 0); @@ -356,40 +328,36 @@ bool ReadWorker::ReadAlignedSector(sector_t sector, size_t sz) { int ReadWorker::ReadUnalignedSector( sector_t sector, size_t size, std::vector>::iterator& it) { - size_t skip_sector_size = 0; - SNAP_LOG(DEBUG) << "ReadUnalignedSector: sector " << sector << " size: " << size << " Aligned sector: " << it->first; - if (!ProcessCowOp(it->second)) { + int num_sectors_skip = sector - it->first; + size_t skip_size = num_sectors_skip << SECTOR_SHIFT; + size_t write_size = std::min(size, BLOCK_SZ - skip_size); + auto buffer = reinterpret_cast(bufsink_.AcquireBuffer(BLOCK_SZ, write_size)); + if (!buffer) { + SNAP_LOG(ERROR) << "ProcessCowOp failed to allocate buffer"; + return -1; + } + + if (!ProcessCowOp(it->second, buffer)) { SNAP_LOG(ERROR) << "ReadUnalignedSector: " << sector << " failed of size: " << size << " Aligned sector: " << it->first; return -1; } - int num_sectors_skip = sector - it->first; - - if (num_sectors_skip > 0) { - skip_sector_size = num_sectors_skip << SECTOR_SHIFT; - char* buffer = reinterpret_cast(bufsink_.GetBufPtr()); - struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0])); - - if (skip_sector_size == BLOCK_SZ) { + if (skip_size) { + if (skip_size == BLOCK_SZ) { SNAP_LOG(ERROR) << "Invalid un-aligned IO request at sector: " << sector << " Base-sector: " << it->first; return -1; } - - memmove(msg->payload.buf, (char*)msg->payload.buf + skip_sector_size, - (BLOCK_SZ - skip_sector_size)); + memmove(buffer, buffer + skip_size, write_size); } - - bufsink_.ResetBufferOffset(); - return std::min(size, (BLOCK_SZ - skip_sector_size)); + return write_size; } bool ReadWorker::ReadUnalignedSector(sector_t sector, size_t size) { - bufsink_.ResetBufferOffset(); std::vector>& chunk_vec = snapuserd_->GetChunkVec(); auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(), std::make_pair(sector, nullptr), @@ -458,7 +426,6 @@ bool ReadWorker::ReadUnalignedSector(sector_t sector, size_t size) { // requested offset in this case is beyond the last mapped COW op size (which // is block 1 in this case). - size_t total_bytes_read = 0; size_t remaining_size = size; int ret = 0; if (!merge_complete && (requested_offset >= final_offset) && @@ -472,11 +439,10 @@ bool ReadWorker::ReadUnalignedSector(sector_t sector, size_t size) { } remaining_size -= ret; - total_bytes_read += ret; sector += (ret >> SECTOR_SHIFT); // Send the data back - if (!WriteDmUserPayload(total_bytes_read)) { + if (!SendBufferedIo()) { return false; } @@ -494,26 +460,21 @@ bool ReadWorker::ReadUnalignedSector(sector_t sector, size_t size) { // Find the diff of the aligned offset size_t diff_size = aligned_offset - requested_offset; CHECK(diff_size <= BLOCK_SZ); - if (remaining_size < diff_size) { - if (!ReadDataFromBaseDevice(sector, remaining_size)) { - return false; - } - total_bytes_read += remaining_size; - - if (!WriteDmUserPayload(total_bytes_read)) { - return false; - } - } else { - if (!ReadDataFromBaseDevice(sector, diff_size)) { - return false; - } - total_bytes_read += diff_size; - - if (!WriteDmUserPayload(total_bytes_read)) { - return false; - } + size_t read_size = std::min(remaining_size, diff_size); + void* buffer = bufsink_.AcquireBuffer(BLOCK_SZ, read_size); + if (!buffer) { + SNAP_LOG(ERROR) << "AcquireBuffer failed in ReadUnalignedSector"; + return false; + } + if (!ReadDataFromBaseDevice(sector, buffer, read_size)) { + return false; + } + if (!SendBufferedIo()) { + return false; + } + if (remaining_size >= diff_size) { remaining_size -= diff_size; size_t num_sectors_read = (diff_size >> SECTOR_SHIFT); sector += num_sectors_read; @@ -555,6 +516,10 @@ bool ReadWorker::DmuserReadRequest() { return ReadAlignedSector(header->sector, header->len); } +bool ReadWorker::SendBufferedIo() { + return WriteDmUserPayload(bufsink_.GetPayloadBytesWritten()); +} + bool ReadWorker::ProcessIORequest() { // Read Header from dm-user misc device. This gives // us the sector number for which IO is issued by dm-snapshot device @@ -579,6 +544,9 @@ bool ReadWorker::ProcessIORequest() { header->type = DM_USER_RESP_SUCCESS; header_response_ = true; + // Reset the output buffer. + bufsink_.ResetBufferOffset(); + bool ok; switch (request_type) { case DM_USER_REQ_MAP_READ: diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h index c3a4c346ebfd..8d6f66379359 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h @@ -37,21 +37,22 @@ class ReadWorker : public Worker { bool ProcessIORequest(); bool WriteDmUserPayload(size_t size); bool DmuserReadRequest(); + bool SendBufferedIo(); void RespondIOError(); - bool ProcessCowOp(const CowOperation* cow_op); - bool ProcessXorOp(const CowOperation* cow_op); - bool ProcessOrderedOp(const CowOperation* cow_op); - bool ProcessCopyOp(const CowOperation* cow_op); - bool ProcessReplaceOp(const CowOperation* cow_op); - bool ProcessZeroOp(); + bool ProcessCowOp(const CowOperation* cow_op, void* buffer); + bool ProcessXorOp(const CowOperation* cow_op, void* buffer); + bool ProcessOrderedOp(const CowOperation* cow_op, void* buffer); + bool ProcessCopyOp(const CowOperation* cow_op, void* buffer); + bool ProcessReplaceOp(const CowOperation* cow_op, void* buffer); + bool ProcessZeroOp(void* buffer); bool ReadAlignedSector(sector_t sector, size_t sz); bool ReadUnalignedSector(sector_t sector, size_t size); int ReadUnalignedSector(sector_t sector, size_t size, std::vector>::iterator& it); - bool ReadFromSourceDevice(const CowOperation* cow_op); - bool ReadDataFromBaseDevice(sector_t sector, size_t read_size); + bool ReadFromSourceDevice(const CowOperation* cow_op, void* buffer); + bool ReadDataFromBaseDevice(sector_t sector, void* buffer, size_t read_size); constexpr bool IsBlockAligned(size_t size) { return ((size & (BLOCK_SZ - 1)) == 0); } constexpr sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; } @@ -62,8 +63,8 @@ class ReadWorker : public Worker { std::string control_device_; unique_fd ctrl_fd_; - XorSink xorsink_; bool header_response_ = false; + std::basic_string xor_buffer_; }; } // namespace snapshot diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp index 563f6ad427cc..517148d36730 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp @@ -106,9 +106,9 @@ bool MergeWorker::MergeReplaceZeroOps() { for (size_t i = 0; i < replace_zero_vec.size(); i++) { const CowOperation* cow_op = replace_zero_vec[i]; - void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ); + void* buffer = bufsink_.AcquireBuffer(BLOCK_SZ); if (!buffer) { - SNAP_LOG(ERROR) << "Failed to acquire buffer in merge"; + SNAP_LOG(ERROR) << "AcquireBuffer failed in MergeReplaceOps"; return false; } if (cow_op->type == kCowReplaceOp) { @@ -120,8 +120,6 @@ bool MergeWorker::MergeReplaceZeroOps() { CHECK(cow_op->type == kCowZeroOp); memset(buffer, 0, BLOCK_SZ); } - - bufsink_.UpdateBufferOffset(BLOCK_SZ); } size_t io_size = linear_blocks * BLOCK_SZ; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp index 399f7b81baf0..3e9588b53d5b 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp @@ -492,7 +492,7 @@ bool ReadAhead::ReadXorData(size_t block_index, size_t xor_op_index, if (xor_op_index < xor_op_vec.size()) { const CowOperation* xor_op = xor_op_vec[xor_op_index]; if (xor_op->new_block == new_block) { - void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ); + void* buffer = bufsink_.AcquireBuffer(BLOCK_SZ); if (!buffer) { SNAP_LOG(ERROR) << "ReadAhead - failed to allocate buffer for block: " << xor_op->new_block; @@ -506,7 +506,6 @@ bool ReadAhead::ReadXorData(size_t block_index, size_t xor_op_index, } xor_op_index += 1; - bufsink_.UpdateBufferOffset(BLOCK_SZ); } } block_index += 1; From ad6ca1451d034cb381d99f9b170a1024bb1d5014 Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Tue, 11 Jul 2023 09:05:11 -0700 Subject: [PATCH 0209/1487] Revert "Fix deadlock caused by two-threaded property controls" This reverts commit 606afc7b7451aba90e3634076d9b59a5ef08186b. These fixes for b/262208935 introduced a race condition. We believe the race is fixed by ag/23879563, but at this point in the release feel that reverting the fixes and refixing in main is the better solution Test: Builds, boots Bug: 283202477 Bug: 288991737 Ignore-AOSP-First: Reverting CL only in internal (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3196be61fcf0e0303cf819630876b9c812b9474e) Merged-In: I9ae6863b0ea5e064c59d9d34c03d33fa1da12fdc Change-Id: I9ae6863b0ea5e064c59d9d34c03d33fa1da12fdc --- init/property_service.cpp | 50 ++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/init/property_service.cpp b/init/property_service.cpp index 4242912ed0af..2d084db46d2a 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -117,6 +117,7 @@ static bool accept_messages = false; static std::mutex accept_messages_lock; static std::thread property_service_thread; static std::thread property_service_for_system_thread; +static std::mutex set_property_lock; static std::unique_ptr persist_write_thread; @@ -394,37 +395,32 @@ static std::optional PropertySet(const std::string& name, const std::s return {PROP_ERROR_INVALID_VALUE}; } - if (name == "sys.powerctl") { - // No action here - NotifyPropertyChange will trigger the appropriate action, and since this - // can come to the second thread, we mustn't call out to the __system_property_* functions - // which support multiple readers but only one mutator. - } else { - prop_info* pi = (prop_info*)__system_property_find(name.c_str()); - if (pi != nullptr) { - // ro.* properties are actually "write-once". - if (StartsWith(name, "ro.")) { - *error = "Read-only property was already set"; - return {PROP_ERROR_READ_ONLY_PROPERTY}; - } + auto lock = std::lock_guard{set_property_lock}; + prop_info* pi = (prop_info*)__system_property_find(name.c_str()); + if (pi != nullptr) { + // ro.* properties are actually "write-once". + if (StartsWith(name, "ro.")) { + *error = "Read-only property was already set"; + return {PROP_ERROR_READ_ONLY_PROPERTY}; + } - __system_property_update(pi, value.c_str(), valuelen); - } else { - int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen); - if (rc < 0) { - *error = "__system_property_add failed"; - return {PROP_ERROR_SET_FAILED}; - } + __system_property_update(pi, value.c_str(), valuelen); + } else { + int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen); + if (rc < 0) { + *error = "__system_property_add failed"; + return {PROP_ERROR_SET_FAILED}; } + } - // Don't write properties to disk until after we have read all default - // properties to prevent them from being overwritten by default values. - if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) { - if (persist_write_thread) { - persist_write_thread->Write(name, value, std::move(*socket)); - return {}; - } - WritePersistentProperty(name, value); + // Don't write properties to disk until after we have read all default + // properties to prevent them from being overwritten by default values. + if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) { + if (persist_write_thread) { + persist_write_thread->Write(name, value, std::move(*socket)); + return {}; } + WritePersistentProperty(name, value); } NotifyPropertyChange(name, value); From de5f915991bb445ddadd4a3889874ee97dc7913d Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Tue, 11 Jul 2023 09:05:27 -0700 Subject: [PATCH 0210/1487] Revert "Listen on property_service_for_system socket" This reverts commit 90879edeea0b2fd1e766428693d736163f39c511. These fixes for b/262208935 introduced a race condition. We believe the race is fixed by ag/23879563, but at this point in the release feel that reverting the fixes and refixing in main is the better solution Test: Builds, boots Bug: 283202477 Bug: 288991737 Ignore-AOSP-First: Reverting CL only in internal (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:be392fc69318d376f18eed7c8ef5ded0d1dc8648) Merged-In: I28491e90847f6aa0c9767b27e1d99190637048b9 Change-Id: I28491e90847f6aa0c9767b27e1d99190637048b9 --- init/property_service.cpp | 53 ++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/init/property_service.cpp b/init/property_service.cpp index 2d084db46d2a..8da69822ccb9 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -57,12 +57,12 @@ #include #include #include -#include #include #include #include #include #include + #include "debug_ramdisk.h" #include "epoll.h" #include "init.h" @@ -111,13 +111,12 @@ constexpr auto API_LEVEL_CURRENT = 10000; static bool persistent_properties_loaded = false; +static int property_set_fd = -1; static int from_init_socket = -1; static int init_socket = -1; static bool accept_messages = false; static std::mutex accept_messages_lock; static std::thread property_service_thread; -static std::thread property_service_for_system_thread; -static std::mutex set_property_lock; static std::unique_ptr persist_write_thread; @@ -395,7 +394,6 @@ static std::optional PropertySet(const std::string& name, const std::s return {PROP_ERROR_INVALID_VALUE}; } - auto lock = std::lock_guard{set_property_lock}; prop_info* pi = (prop_info*)__system_property_find(name.c_str()); if (pi != nullptr) { // ro.* properties are actually "write-once". @@ -581,10 +579,10 @@ uint32_t HandlePropertySetNoSocket(const std::string& name, const std::string& v return *ret; } -static void handle_property_set_fd(int fd) { +static void handle_property_set_fd() { static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */ - int s = accept4(fd, nullptr, nullptr, SOCK_CLOEXEC); + int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC); if (s == -1) { return; } @@ -1421,21 +1419,19 @@ static void HandleInitSocket() { } } -static void PropertyServiceThread(int fd, bool listen_init) { +static void PropertyServiceThread() { Epoll epoll; if (auto result = epoll.Open(); !result.ok()) { LOG(FATAL) << result.error(); } - if (auto result = epoll.RegisterHandler(fd, std::bind(handle_property_set_fd, fd)); + if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd); !result.ok()) { LOG(FATAL) << result.error(); } - if (listen_init) { - if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) { - LOG(FATAL) << result.error(); - } + if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) { + LOG(FATAL) << result.error(); } while (true) { @@ -1486,23 +1482,6 @@ void PersistWriteThread::Write(std::string name, std::string value, SocketConnec cv_.notify_all(); } -void StartThread(const char* name, int mode, int gid, std::thread& t, bool listen_init) { - int fd = -1; - if (auto result = CreateSocket(name, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - /*passcred=*/false, /*should_listen=*/false, mode, /*uid=*/0, - /*gid=*/gid, /*socketcon=*/{}); - result.ok()) { - fd = *result; - } else { - LOG(FATAL) << "start_property_service socket creation failed: " << result.error(); - } - - listen(fd, 8); - - auto new_thread = std::thread(PropertyServiceThread, fd, listen_init); - t.swap(new_thread); -} - void StartPropertyService(int* epoll_socket) { InitPropertySet("ro.property_service.version", "2"); @@ -1514,9 +1493,19 @@ void StartPropertyService(int* epoll_socket) { init_socket = sockets[1]; StartSendingMessages(); - StartThread(PROP_SERVICE_FOR_SYSTEM_NAME, 0660, AID_SYSTEM, property_service_for_system_thread, - true); - StartThread(PROP_SERVICE_NAME, 0666, 0, property_service_thread, false); + if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + /*passcred=*/false, /*should_listen=*/false, 0666, /*uid=*/0, + /*gid=*/0, /*socketcon=*/{}); + result.ok()) { + property_set_fd = *result; + } else { + LOG(FATAL) << "start_property_service socket creation failed: " << result.error(); + } + + listen(property_set_fd, 8); + + auto new_thread = std::thread{PropertyServiceThread}; + property_service_thread.swap(new_thread); auto async_persist_writes = android::base::GetBoolProperty("ro.property_service.async_persist_writes", false); From 689adfad37bb2fc98fd9b687c3e087901255328e Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Tue, 18 Jul 2023 08:39:10 -0700 Subject: [PATCH 0211/1487] Listen on property_service_for_system socket for powerctl messages It is easy to dos the property_service socket, since it will wait for a complete data packet from one command before moving on to the next one. To prevent low privilege apps interfering with system and root apps, add a second property_service socket that only they can use. However, since writes to properties are not thread-safe, limit use of this second socket to just sys.powerctl messages. These are the messages that this security issue is concerned about, and they do not actually write to the properties, rather they are acted upon immediately. Bug: 262208935 Test: Builds, boots Ignore-AOSP-First: Security fix Change-Id: I32835de31bb42c91b6479051ddf4b26b5c0b163f --- init/property_service.cpp | 108 ++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 46 deletions(-) diff --git a/init/property_service.cpp b/init/property_service.cpp index 8da69822ccb9..3e9a6d9f342e 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -57,12 +57,12 @@ #include #include #include +#include #include #include #include #include #include - #include "debug_ramdisk.h" #include "epoll.h" #include "init.h" @@ -111,12 +111,13 @@ constexpr auto API_LEVEL_CURRENT = 10000; static bool persistent_properties_loaded = false; -static int property_set_fd = -1; static int from_init_socket = -1; static int init_socket = -1; static bool accept_messages = false; static std::mutex accept_messages_lock; +static std::mutex selinux_check_access_lock; static std::thread property_service_thread; +static std::thread property_service_for_system_thread; static std::unique_ptr persist_write_thread; @@ -161,6 +162,7 @@ bool CanReadProperty(const std::string& source_context, const std::string& name) ucred cr = {.pid = 0, .uid = 0, .gid = 0}; audit_data.cr = &cr; + auto lock = std::lock_guard{selinux_check_access_lock}; return selinux_check_access(source_context.c_str(), target_context, "file", "read", &audit_data) == 0; } @@ -176,10 +178,9 @@ static bool CheckMacPerms(const std::string& name, const char* target_context, audit_data.name = name.c_str(); audit_data.cr = &cr; - bool has_access = (selinux_check_access(source_context, target_context, "property_service", - "set", &audit_data) == 0); - - return has_access; + auto lock = std::lock_guard{selinux_check_access_lock}; + return selinux_check_access(source_context, target_context, "property_service", "set", + &audit_data) == 0; } void NotifyPropertyChange(const std::string& name, const std::string& value) { @@ -394,31 +395,37 @@ static std::optional PropertySet(const std::string& name, const std::s return {PROP_ERROR_INVALID_VALUE}; } - prop_info* pi = (prop_info*)__system_property_find(name.c_str()); - if (pi != nullptr) { - // ro.* properties are actually "write-once". - if (StartsWith(name, "ro.")) { - *error = "Read-only property was already set"; - return {PROP_ERROR_READ_ONLY_PROPERTY}; - } - - __system_property_update(pi, value.c_str(), valuelen); + if (name == "sys.powerctl") { + // No action here - NotifyPropertyChange will trigger the appropriate action, and since this + // can come to the second thread, we mustn't call out to the __system_property_* functions + // which support multiple readers but only one mutator. } else { - int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen); - if (rc < 0) { - *error = "__system_property_add failed"; - return {PROP_ERROR_SET_FAILED}; + prop_info* pi = (prop_info*)__system_property_find(name.c_str()); + if (pi != nullptr) { + // ro.* properties are actually "write-once". + if (StartsWith(name, "ro.")) { + *error = "Read-only property was already set"; + return {PROP_ERROR_READ_ONLY_PROPERTY}; + } + + __system_property_update(pi, value.c_str(), valuelen); + } else { + int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen); + if (rc < 0) { + *error = "__system_property_add failed"; + return {PROP_ERROR_SET_FAILED}; + } } - } - // Don't write properties to disk until after we have read all default - // properties to prevent them from being overwritten by default values. - if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) { - if (persist_write_thread) { - persist_write_thread->Write(name, value, std::move(*socket)); - return {}; + // Don't write properties to disk until after we have read all default + // properties to prevent them from being overwritten by default values. + if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) { + if (persist_write_thread) { + persist_write_thread->Write(name, value, std::move(*socket)); + return {}; + } + WritePersistentProperty(name, value); } - WritePersistentProperty(name, value); } NotifyPropertyChange(name, value); @@ -579,10 +586,10 @@ uint32_t HandlePropertySetNoSocket(const std::string& name, const std::string& v return *ret; } -static void handle_property_set_fd() { +static void handle_property_set_fd(int fd) { static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */ - int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC); + int s = accept4(fd, nullptr, nullptr, SOCK_CLOEXEC); if (s == -1) { return; } @@ -1419,19 +1426,21 @@ static void HandleInitSocket() { } } -static void PropertyServiceThread() { +static void PropertyServiceThread(int fd, bool listen_init) { Epoll epoll; if (auto result = epoll.Open(); !result.ok()) { LOG(FATAL) << result.error(); } - if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd); + if (auto result = epoll.RegisterHandler(fd, std::bind(handle_property_set_fd, fd)); !result.ok()) { LOG(FATAL) << result.error(); } - if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) { - LOG(FATAL) << result.error(); + if (listen_init) { + if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) { + LOG(FATAL) << result.error(); + } } while (true) { @@ -1482,6 +1491,23 @@ void PersistWriteThread::Write(std::string name, std::string value, SocketConnec cv_.notify_all(); } +void StartThread(const char* name, int mode, int gid, std::thread& t, bool listen_init) { + int fd = -1; + if (auto result = CreateSocket(name, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + /*passcred=*/false, /*should_listen=*/false, mode, /*uid=*/0, + /*gid=*/gid, /*socketcon=*/{}); + result.ok()) { + fd = *result; + } else { + LOG(FATAL) << "start_property_service socket creation failed: " << result.error(); + } + + listen(fd, 8); + + auto new_thread = std::thread(PropertyServiceThread, fd, listen_init); + t.swap(new_thread); +} + void StartPropertyService(int* epoll_socket) { InitPropertySet("ro.property_service.version", "2"); @@ -1493,19 +1519,9 @@ void StartPropertyService(int* epoll_socket) { init_socket = sockets[1]; StartSendingMessages(); - if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - /*passcred=*/false, /*should_listen=*/false, 0666, /*uid=*/0, - /*gid=*/0, /*socketcon=*/{}); - result.ok()) { - property_set_fd = *result; - } else { - LOG(FATAL) << "start_property_service socket creation failed: " << result.error(); - } - - listen(property_set_fd, 8); - - auto new_thread = std::thread{PropertyServiceThread}; - property_service_thread.swap(new_thread); + StartThread(PROP_SERVICE_FOR_SYSTEM_NAME, 0660, AID_SYSTEM, property_service_for_system_thread, + true); + StartThread(PROP_SERVICE_NAME, 0666, 0, property_service_thread, false); auto async_persist_writes = android::base::GetBoolProperty("ro.property_service.async_persist_writes", false); From 3adb2a63bed9e97a5a179316b4f14a3196df81e3 Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Tue, 11 Jul 2023 09:05:11 -0700 Subject: [PATCH 0212/1487] Revert "Fix deadlock caused by two-threaded property controls" This reverts commit 606afc7b7451aba90e3634076d9b59a5ef08186b. These fixes for b/262208935 introduced a race condition. We believe the race is fixed by ag/23879563, but at this point in the release feel that reverting the fixes and refixing in main is the better solution Test: Builds, boots Bug: 283202477 Bug: 288991737 Ignore-AOSP-First: Reverting CL only in internal (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3196be61fcf0e0303cf819630876b9c812b9474e) Merged-In: I9ae6863b0ea5e064c59d9d34c03d33fa1da12fdc Change-Id: I9ae6863b0ea5e064c59d9d34c03d33fa1da12fdc --- init/property_service.cpp | 50 ++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/init/property_service.cpp b/init/property_service.cpp index 4242912ed0af..2d084db46d2a 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -117,6 +117,7 @@ static bool accept_messages = false; static std::mutex accept_messages_lock; static std::thread property_service_thread; static std::thread property_service_for_system_thread; +static std::mutex set_property_lock; static std::unique_ptr persist_write_thread; @@ -394,37 +395,32 @@ static std::optional PropertySet(const std::string& name, const std::s return {PROP_ERROR_INVALID_VALUE}; } - if (name == "sys.powerctl") { - // No action here - NotifyPropertyChange will trigger the appropriate action, and since this - // can come to the second thread, we mustn't call out to the __system_property_* functions - // which support multiple readers but only one mutator. - } else { - prop_info* pi = (prop_info*)__system_property_find(name.c_str()); - if (pi != nullptr) { - // ro.* properties are actually "write-once". - if (StartsWith(name, "ro.")) { - *error = "Read-only property was already set"; - return {PROP_ERROR_READ_ONLY_PROPERTY}; - } + auto lock = std::lock_guard{set_property_lock}; + prop_info* pi = (prop_info*)__system_property_find(name.c_str()); + if (pi != nullptr) { + // ro.* properties are actually "write-once". + if (StartsWith(name, "ro.")) { + *error = "Read-only property was already set"; + return {PROP_ERROR_READ_ONLY_PROPERTY}; + } - __system_property_update(pi, value.c_str(), valuelen); - } else { - int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen); - if (rc < 0) { - *error = "__system_property_add failed"; - return {PROP_ERROR_SET_FAILED}; - } + __system_property_update(pi, value.c_str(), valuelen); + } else { + int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen); + if (rc < 0) { + *error = "__system_property_add failed"; + return {PROP_ERROR_SET_FAILED}; } + } - // Don't write properties to disk until after we have read all default - // properties to prevent them from being overwritten by default values. - if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) { - if (persist_write_thread) { - persist_write_thread->Write(name, value, std::move(*socket)); - return {}; - } - WritePersistentProperty(name, value); + // Don't write properties to disk until after we have read all default + // properties to prevent them from being overwritten by default values. + if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) { + if (persist_write_thread) { + persist_write_thread->Write(name, value, std::move(*socket)); + return {}; } + WritePersistentProperty(name, value); } NotifyPropertyChange(name, value); From 8543f7dcd4fa94c7aeba938ad78679915ea8b1cd Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Tue, 11 Jul 2023 09:05:27 -0700 Subject: [PATCH 0213/1487] Revert "Listen on property_service_for_system socket" This reverts commit 90879edeea0b2fd1e766428693d736163f39c511. These fixes for b/262208935 introduced a race condition. We believe the race is fixed by ag/23879563, but at this point in the release feel that reverting the fixes and refixing in main is the better solution Test: Builds, boots Bug: 283202477 Bug: 288991737 Ignore-AOSP-First: Reverting CL only in internal (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:be392fc69318d376f18eed7c8ef5ded0d1dc8648) Merged-In: I28491e90847f6aa0c9767b27e1d99190637048b9 Change-Id: I28491e90847f6aa0c9767b27e1d99190637048b9 --- init/property_service.cpp | 53 ++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/init/property_service.cpp b/init/property_service.cpp index 2d084db46d2a..8da69822ccb9 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -57,12 +57,12 @@ #include #include #include -#include #include #include #include #include #include + #include "debug_ramdisk.h" #include "epoll.h" #include "init.h" @@ -111,13 +111,12 @@ constexpr auto API_LEVEL_CURRENT = 10000; static bool persistent_properties_loaded = false; +static int property_set_fd = -1; static int from_init_socket = -1; static int init_socket = -1; static bool accept_messages = false; static std::mutex accept_messages_lock; static std::thread property_service_thread; -static std::thread property_service_for_system_thread; -static std::mutex set_property_lock; static std::unique_ptr persist_write_thread; @@ -395,7 +394,6 @@ static std::optional PropertySet(const std::string& name, const std::s return {PROP_ERROR_INVALID_VALUE}; } - auto lock = std::lock_guard{set_property_lock}; prop_info* pi = (prop_info*)__system_property_find(name.c_str()); if (pi != nullptr) { // ro.* properties are actually "write-once". @@ -581,10 +579,10 @@ uint32_t HandlePropertySetNoSocket(const std::string& name, const std::string& v return *ret; } -static void handle_property_set_fd(int fd) { +static void handle_property_set_fd() { static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */ - int s = accept4(fd, nullptr, nullptr, SOCK_CLOEXEC); + int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC); if (s == -1) { return; } @@ -1421,21 +1419,19 @@ static void HandleInitSocket() { } } -static void PropertyServiceThread(int fd, bool listen_init) { +static void PropertyServiceThread() { Epoll epoll; if (auto result = epoll.Open(); !result.ok()) { LOG(FATAL) << result.error(); } - if (auto result = epoll.RegisterHandler(fd, std::bind(handle_property_set_fd, fd)); + if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd); !result.ok()) { LOG(FATAL) << result.error(); } - if (listen_init) { - if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) { - LOG(FATAL) << result.error(); - } + if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) { + LOG(FATAL) << result.error(); } while (true) { @@ -1486,23 +1482,6 @@ void PersistWriteThread::Write(std::string name, std::string value, SocketConnec cv_.notify_all(); } -void StartThread(const char* name, int mode, int gid, std::thread& t, bool listen_init) { - int fd = -1; - if (auto result = CreateSocket(name, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - /*passcred=*/false, /*should_listen=*/false, mode, /*uid=*/0, - /*gid=*/gid, /*socketcon=*/{}); - result.ok()) { - fd = *result; - } else { - LOG(FATAL) << "start_property_service socket creation failed: " << result.error(); - } - - listen(fd, 8); - - auto new_thread = std::thread(PropertyServiceThread, fd, listen_init); - t.swap(new_thread); -} - void StartPropertyService(int* epoll_socket) { InitPropertySet("ro.property_service.version", "2"); @@ -1514,9 +1493,19 @@ void StartPropertyService(int* epoll_socket) { init_socket = sockets[1]; StartSendingMessages(); - StartThread(PROP_SERVICE_FOR_SYSTEM_NAME, 0660, AID_SYSTEM, property_service_for_system_thread, - true); - StartThread(PROP_SERVICE_NAME, 0666, 0, property_service_thread, false); + if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + /*passcred=*/false, /*should_listen=*/false, 0666, /*uid=*/0, + /*gid=*/0, /*socketcon=*/{}); + result.ok()) { + property_set_fd = *result; + } else { + LOG(FATAL) << "start_property_service socket creation failed: " << result.error(); + } + + listen(property_set_fd, 8); + + auto new_thread = std::thread{PropertyServiceThread}; + property_service_thread.swap(new_thread); auto async_persist_writes = android::base::GetBoolProperty("ro.property_service.async_persist_writes", false); From 253445ce3ad507f41c61ebf0f829f75ee2c37509 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Tue, 18 Jul 2023 18:46:34 +0000 Subject: [PATCH 0214/1487] threads.h: avoid defining gettid on glibc >= 2.30 The issue in https://bugs.chromium.org/p/chromium/issues/detail?id=1182060 also exists on glibc 2.30 and 2.31 since `gettid` was Introduced in glibc 2.30. See https://man7.org/linux/man-pages/man2/gettid.2.html Bug: 285204695 Test: Build Change-Id: I7e534edf8c0a20c415232bcfffabbf2c1d6eec98 --- libcutils/include/cutils/threads.h | 2 +- libcutils/threads.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libcutils/include/cutils/threads.h b/libcutils/include/cutils/threads.h index 0082c6c63445..18861840e28d 100644 --- a/libcutils/include/cutils/threads.h +++ b/libcutils/include/cutils/threads.h @@ -31,7 +31,7 @@ extern "C" { // // Deprecated: use android::base::GetThreadId instead, which doesn't truncate on Mac/Windows. // -#if !defined(__GLIBC__) || __GLIBC__ >= 2 && __GLIBC_MINOR__ < 32 +#if !defined(__GLIBC__) || __GLIBC__ >= 2 && __GLIBC_MINOR__ < 30 extern pid_t gettid(); #endif diff --git a/libcutils/threads.cpp b/libcutils/threads.cpp index 6ece7a3afc93..2638720847d8 100644 --- a/libcutils/threads.cpp +++ b/libcutils/threads.cpp @@ -25,9 +25,9 @@ #include #endif -#if defined(__BIONIC__) || defined(__GLIBC__) && __GLIBC_MINOR__ >= 32 +#if defined(__BIONIC__) || defined(__GLIBC__) && __GLIBC_MINOR__ >= 30 // No definition needed for Android because we'll just pick up bionic's copy. -// No definition needed for Glibc >= 2.32 because it exposes its own copy. +// No definition needed for Glibc >= 2.30 because it exposes its own copy. #else pid_t gettid() { #if defined(__APPLE__) From 749becfa689186a6ab5cc6d83f9f470cced9b05c Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 13 Jul 2023 21:19:50 +0000 Subject: [PATCH 0215/1487] Fix libutils_fuzz_string8 deadlock. Bug: 290835996 Test: libutils_fuzz_string8 for several minutes Change-Id: I9b312dd968c380f4fa2a837d38121d0a7a7ac7b1 --- libutils/String8_fuzz.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp index faf49b66b5ce..e5dcd316ecb0 100644 --- a/libutils/String8_fuzz.cpp +++ b/libutils/String8_fuzz.cpp @@ -45,6 +45,8 @@ std::vectortoLower(); }, [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void { + if (str2->size() == 0) return; + str1->removeAll(str2->c_str()); }, [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void { From 658182b8e7ce29c1e14ea0b96b147cd6a21f1144 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 18 Jul 2023 15:36:26 -0700 Subject: [PATCH 0216/1487] Adding documentation adding --help documentation to fastboot for --disable-super-optimization and --disable-fastboot-info Test: fastboot -h Change-Id: Ia8993b3894d302a63cc97796d66e0af3fb004eef --- fastboot/fastboot.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 61c7204daacd..b64888ace83a 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -630,6 +630,9 @@ static int show_help() { " --skip-reboot Don't reboot device after flashing.\n" " --disable-verity Sets disable-verity when flashing vbmeta.\n" " --disable-verification Sets disable-verification when flashing vbmeta.\n" + " --disable-super-optimization\n" + " Disables optimizations on flashing super partition.\n" + " --disable-fastboot-info Will collects tasks from image list rather than $OUT/fastboot-info.txt.\n" " --fs-options=OPTION[,OPTION]\n" " Enable filesystem features. OPTION supports casefold, projid, compress\n" // TODO: remove --unbuffered? From c6ce48ef190d74b11c265076518dcc69f6fe4665 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Fri, 14 Jul 2023 16:35:09 -0700 Subject: [PATCH 0217/1487] String8: fix infinite loop and segmentation fault in removeAll() Bug: 290835996 Test: libutils_fuzz_string8 for several minutes String8::removeAll() has 2 serious problems: 1. When `other` is an empty string, `removeAll()` will loop infinitely due to below process: a) with `other` being empty string `""`, find() will call strstr() on an empty string, which always returns `mString`, and thus find() always return 0 in this case b) with find() returns 0 for empty string, the next while loop in String8::removeAll() will keep loop infinitely as `index` will always be 0 This CL fixes this problem by returning true if `other` is an empty string (i.e. `strlen(other) == 0`), this follows the logic that an empty string will always be found and no actual remove needs to be done. 2. When `other` is a NULL string, strstr() has undefined behavior. See https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf. This undefined behavior on Android unfortunately causes immediate segmentation fault as the current `strstr` implementation in bionic libc doesn't check `needle` being NULL, and an access to a NULL location is performed to check if the `needle` string is an empty string, and thus causes segmentation fault. This CL gives an error message and aborts instead of having a segfault, and to keep some backward compatibility. This CL also adds test for String8::removeAll() Change-Id: Ie2ccee6767efe0fed476db4ec6072717198279e9 --- libutils/String8.cpp | 5 +++++ libutils/String8_test.cpp | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/libutils/String8.cpp b/libutils/String8.cpp index 82f5cb682b47..8d312b57ce2b 100644 --- a/libutils/String8.cpp +++ b/libutils/String8.cpp @@ -393,6 +393,11 @@ ssize_t String8::find(const char* other, size_t start) const } bool String8::removeAll(const char* other) { + ALOG_ASSERT(other, "String8::removeAll() requires a non-NULL string"); + + if (*other == '\0') + return true; + ssize_t index = find(other); if (index < 0) return false; diff --git a/libutils/String8_test.cpp b/libutils/String8_test.cpp index 1356cd08f53b..35fd512f442d 100644 --- a/libutils/String8_test.cpp +++ b/libutils/String8_test.cpp @@ -114,3 +114,21 @@ TEST_F(String8Test, append) { EXPECT_EQ(NO_MEMORY, s.append("baz", SIZE_MAX)); EXPECT_STREQ("foobar", s); } + +TEST_F(String8Test, removeAll) { + String8 s("Hello, world!"); + + // NULL input should cause an assertion failure and error message in logcat + EXPECT_DEATH(s.removeAll(NULL), ""); + + // expect to return true and string content should remain unchanged + EXPECT_TRUE(s.removeAll("")); + EXPECT_STREQ("Hello, world!", s); + + // expect to return false + EXPECT_FALSE(s.removeAll("x")); + EXPECT_STREQ("Hello, world!", s); + + EXPECT_TRUE(s.removeAll("o")); + EXPECT_STREQ("Hell, wrld!", s); +} From 7acaea6770021889d1745b8fb54b57b7cf10585a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 19 Jul 2023 01:13:15 +0000 Subject: [PATCH 0218/1487] init.rc: stop calling 'fsverity_init --load-verified-keys' Since Android 14, Android does not use fsverity builtin signatures. (fsverity remains supported, but signatures are verified in userspace, or fsverity is used for integrity-only use cases.) Therefore, the only reason to still run 'fsverity_init --load-verified-keys' at boot time is to ensure that old files can still be opened, if: - They were created by Android 13 or earlier, with an fsverity builtin signature by a key in /{system,product}/etc/security/fsverity/. - *And*, the kernel still has CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y. However, it appears that this isn't actually needed anymore. Only two features could potentially be affected: APK verity and updatable fonts. APK verity wasn't widely rolled out before being disabled, and updatable fonts have recovery logic in place for when the files cannot be opened. And in any case, disabling CONFIG_FS_VERITY_BUILTIN_SIGNATURES in the kernel is recommended and would avoid any problem. Bug: 290064770 Test: presubmit Change-Id: I3376c3f0b4b9bd4ba2fd614259522be0c1daafb6 --- rootdir/Android.bp | 5 +---- rootdir/init.rc | 3 --- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/rootdir/Android.bp b/rootdir/Android.bp index e98733ada721..65865a65b4ea 100644 --- a/rootdir/Android.bp +++ b/rootdir/Android.bp @@ -20,10 +20,7 @@ prebuilt_etc { name: "init.rc", src: "init.rc", sub_dir: "init/hw", - required: [ - "fsverity_init", - "platform-bootclasspath", - ], + required: ["platform-bootclasspath"], } prebuilt_etc { diff --git a/rootdir/init.rc b/rootdir/init.rc index d2499ef3816e..dec763ac1df9 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -629,9 +629,6 @@ on late-fs # HALs required before storage encryption can get unlocked (FBE) class_start early_hal - # Load trusted keys from dm-verity protected partitions - exec -- /system/bin/fsverity_init --load-verified-keys - # Only enable the bootreceiver tracing instance for kernels 5.10 and above. on late-fs && property:ro.kernel.version=4.9 setprop bootreceiver.enable 0 From e37743292464cd8ae4f3d198c318bbe4ab3e71a8 Mon Sep 17 00:00:00 2001 From: Jakob Vukalovic Date: Tue, 11 Jul 2023 10:28:53 +0100 Subject: [PATCH 0219/1487] ueventd: Fix creation of VFIO dev nodes VFIO nodes, both the container (`vfio`) node and group (numbered) nodes, should be located in `/dev/vfio`. This change prevents ueventd from flattening that structure. Test: Bind a device to VFIO driver to create a VFIO group Change-Id: I635e9febe6bb52718df263e735479f361eacad4c --- init/devices.cpp | 2 ++ rootdir/ueventd.rc | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/init/devices.cpp b/init/devices.cpp index d29ffd604f4e..7c234924b450 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -568,6 +568,8 @@ void DeviceHandler::HandleUevent(const Uevent& uevent) { return; } else if (uevent.subsystem == "misc" && StartsWith(uevent.device_name, "dm-user/")) { devpath = "/dev/dm-user/" + uevent.device_name.substr(8); + } else if (uevent.subsystem == "misc" && uevent.device_name == "vfio/vfio") { + devpath = "/dev/" + uevent.device_name; } else { devpath = "/dev/" + Basename(uevent.path); } diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc index 0b7ffb8ea684..60dcc2a95c9f 100644 --- a/rootdir/ueventd.rc +++ b/rootdir/ueventd.rc @@ -23,6 +23,11 @@ subsystem sound subsystem dma_heap devname uevent_devpath dirname /dev/dma_heap + +subsystem vfio + devname uevent_devpath + dirname /dev/vfio + # ueventd can only set permissions on device nodes and their associated # sysfs attributes, not on arbitrary paths. # @@ -43,6 +48,7 @@ subsystem dma_heap /dev/binder 0666 root root /dev/hwbinder 0666 root root /dev/vndbinder 0666 root root +/dev/vfio/* 0666 root root /dev/pmsg0 0222 root log /dev/dma_heap/system 0444 system system From fb92cd3c22980e6ee6574be193f8ec993d19b2bf Mon Sep 17 00:00:00 2001 From: Stephen Crane Date: Mon, 17 Jul 2023 20:29:46 +0000 Subject: [PATCH 0220/1487] storageproxyd: Start binder thread pool The Trusty storage proxy requires that the suspend service is started to acquire a wakelock for UFS RPMB operations. Without the binder thread pool running, starting this service results in at least a 1s polling delay. This change ensures that we start the thread pool before handling any RPMB operations, so acquiring the wakelock will complete as soon as the service is ready without needing to poll once per second. Test: m storageproxyd Test: Artificially delay suspend_service to check if we poll Bug: 281951047 Change-Id: I1a4cdd48d57201b0cf9c24523d22e5bdbcea376a --- trusty/storage/proxy/Android.bp | 1 + trusty/storage/proxy/proxy.c | 10 ++++++++++ trusty/storage/proxy/rpmb.c | 8 ++++++++ 3 files changed, 19 insertions(+) diff --git a/trusty/storage/proxy/Android.bp b/trusty/storage/proxy/Android.bp index 2e97ee0fe568..e362b8b97e21 100644 --- a/trusty/storage/proxy/Android.bp +++ b/trusty/storage/proxy/Android.bp @@ -33,6 +33,7 @@ cc_binary { shared_libs: [ "libbase", + "libbinder_ndk", "libcutils", "liblog", "libhardware_legacy", diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c index c89c5b6fd21b..3b744ec9422f 100644 --- a/trusty/storage/proxy/proxy.c +++ b/trusty/storage/proxy/proxy.c @@ -24,6 +24,7 @@ #include #include +#include #include #include "checkpoint_handling.h" @@ -238,6 +239,15 @@ int main(int argc, char* argv[]) { /* parse arguments */ parse_args(argc, argv); + /* + * Start binder threadpool. At least one extra binder thread is needed to + * connect to the wakelock service without relying on polling. If we poll on + * the main thread we end up pausing for at least 1s even if the service + * starts faster. + */ + ABinderProcess_setThreadPoolMaxThreadCount(1); + ABinderProcess_startThreadPool(); + /* initialize secure storage directory */ rc = storage_init(ss_data_root); if (rc < 0) return EXIT_FAILURE; diff --git a/trusty/storage/proxy/rpmb.c b/trusty/storage/proxy/rpmb.c index 22a85a72b717..1f5d1079699d 100644 --- a/trusty/storage/proxy/rpmb.c +++ b/trusty/storage/proxy/rpmb.c @@ -399,6 +399,14 @@ static int send_ufs_rpmb_req(int sg_fd, const struct storage_rpmb_send_req* req, bool is_request_write = req->reliable_write_size > 0; + /* + * Internally this call connects to the suspend service, which will cause + * this service to start if not already running. If the binder thread pool + * has not been started at this point, this call will block and poll for the + * service every 1s. We need to make sure the thread pool is started to + * receive an async notification that the service is started to avoid + * blocking (see main). + */ wl_rc = acquire_wake_lock(PARTIAL_WAKE_LOCK, UFS_WAKE_LOCK_NAME); if (wl_rc < 0) { ALOGE("%s: failed to acquire wakelock: %d, %s\n", __func__, wl_rc, strerror(errno)); From e1132a9c2ff5a039fcdd33694fe42bd245d2fca8 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 19 Jul 2023 23:03:54 -0700 Subject: [PATCH 0221/1487] snapuserd: Fix ubsan when reading a single aligned sector. When a read request is for a single sector, and the sector is block-aligned, it falls into the ReadAlignedSector path, which assumes block-sized reads. Fix this by clamping the expected size. Bug: 291862304 Test: manual test of ReadWorker::ReadAlignedSector full OTA Change-Id: I00e460c333e8a9a4dc2433443e3633f3d794da1d --- fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp index 7268fca1e1cc..7d2e3a613746 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp @@ -305,7 +305,7 @@ bool ReadWorker::ReadAlignedSector(sector_t sector, size_t sz) { return false; } - ret = BLOCK_SZ; + ret = std::min(BLOCK_SZ, read_size); } read_size -= ret; From 908056efeb612c57eee789aef43229487bce6b27 Mon Sep 17 00:00:00 2001 From: Mitchell Wills Date: Thu, 20 Jul 2023 05:32:03 +0000 Subject: [PATCH 0222/1487] Add logs in SuperLayoutBuilder::Open when the metadata isn't supported Change-Id: Ic9733775616b642f669ceb7459cccd33631ae12b --- fs_mgr/liblp/super_layout_builder.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs_mgr/liblp/super_layout_builder.cpp b/fs_mgr/liblp/super_layout_builder.cpp index 37f28e124102..5349e41a9a69 100644 --- a/fs_mgr/liblp/super_layout_builder.cpp +++ b/fs_mgr/liblp/super_layout_builder.cpp @@ -46,21 +46,21 @@ bool SuperLayoutBuilder::Open(const void* data, size_t size) { bool SuperLayoutBuilder::Open(const LpMetadata& metadata) { for (const auto& partition : metadata.partitions) { if (partition.attributes & LP_PARTITION_ATTR_SLOT_SUFFIXED) { - // Retrofit devices are not supported. + LOG(ERROR) << "Retrofit devices are not supported"; return false; } if (!(partition.attributes & LP_PARTITION_ATTR_READONLY)) { - // Writable partitions are not supported. + LOG(ERROR) << "Writable partitions are not supported"; return false; } } if (!metadata.extents.empty()) { - // Partitions that already have extents are not supported (should - // never be true of super_empty.img). + LOG(ERROR) << "Partitions that already have extents are not supported"; + // should never be true of super_empty.img. return false; } if (metadata.block_devices.size() != 1) { - // Only one "super" is supported. + LOG(ERROR) << "Only one 'super' is supported"; return false; } From 4d6fa8ccaf37f5ba5b501036cd187a184f119438 Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Thu, 20 Jul 2023 18:41:15 +0800 Subject: [PATCH 0223/1487] init_first_stage: Disable ThinLTO Static executables + x86 target build + ThinLTO produces bug behavior. Global variables are not constructor initialized, resulting in faulty runtime behavior. Bug: 169004486 Bug: 291033685 Test: Treehugger Change-Id: I777016cceb4851f2b432a37bc4d29aed56c23804 --- init/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/init/Android.bp b/init/Android.bp index 1af398a9a0ae..0b8c7dc0971d 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -394,6 +394,10 @@ init_first_stage_cc_defaults { ], static_executable: true, + lto: { + // b/169004486 ThinLTO breaks x86 static executables. + never: true, + }, system_shared_libs: [], cflags: [ From 1310d7a6d6d665299f4aa8b485809a78eba0ad9b Mon Sep 17 00:00:00 2001 From: Stephen Crane Date: Mon, 17 Jul 2023 20:29:46 +0000 Subject: [PATCH 0224/1487] storageproxyd: Start binder thread pool The Trusty storage proxy requires that the suspend service is started to acquire a wakelock for UFS RPMB operations. Without the binder thread pool running, starting this service results in at least a 1s polling delay. This change ensures that we start the thread pool before handling any RPMB operations, so acquiring the wakelock will complete as soon as the service is ready without needing to poll once per second. Test: m storageproxyd Test: Artificially delay suspend_service to check if we poll Bug: 281951047 (cherry picked from https://android-review.googlesource.com/q/commit:fb92cd3c22980e6ee6574be193f8ec993d19b2bf) Merged-In: I1a4cdd48d57201b0cf9c24523d22e5bdbcea376a Change-Id: I1a4cdd48d57201b0cf9c24523d22e5bdbcea376a --- trusty/storage/proxy/Android.bp | 1 + trusty/storage/proxy/proxy.c | 10 ++++++++++ trusty/storage/proxy/rpmb.c | 8 ++++++++ 3 files changed, 19 insertions(+) diff --git a/trusty/storage/proxy/Android.bp b/trusty/storage/proxy/Android.bp index 2e97ee0fe568..e362b8b97e21 100644 --- a/trusty/storage/proxy/Android.bp +++ b/trusty/storage/proxy/Android.bp @@ -33,6 +33,7 @@ cc_binary { shared_libs: [ "libbase", + "libbinder_ndk", "libcutils", "liblog", "libhardware_legacy", diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c index c89c5b6fd21b..3b744ec9422f 100644 --- a/trusty/storage/proxy/proxy.c +++ b/trusty/storage/proxy/proxy.c @@ -24,6 +24,7 @@ #include #include +#include #include #include "checkpoint_handling.h" @@ -238,6 +239,15 @@ int main(int argc, char* argv[]) { /* parse arguments */ parse_args(argc, argv); + /* + * Start binder threadpool. At least one extra binder thread is needed to + * connect to the wakelock service without relying on polling. If we poll on + * the main thread we end up pausing for at least 1s even if the service + * starts faster. + */ + ABinderProcess_setThreadPoolMaxThreadCount(1); + ABinderProcess_startThreadPool(); + /* initialize secure storage directory */ rc = storage_init(ss_data_root); if (rc < 0) return EXIT_FAILURE; diff --git a/trusty/storage/proxy/rpmb.c b/trusty/storage/proxy/rpmb.c index 22a85a72b717..1f5d1079699d 100644 --- a/trusty/storage/proxy/rpmb.c +++ b/trusty/storage/proxy/rpmb.c @@ -399,6 +399,14 @@ static int send_ufs_rpmb_req(int sg_fd, const struct storage_rpmb_send_req* req, bool is_request_write = req->reliable_write_size > 0; + /* + * Internally this call connects to the suspend service, which will cause + * this service to start if not already running. If the binder thread pool + * has not been started at this point, this call will block and poll for the + * service every 1s. We need to make sure the thread pool is started to + * receive an async notification that the service is started to avoid + * blocking (see main). + */ wl_rc = acquire_wake_lock(PARTIAL_WAKE_LOCK, UFS_WAKE_LOCK_NAME); if (wl_rc < 0) { ALOGE("%s: failed to acquire wakelock: %d, %s\n", __func__, wl_rc, strerror(errno)); From bf2bebd8e74908317a76c11f1951c67c0910eefb Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Fri, 21 Jul 2023 00:31:06 +0000 Subject: [PATCH 0225/1487] libprocessgroup: UIDs in linux are unsigned We use the %d format specificier for uid_t, which maps to __kernel_uid32_t, which is unsigned. [1] This is undefined behavior which can lead to paths with negative UIDs when erroneously large values are passed for uid: E libprocessgroup: No such cgroup attribute: /sys/fs/cgroup/uid_-89846/cgroup.freeze Fix it with %u. [1] https://cs.android.com/search?q=typedef.*__kernel_uid32_t&ss=android%2Fplatform%2Fsuperproject%2Fmain Change-Id: Ibb52ba2503e30e2f20770b7d23629167e38d076a --- libprocessgroup/task_profiles.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 44dba2a16694..1276a72a6ad0 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -146,7 +146,7 @@ bool ProfileAttribute::GetPathForUID(uid_t uid, std::string* path) const { 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()); + *path = StringPrintf("%s/uid_%u/%s", controller()->path(), uid, file_name.c_str()); return true; } From b2e0edcaae52804484278340813a1556db8f95ac Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Fri, 21 Jul 2023 16:19:13 +0800 Subject: [PATCH 0226/1487] fs_mgr_overlayfs: Make all string constants constexpr According to https://abseil.io/tips/140, string constants should be constexpr char array or string_view object. This avoids subtle bugs due to the toolchain shuffling object initialization order between/within compilation units. string_view has bad interoperability between C APIs as many of those functions require string values to be null-terminated. Thus we can only rely on good old c-string constants. This change groups all string constants together and change them all to constexpr char array for consistent style. Also remove some duplicated method definition. Test: adb-remount-test Change-Id: I1ed57e6dc24ce3750e72c5538c388a6872cd2b40 --- fs_mgr/fs_mgr_overlayfs_control.cpp | 117 ++++------------------------ fs_mgr/fs_mgr_overlayfs_mount.cpp | 26 +++---- fs_mgr/fs_mgr_overlayfs_mount.h | 21 ++--- 3 files changed, 36 insertions(+), 128 deletions(-) diff --git a/fs_mgr/fs_mgr_overlayfs_control.cpp b/fs_mgr/fs_mgr_overlayfs_control.cpp index 69a2ac028c6c..c9a8997f6cb1 100644 --- a/fs_mgr/fs_mgr_overlayfs_control.cpp +++ b/fs_mgr/fs_mgr_overlayfs_control.cpp @@ -71,15 +71,18 @@ namespace { constexpr char kDataScratchSizeMbProp[] = "fs_mgr.overlayfs.data_scratch_size_mb"; +constexpr char kPhysicalDevice[] = "/dev/block/by-name/"; +constexpr char kScratchImageMetadata[] = "/metadata/gsi/remount/lp_metadata"; + +constexpr char kMkF2fs[] = "/system/bin/make_f2fs"; +constexpr char kMkExt4[] = "/system/bin/mke2fs"; + // Return true if everything is mounted, but before adb is started. Right // after 'trigger load_persist_props_action' is done. static bool fs_mgr_boot_completed() { return android::base::GetBoolProperty("ro.persistent_properties.ready", false); } -constexpr auto kPhysicalDevice = "/dev/block/by-name/"; -constexpr char kScratchImageMetadata[] = "/metadata/gsi/remount/lp_metadata"; - // Note: this is meant only for recovery/first-stage init. static bool ScratchIsOnData() { // The scratch partition of DSU is managed by gsid. @@ -131,7 +134,7 @@ static bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int l } std::string fs_mgr_overlayfs_setup_dir(const std::string& dir) { - auto top = dir + kOverlayTopDir; + auto top = dir + "/" + kOverlayTopDir; AutoSetFsCreateCon createcon(kOverlayfsFileContext); if (!createcon.Ok()) { @@ -290,7 +293,7 @@ OverlayfsTeardownResult fs_mgr_overlayfs_teardown_scratch(const std::string& ove bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string& mount_point, bool* change, bool* should_destroy_scratch = nullptr) { - const auto top = overlay + kOverlayTopDir; + const auto top = overlay + "/" + kOverlayTopDir; if (!fs_mgr_access(top)) { if (should_destroy_scratch) *should_destroy_scratch = true; @@ -300,7 +303,7 @@ bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string auto cleanup_all = mount_point.empty(); const auto partition_name = android::base::Basename(mount_point); const auto oldpath = top + (cleanup_all ? "" : ("/" + partition_name)); - const auto newpath = cleanup_all ? overlay + "/." + (kOverlayTopDir + 1) + ".teardown" + const auto newpath = cleanup_all ? overlay + "/." + kOverlayTopDir + ".teardown" : top + "/." + partition_name + ".teardown"; auto ret = fs_mgr_rm_all(newpath); if (!rename(oldpath.c_str(), newpath.c_str())) { @@ -346,72 +349,6 @@ bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string return ret; } -// Mount kScratchMountPoint -bool MountScratch(const std::string& device_path, bool readonly = false) { - if (readonly) { - if (!fs_mgr_access(device_path)) { - LOG(ERROR) << "Path does not exist: " << device_path; - return false; - } - } else if (!fs_mgr_rw_access(device_path)) { - LOG(ERROR) << "Path does not exist or is not readwrite: " << device_path; - return false; - } - - std::vector filesystem_candidates; - if (fs_mgr_is_f2fs(device_path)) { - filesystem_candidates = {"f2fs", "ext4"}; - } else if (fs_mgr_is_ext4(device_path)) { - filesystem_candidates = {"ext4", "f2fs"}; - } else { - LOG(ERROR) << "Scratch partition is not f2fs or ext4"; - return false; - } - - AutoSetFsCreateCon createcon(kOverlayfsFileContext); - if (!createcon.Ok()) { - return false; - } - if (mkdir(kScratchMountPoint, 0755) && (errno != EEXIST)) { - PERROR << "create " << kScratchMountPoint; - return false; - } - - FstabEntry entry; - entry.blk_device = device_path; - entry.mount_point = kScratchMountPoint; - entry.flags = MS_NOATIME | MS_RDONLY; - if (!readonly) { - entry.flags &= ~MS_RDONLY; - entry.flags |= MS_SYNCHRONOUS; - entry.fs_options = "nodiscard"; - fs_mgr_set_blk_ro(device_path, false); - } - // check_fs requires apex runtime library - if (fs_mgr_overlayfs_already_mounted("/data", false)) { - entry.fs_mgr_flags.check = true; - } - bool mounted = false; - for (auto fs_type : filesystem_candidates) { - entry.fs_type = fs_type; - if (fs_mgr_do_mount_one(entry) == 0) { - mounted = true; - break; - } - } - if (!createcon.Restore()) { - return false; - } - if (!mounted) { - rmdir(kScratchMountPoint); - return false; - } - return true; -} - -const std::string kMkF2fs("/system/bin/make_f2fs"); -const std::string kMkExt4("/system/bin/mke2fs"); - // Note: The scratch partition of DSU is managed by gsid, and should be initialized during // first-stage-mount. Just check if the DM device for DSU scratch partition is created or not. static std::string GetDsuScratchDevice() { @@ -456,14 +393,14 @@ bool MakeScratchFilesystem(const std::string& scratch_device) { // thus do not rely on fsck to correct problems that could creep in. auto fs_type = ""s; auto command = ""s; - if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_filesystem_available("f2fs")) { + if (!access(kMkF2fs, X_OK) && fs_mgr_filesystem_available("f2fs")) { fs_type = "f2fs"; - command = kMkF2fs + " -w "; + command = kMkF2fs + " -w "s; command += std::to_string(getpagesize()); command += " -f -d1 -l" + android::base::Basename(kScratchMountPoint); - } else if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_filesystem_available("ext4")) { + } else if (!access(kMkExt4, X_OK) && fs_mgr_filesystem_available("ext4")) { fs_type = "ext4"; - command = kMkExt4 + " -F -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint; + command = kMkExt4 + " -F -b 4096 -t ext4 -m 0 -O has_journal -M "s + kScratchMountPoint; } else { LERROR << "No supported mkfs command or filesystem driver available, supported filesystems " "are: f2fs, ext4"; @@ -697,7 +634,7 @@ bool fs_mgr_overlayfs_setup_scratch(const Fstab& fstab) { // If the partition exists, assume first that it can be mounted. if (partition_exists) { if (MountScratch(scratch_device)) { - if (fs_mgr_access(std::string(kScratchMountPoint) + kOverlayTopDir) || + if (fs_mgr_access(kScratchMountPoint + "/"s + kOverlayTopDir) || fs_mgr_filesystem_has_space(kScratchMountPoint)) { return true; } @@ -717,32 +654,6 @@ bool fs_mgr_overlayfs_setup_scratch(const Fstab& fstab) { return MountScratch(scratch_device); } -// NOTE: OverlayfsSetupAllowed() must be "stricter" than OverlayfsTeardownAllowed(). -// Setup is allowed only if teardown is also allowed. -bool OverlayfsSetupAllowed(bool verbose = false) { - if (!kAllowOverlayfs) { - if (verbose) { - LOG(ERROR) << "Overlayfs remounts can only be used in debuggable builds"; - } - return false; - } - // Check mandatory kernel patches. - if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) { - if (verbose) { - LOG(ERROR) << "Kernel does not support overlayfs"; - } - return false; - } - // in recovery or fastbootd, not allowed! - if (fs_mgr_in_recovery()) { - if (verbose) { - LOG(ERROR) << "Unsupported overlayfs setup from recovery"; - } - return false; - } - return true; -} - constexpr bool OverlayfsTeardownAllowed() { // Never allow on non-debuggable build. return kAllowOverlayfs; diff --git a/fs_mgr/fs_mgr_overlayfs_mount.cpp b/fs_mgr/fs_mgr_overlayfs_mount.cpp index c057c2bc1369..e380f8401112 100644 --- a/fs_mgr/fs_mgr_overlayfs_mount.cpp +++ b/fs_mgr/fs_mgr_overlayfs_mount.cpp @@ -62,13 +62,16 @@ using namespace android::storage_literals; constexpr char kPreferCacheBackingStorageProp[] = "fs_mgr.overlayfs.prefer_cache_backing_storage"; +constexpr char kCacheMountPoint[] = "/cache"; +constexpr char kPhysicalDevice[] = "/dev/block/by-name/"; + +constexpr char kLowerdirOption[] = "lowerdir="; +constexpr char kUpperdirOption[] = "upperdir="; + bool fs_mgr_access(const std::string& path) { return access(path.c_str(), F_OK) == 0; } -const auto kLowerdirOption = "lowerdir="; -const auto kUpperdirOption = "upperdir="; - bool fs_mgr_in_recovery() { // Check the existence of recovery binary instead of using the compile time // __ANDROID_RECOVERY__ macro. @@ -89,8 +92,6 @@ bool fs_mgr_is_dsu_running() { return android::gsi::IsGsiRunning(); } -const auto kCacheMountPoint = "/cache"; - static bool IsABDevice() { return !android::base::GetProperty("ro.boot.slot_suffix", "").empty(); } @@ -141,8 +142,6 @@ bool fs_mgr_filesystem_has_space(const std::string& mount_point) { (static_cast(vst.f_bfree) * vst.f_frsize) >= kSizeThreshold; } -const auto kPhysicalDevice = "/dev/block/by-name/"; - static bool fs_mgr_update_blk_device(FstabEntry* entry) { if (entry->fs_mgr_flags.logical) { fs_mgr_update_logical_partition(entry); @@ -155,7 +154,7 @@ static bool fs_mgr_update_blk_device(FstabEntry* entry) { } // special case for system-as-root (taimen and others) - auto blk_device = std::string(kPhysicalDevice) + "system"; + auto blk_device = kPhysicalDevice + "system"s; if (!fs_mgr_access(blk_device)) { blk_device += fs_mgr_get_slot_suffix(); if (!fs_mgr_access(blk_device)) { @@ -237,7 +236,7 @@ static std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point if (!fs_mgr_is_dir(mount_point)) return ""; const auto base = android::base::Basename(mount_point) + "/"; for (const auto& overlay_mount_point : OverlayMountPoints()) { - auto dir = overlay_mount_point + kOverlayTopDir + "/" + base; + auto dir = overlay_mount_point + "/" + kOverlayTopDir + "/" + base; auto upper = dir + kUpperName; if (!fs_mgr_is_dir(upper)) continue; auto work = dir + kWorkName; @@ -527,7 +526,7 @@ static bool fs_mgr_overlayfs_mount(const FstabEntry& entry) { } // Mount kScratchMountPoint -static bool MountScratch(const std::string& device_path, bool readonly = false) { +bool MountScratch(const std::string& device_path, bool readonly) { if (readonly) { if (!fs_mgr_access(device_path)) { LOG(ERROR) << "Path does not exist: " << device_path; @@ -589,9 +588,6 @@ static bool MountScratch(const std::string& device_path, bool readonly = false) return true; } -const std::string kMkF2fs("/system/bin/make_f2fs"); -const std::string kMkExt4("/system/bin/mke2fs"); - // Note: The scratch partition of DSU is managed by gsid, and should be initialized during // first-stage-mount. Just check if the DM device for DSU scratch partition is created or not. static std::string GetDsuScratchDevice() { @@ -633,7 +629,7 @@ static std::string GetBootScratchDevice() { // NOTE: OverlayfsSetupAllowed() must be "stricter" than OverlayfsTeardownAllowed(). // Setup is allowed only if teardown is also allowed. -bool OverlayfsSetupAllowed(bool verbose = false) { +bool OverlayfsSetupAllowed(bool verbose) { if (!kAllowOverlayfs) { if (verbose) { LOG(ERROR) << "Overlayfs remounts can only be used in debuggable builds"; @@ -737,7 +733,7 @@ static void TryMountScratch() { if (!MountScratch(scratch_device, true /* readonly */)) { return; } - auto has_overlayfs_dir = fs_mgr_access(std::string(kScratchMountPoint) + kOverlayTopDir); + auto has_overlayfs_dir = fs_mgr_access(kScratchMountPoint + "/"s + kOverlayTopDir); fs_mgr_overlayfs_umount_scratch(); if (has_overlayfs_dir) { MountScratch(scratch_device); diff --git a/fs_mgr/fs_mgr_overlayfs_mount.h b/fs_mgr/fs_mgr_overlayfs_mount.h index ae3ea84edab6..d9a93d4ac50a 100644 --- a/fs_mgr/fs_mgr_overlayfs_mount.h +++ b/fs_mgr/fs_mgr_overlayfs_mount.h @@ -20,9 +20,12 @@ #include -bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true); -bool fs_mgr_wants_overlayfs(android::fs_mgr::FstabEntry* entry); -android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab); +constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0"; + +constexpr char kScratchMountPoint[] = "/mnt/scratch"; +constexpr char kOverlayTopDir[] = "overlay"; +constexpr char kUpperName[] = "upper"; +constexpr char kWorkName[] = "work"; #if ALLOW_ADBD_DISABLE_VERITY constexpr bool kAllowOverlayfs = true; @@ -45,18 +48,16 @@ class AutoSetFsCreateCon final { bool restored_ = false; }; -constexpr auto kScratchMountPoint = "/mnt/scratch"; -constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0"; - -constexpr auto kUpperName = "upper"; -constexpr auto kWorkName = "work"; -constexpr auto kOverlayTopDir = "/overlay"; - bool fs_mgr_is_dsu_running(); bool fs_mgr_in_recovery(); bool fs_mgr_access(const std::string& path); bool fs_mgr_rw_access(const std::string& path); bool fs_mgr_filesystem_has_space(const std::string& mount_point); const std::string fs_mgr_mount_point(const std::string& mount_point); +bool OverlayfsSetupAllowed(bool verbose = false); +bool MountScratch(const std::string& device_path, bool readonly = false); bool fs_mgr_overlayfs_umount_scratch(); std::vector OverlayMountPoints(); +bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true); +bool fs_mgr_wants_overlayfs(android::fs_mgr::FstabEntry* entry); +android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab); From 98e3522762797ecadca62a5732372c51b60dfc59 Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Fri, 21 Jul 2023 22:31:59 +0800 Subject: [PATCH 0227/1487] fs_mgr: Refactor by inlining trivial helpers Inline some trivial helpers and remove unused header declarations. Remove fs_mgr_*access() as it is really just access(). Remove fs_mgr_overlayfs_super_device() as we always want the primary slot and having this wrapper isn't particularly helpful. Test: adb-remount-test Change-Id: I2581fd7c7d5071cbb97778535b7811dbcb80d76e --- fs_mgr/fs_mgr_fstab.cpp | 26 ++++++++------ fs_mgr/fs_mgr_overlayfs_control.cpp | 40 +++++++-------------- fs_mgr/fs_mgr_overlayfs_control.h | 2 -- fs_mgr/fs_mgr_overlayfs_mount.cpp | 54 +++++++---------------------- fs_mgr/fs_mgr_overlayfs_mount.h | 3 -- fs_mgr/fs_mgr_priv.h | 2 -- fs_mgr/include_fstab/fstab/fstab.h | 2 ++ 7 files changed, 43 insertions(+), 86 deletions(-) diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index c85e83116bde..ca27034f4451 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -328,8 +328,7 @@ bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) { // some recovery fstabs still contain the FDE options since they didn't do // anything in recovery mode anyway (except possibly to cause the // reservation of a crypto footer) and thus never got removed. - if (entry->fs_mgr_flags.crypt && !entry->fs_mgr_flags.vold_managed && - access("/system/bin/recovery", F_OK) != 0) { + if (entry->fs_mgr_flags.crypt && !entry->fs_mgr_flags.vold_managed && !InRecovery()) { LERROR << "FDE is no longer supported; 'encryptable' can only be used for adoptable " "storage"; return false; @@ -520,6 +519,9 @@ std::vector GetEntriesByPred(FstabPtr fstab, const Pred& pre // ramdisk's copy of the fstab had to be located in the root directory, but now // the system/etc directory is supported too and is the preferred location. std::string GetFstabPath() { + if (InRecovery()) { + return "/etc/recovery.fstab"; + } for (const char* prop : {"fstab_suffix", "hardware", "hardware.platform"}) { std::string suffix; @@ -835,15 +837,8 @@ bool ReadDefaultFstab(Fstab* fstab) { fstab->clear(); ReadFstabFromDt(fstab, false /* verbose */); - std::string default_fstab_path; - // Use different fstab paths for normal boot and recovery boot, respectively - if ((access("/sbin/recovery", F_OK) == 0) || (access("/system/bin/recovery", F_OK) == 0)) { - default_fstab_path = "/etc/recovery.fstab"; - } else { // normal boot - default_fstab_path = GetFstabPath(); - } - Fstab default_fstab; + const std::string default_fstab_path = GetFstabPath(); if (!default_fstab_path.empty() && ReadFstabFromFile(default_fstab_path, &default_fstab)) { for (auto&& entry : default_fstab) { fstab->emplace_back(std::move(entry)); @@ -936,6 +931,17 @@ std::string GetVerityDeviceName(const FstabEntry& entry) { return base_device + "-verity"; } +bool InRecovery() { + // Check the existence of recovery binary instead of using the compile time + // __ANDROID_RECOVERY__ macro. + // If BOARD_USES_RECOVERY_AS_BOOT is true, both normal and recovery boot + // mode would use the same init binary, which would mean during normal boot + // the '/init' binary is actually a symlink pointing to + // init_second_stage.recovery, which would be compiled with + // __ANDROID_RECOVERY__ defined. + return access("/system/bin/recovery", F_OK) == 0 || access("/sbin/recovery", F_OK) == 0; +} + } // namespace fs_mgr } // namespace android diff --git a/fs_mgr/fs_mgr_overlayfs_control.cpp b/fs_mgr/fs_mgr_overlayfs_control.cpp index c9a8997f6cb1..68576f22086d 100644 --- a/fs_mgr/fs_mgr_overlayfs_control.cpp +++ b/fs_mgr/fs_mgr_overlayfs_control.cpp @@ -18,17 +18,10 @@ #include #include #include -#include -#include #include -#include -#include -#include #include #include #include -#include -#include #include #include @@ -38,13 +31,9 @@ #include #include -#include #include #include -#include -#include #include -#include #include #include #include @@ -89,7 +78,7 @@ static bool ScratchIsOnData() { if (fs_mgr_is_dsu_running()) { return false; } - return fs_mgr_access(kScratchImageMetadata); + return access(kScratchImageMetadata, F_OK) == 0; } static bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int level = 0) { @@ -198,10 +187,6 @@ static uint32_t fs_mgr_overlayfs_slot_number() { return SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix()); } -static std::string fs_mgr_overlayfs_super_device(uint32_t slot_number) { - return kPhysicalDevice + fs_mgr_get_super_partition_name(slot_number); -} - static bool fs_mgr_overlayfs_has_logical(const Fstab& fstab) { for (const auto& entry : fstab) { if (entry.fs_mgr_flags.logical) { @@ -261,8 +246,8 @@ OverlayfsTeardownResult fs_mgr_overlayfs_teardown_scratch(const std::string& ove } auto slot_number = fs_mgr_overlayfs_slot_number(); - auto super_device = fs_mgr_overlayfs_super_device(slot_number); - if (!fs_mgr_rw_access(super_device)) { + const auto super_device = kPhysicalDevice + fs_mgr_get_super_partition_name(); + if (access(super_device.c_str(), R_OK | W_OK)) { return OverlayfsTeardownResult::Ok; } @@ -295,7 +280,7 @@ bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string bool* change, bool* should_destroy_scratch = nullptr) { const auto top = overlay + "/" + kOverlayTopDir; - if (!fs_mgr_access(top)) { + if (access(top.c_str(), F_OK)) { if (should_destroy_scratch) *should_destroy_scratch = true; return true; } @@ -443,7 +428,7 @@ static bool CreateDynamicScratch(std::string* scratch_device, bool* partition_ex auto partition_create = !*partition_exists; auto slot_number = fs_mgr_overlayfs_slot_number(); - auto super_device = fs_mgr_overlayfs_super_device(slot_number); + const auto super_device = kPhysicalDevice + fs_mgr_get_super_partition_name(); auto builder = MetadataBuilder::New(super_device, slot_number); if (!builder) { LERROR << "open " << super_device << " metadata"; @@ -583,8 +568,8 @@ static bool CreateScratchOnData(std::string* scratch_device, bool* partition_exi static bool CanUseSuperPartition(const Fstab& fstab) { auto slot_number = fs_mgr_overlayfs_slot_number(); - auto super_device = fs_mgr_overlayfs_super_device(slot_number); - if (!fs_mgr_rw_access(super_device) || !fs_mgr_overlayfs_has_logical(fstab)) { + const auto super_device = kPhysicalDevice + fs_mgr_get_super_partition_name(); + if (access(super_device.c_str(), R_OK | W_OK) || !fs_mgr_overlayfs_has_logical(fstab)) { return false; } auto metadata = ReadMetadata(super_device, slot_number); @@ -634,8 +619,8 @@ bool fs_mgr_overlayfs_setup_scratch(const Fstab& fstab) { // If the partition exists, assume first that it can be mounted. if (partition_exists) { if (MountScratch(scratch_device)) { - if (fs_mgr_access(kScratchMountPoint + "/"s + kOverlayTopDir) || - fs_mgr_filesystem_has_space(kScratchMountPoint)) { + const auto top = kScratchMountPoint + "/"s + kOverlayTopDir; + if (access(top.c_str(), F_OK) == 0 || fs_mgr_filesystem_has_space(kScratchMountPoint)) { return true; } // declare it useless, no overrides and no free space @@ -755,7 +740,7 @@ static std::optional EnsureScratchMapped() { if (!info.device.empty()) { return {std::move(info)}; } - if (!fs_mgr_in_recovery()) { + if (!InRecovery()) { return {}; } @@ -778,8 +763,7 @@ static std::optional EnsureScratchMapped() { } // Avoid uart spam by first checking for a scratch partition. - auto metadata_slot = fs_mgr_overlayfs_slot_number(); - auto super_device = fs_mgr_overlayfs_super_device(metadata_slot); + const auto super_device = kPhysicalDevice + fs_mgr_get_super_partition_name(); auto metadata = ReadCurrentMetadata(super_device); if (!metadata) { return {}; @@ -941,7 +925,7 @@ void TeardownAllOverlayForMountPoint(const std::string& mount_point) { if (!OverlayfsTeardownAllowed()) { return; } - if (!fs_mgr_in_recovery()) { + if (!InRecovery()) { LERROR << __FUNCTION__ << "(): must be called within recovery."; return; } diff --git a/fs_mgr/fs_mgr_overlayfs_control.h b/fs_mgr/fs_mgr_overlayfs_control.h index 50e83e8a30ef..b1751015844f 100644 --- a/fs_mgr/fs_mgr_overlayfs_control.h +++ b/fs_mgr/fs_mgr_overlayfs_control.h @@ -14,8 +14,6 @@ #pragma once -#include - #include // If "mount_point" is non-null, set up exactly one overlay. diff --git a/fs_mgr/fs_mgr_overlayfs_mount.cpp b/fs_mgr/fs_mgr_overlayfs_mount.cpp index e380f8401112..37e30585a040 100644 --- a/fs_mgr/fs_mgr_overlayfs_mount.cpp +++ b/fs_mgr/fs_mgr_overlayfs_mount.cpp @@ -14,16 +14,12 @@ * limitations under the License. */ -#include #include #include #include #include -#include #include -#include #include -#include #include #include #include @@ -33,7 +29,6 @@ #include #include -#include #include #include @@ -45,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -68,34 +62,15 @@ constexpr char kPhysicalDevice[] = "/dev/block/by-name/"; constexpr char kLowerdirOption[] = "lowerdir="; constexpr char kUpperdirOption[] = "upperdir="; -bool fs_mgr_access(const std::string& path) { - return access(path.c_str(), F_OK) == 0; -} - -bool fs_mgr_in_recovery() { - // Check the existence of recovery binary instead of using the compile time - // __ANDROID_RECOVERY__ macro. - // If BOARD_USES_RECOVERY_AS_BOOT is true, both normal and recovery boot - // mode would use the same init binary, which would mean during normal boot - // the '/init' binary is actually a symlink pointing to - // init_second_stage.recovery, which would be compiled with - // __ANDROID_RECOVERY__ defined. - return fs_mgr_access("/system/bin/recovery"); -} - bool fs_mgr_is_dsu_running() { // Since android::gsi::CanBootIntoGsi() or android::gsi::MarkSystemAsGsi() is // never called in recovery, the return value of android::gsi::IsGsiRunning() // is not well-defined. In this case, just return false as being in recovery // implies not running a DSU system. - if (fs_mgr_in_recovery()) return false; + if (InRecovery()) return false; return android::gsi::IsGsiRunning(); } -static bool IsABDevice() { - return !android::base::GetProperty("ro.boot.slot_suffix", "").empty(); -} - std::vector OverlayMountPoints() { // Never fallback to legacy cache mount point if within a DSU system, // because running a DSU system implies the device supports dynamic @@ -106,7 +81,8 @@ std::vector OverlayMountPoints() { // For non-A/B devices prefer cache backing storage if // kPreferCacheBackingStorageProp property set. - if (!IsABDevice() && android::base::GetBoolProperty(kPreferCacheBackingStorageProp, false) && + if (fs_mgr_get_slot_suffix().empty() && + android::base::GetBoolProperty(kPreferCacheBackingStorageProp, false) && android::base::GetIntProperty("ro.vendor.api_level", -1) < __ANDROID_API_T__) { return {kCacheMountPoint, kScratchMountPoint}; } @@ -119,11 +95,6 @@ static bool fs_mgr_is_dir(const std::string& path) { return !stat(path.c_str(), &st) && S_ISDIR(st.st_mode); } -bool fs_mgr_rw_access(const std::string& path) { - if (path.empty()) return false; - return access(path.c_str(), R_OK | W_OK) == 0; -} - // At less than 1% or 8MB of free space return value of false, // means we will try to wrap with overlayfs. bool fs_mgr_filesystem_has_space(const std::string& mount_point) { @@ -146,7 +117,7 @@ static bool fs_mgr_update_blk_device(FstabEntry* entry) { if (entry->fs_mgr_flags.logical) { fs_mgr_update_logical_partition(entry); } - if (fs_mgr_access(entry->blk_device)) { + if (access(entry->blk_device.c_str(), F_OK) == 0) { return true; } if (entry->blk_device != "/dev/root") { @@ -155,9 +126,9 @@ static bool fs_mgr_update_blk_device(FstabEntry* entry) { // special case for system-as-root (taimen and others) auto blk_device = kPhysicalDevice + "system"s; - if (!fs_mgr_access(blk_device)) { + if (access(blk_device.c_str(), F_OK)) { blk_device += fs_mgr_get_slot_suffix(); - if (!fs_mgr_access(blk_device)) { + if (access(blk_device.c_str(), F_OK)) { return false; } } @@ -241,7 +212,7 @@ static std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point if (!fs_mgr_is_dir(upper)) continue; auto work = dir + kWorkName; if (!fs_mgr_is_dir(work)) continue; - if (!fs_mgr_rw_access(work)) continue; + if (access(work.c_str(), R_OK | W_OK)) continue; return dir; } return ""; @@ -528,11 +499,11 @@ static bool fs_mgr_overlayfs_mount(const FstabEntry& entry) { // Mount kScratchMountPoint bool MountScratch(const std::string& device_path, bool readonly) { if (readonly) { - if (!fs_mgr_access(device_path)) { + if (access(device_path.c_str(), F_OK)) { LOG(ERROR) << "Path does not exist: " << device_path; return false; } - } else if (!fs_mgr_rw_access(device_path)) { + } else if (access(device_path.c_str(), R_OK | W_OK)) { LOG(ERROR) << "Path does not exist or is not readwrite: " << device_path; return false; } @@ -644,7 +615,7 @@ bool OverlayfsSetupAllowed(bool verbose) { return false; } // in recovery or fastbootd, not allowed! - if (fs_mgr_in_recovery()) { + if (InRecovery()) { if (verbose) { LOG(ERROR) << "Unsupported overlayfs setup from recovery"; } @@ -724,7 +695,7 @@ static void TryMountScratch() { // if verity is still disabled, i.e. no reboot occurred), and skips calling // fs_mgr_overlayfs_mount_all(). auto scratch_device = GetBootScratchDevice(); - if (!fs_mgr_rw_access(scratch_device)) { + if (access(scratch_device.c_str(), R_OK | W_OK)) { return; } if (!WaitForFile(scratch_device, 10s)) { @@ -733,7 +704,8 @@ static void TryMountScratch() { if (!MountScratch(scratch_device, true /* readonly */)) { return; } - auto has_overlayfs_dir = fs_mgr_access(kScratchMountPoint + "/"s + kOverlayTopDir); + const auto top = kScratchMountPoint + "/"s + kOverlayTopDir; + const bool has_overlayfs_dir = access(top.c_str(), F_OK) == 0; fs_mgr_overlayfs_umount_scratch(); if (has_overlayfs_dir) { MountScratch(scratch_device); diff --git a/fs_mgr/fs_mgr_overlayfs_mount.h b/fs_mgr/fs_mgr_overlayfs_mount.h index d9a93d4ac50a..f0afac1edfe9 100644 --- a/fs_mgr/fs_mgr_overlayfs_mount.h +++ b/fs_mgr/fs_mgr_overlayfs_mount.h @@ -49,9 +49,6 @@ class AutoSetFsCreateCon final { }; bool fs_mgr_is_dsu_running(); -bool fs_mgr_in_recovery(); -bool fs_mgr_access(const std::string& path); -bool fs_mgr_rw_access(const std::string& path); bool fs_mgr_filesystem_has_space(const std::string& mount_point); const std::string fs_mgr_mount_point(const std::string& mount_point); bool OverlayfsSetupAllowed(bool verbose = false); diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index 46cdb62cfcc1..c3b18c85c78f 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -97,8 +97,6 @@ bool is_dt_compatible(); bool fs_mgr_is_ext4(const std::string& blk_device); bool fs_mgr_is_f2fs(const std::string& blk_device); -bool fs_mgr_teardown_verity(android::fs_mgr::FstabEntry* fstab); - bool fs_mgr_filesystem_available(const std::string& filesystem); std::string fs_mgr_get_context(const std::string& mount_point); diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h index 9cb1546c5aaf..80b45ba93dc6 100644 --- a/fs_mgr/include_fstab/fstab/fstab.h +++ b/fs_mgr/include_fstab/fstab/fstab.h @@ -131,5 +131,7 @@ std::set GetBootDevices(); // expected name. std::string GetVerityDeviceName(const FstabEntry& entry); +bool InRecovery(); + } // namespace fs_mgr } // namespace android From f580fe57991f0fef9ac058040e813eeb16876af2 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Fri, 21 Jul 2023 19:13:48 +0100 Subject: [PATCH 0228/1487] Add safety comments. These will soon be required by a lint. Bug: 290018030 Test: m rust Change-Id: I0b25bcaa18d167fb9c2d63e637833d4935dc8ff4 --- libstats/pull_rust/stats_pull.rs | 7 +++++-- trusty/libtrusty-rs/src/lib.rs | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libstats/pull_rust/stats_pull.rs b/libstats/pull_rust/stats_pull.rs index 09b26232f8b8..d188b5fb5838 100644 --- a/libstats/pull_rust/stats_pull.rs +++ b/libstats/pull_rust/stats_pull.rs @@ -111,7 +111,9 @@ lazy_static! { static ref COOKIES: Mutex StatsPullResult>> = Mutex::new(HashMap::new()); } -// Safety: We store our callbacks in the global so they are valid. +/// # Safety +/// +/// `data` must be a valid pointer with no aliases. unsafe extern "C" fn callback_wrapper( atom_tag: i32, data: *mut AStatsEventList, @@ -126,7 +128,8 @@ unsafe extern "C" fn callback_wrapper( let stats = cb(); let result = stats .iter() - .map(|stat| stat.add_astats_event(&mut *data)) + // Safety: The caller promises that `data` is valid and unaliased. + .map(|stat| stat.add_astats_event(unsafe { &mut *data })) .collect::, StatsError>>(); match result { Ok(_) => { diff --git a/trusty/libtrusty-rs/src/lib.rs b/trusty/libtrusty-rs/src/lib.rs index 28ea07505b0f..22b894a47afb 100644 --- a/trusty/libtrusty-rs/src/lib.rs +++ b/trusty/libtrusty-rs/src/lib.rs @@ -102,6 +102,8 @@ impl TipcChannel { let file = File::options().read(true).write(true).open(device)?; let srv_name = CString::new(service).expect("Service name contained null bytes"); + // SAFETY: The file descriptor is valid because it came from a `File`, and the name is a + // valid C string because it came from a `CString`. unsafe { tipc_connect(file.as_raw_fd(), srv_name.as_ptr())?; } From b05b8706714a6e7eb64890e0bee012dbc69f72be Mon Sep 17 00:00:00 2001 From: Stephen Crane Date: Fri, 21 Jul 2023 19:10:40 +0000 Subject: [PATCH 0229/1487] storageproxyd: Start only a single binder thread We only need a single binder thread to receive notifications, so we should set the thread pool max to 0 rather than 1. startThreadPool() starts one thread + the max count. Test: m storageproxyd Bug: 281951047 Fixes: 292030372 Change-Id: I53a90eaa2aa69469fd3a00b6da0d7061318c8ba9 --- trusty/storage/proxy/proxy.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c index 3b744ec9422f..67e935e39324 100644 --- a/trusty/storage/proxy/proxy.c +++ b/trusty/storage/proxy/proxy.c @@ -243,9 +243,12 @@ int main(int argc, char* argv[]) { * Start binder threadpool. At least one extra binder thread is needed to * connect to the wakelock service without relying on polling. If we poll on * the main thread we end up pausing for at least 1s even if the service - * starts faster. + * starts faster. We set the max thread count to 0 because startThreadPool + * "Starts one thread, PLUS those requested in setThreadPoolMaxThreadCount, + * PLUS those manually requested in joinThreadPool." We only need a single + * binder thread to receive notifications on. */ - ABinderProcess_setThreadPoolMaxThreadCount(1); + ABinderProcess_setThreadPoolMaxThreadCount(0); ABinderProcess_startThreadPool(); /* initialize secure storage directory */ From 37c18b30cb8e19db4e4d55050aed67863831b5c5 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Thu, 20 Jul 2023 22:00:53 -0700 Subject: [PATCH 0230/1487] snapuserd: use local buffers for xor processing during sync I/O Bug: 291862304 Test: Incremental OTA on Pixel - Verify first stage boot logs Change-Id: Ifc4f1ec912ccc1d24673f7bb03b05129ce504fa1 Signed-off-by: Akilesh Kailash --- .../libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp | 2 +- .../snapuserd/user-space-merge/snapuserd_readahead.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 e52d752a0eb9..2dd2ec09d6ce 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -308,7 +308,7 @@ bool SnapshotHandler::Start() { ra_thread_status = std::async(std::launch::async, &ReadAhead::RunThread, read_ahead_thread_.get()); - SNAP_LOG(INFO) << "Read-ahead thread started..."; + SNAP_LOG(INFO) << "Read-ahead thread started"; } // Launch worker threads diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp index 3e9588b53d5b..8755820e1ed2 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp @@ -592,7 +592,7 @@ bool ReadAhead::ReadAheadSyncIO() { // Check if this block is an XOR op if (xor_op->new_block == new_block) { // Read the xor'ed data from COW - void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ); + void* buffer = bufsink.GetPayloadBuffer(BLOCK_SZ); if (!buffer) { SNAP_LOG(ERROR) << "ReadAhead - failed to allocate buffer"; return false; From c5184f79eed2efbe793a8869671c0868547f6b36 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Fri, 21 Jul 2023 15:21:28 -0700 Subject: [PATCH 0231/1487] Explicitly ignore the result of std::async The newer libc++ marks std::async with [[nodiscard]] in C++20 mode. Bug: b/175635923 Test: treehugger Change-Id: Ib63259983d952b97cf1b1c6c243c831cb72f9724 --- fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp index 978a7f25c510..71664bfa91b6 100644 --- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp +++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp @@ -734,8 +734,8 @@ void Snapuserd::ReadBlocks(const std::string& partition_name, const std::string& off_t offset = 0; for (int i = 0; i < num_threads; i++) { - std::async(std::launch::async, &Snapuserd::ReadBlocksToCache, this, dm_block_device, - partition_name, offset, read_sz_per_thread); + (void)std::async(std::launch::async, &Snapuserd::ReadBlocksToCache, this, dm_block_device, + partition_name, offset, read_sz_per_thread); offset += read_sz_per_thread; } From 209890c07d40651e5c44eb8677c6c4e555b35488 Mon Sep 17 00:00:00 2001 From: Stephen Crane Date: Fri, 21 Jul 2023 22:21:31 +0000 Subject: [PATCH 0232/1487] storageproxyd: Start only a single binder thread We only need a single binder thread to receive notifications, so we should set the thread pool max to 0 rather than 1. startThreadPool() starts one thread + the max count. Test: m storageproxyd Bug: 281951047 Fixes: 292030372 (cherry picked from https://android-review.googlesource.com/q/commit:b05b8706714a6e7eb64890e0bee012dbc69f72be) Merged-In: I53a90eaa2aa69469fd3a00b6da0d7061318c8ba9 Change-Id: I53a90eaa2aa69469fd3a00b6da0d7061318c8ba9 --- trusty/storage/proxy/proxy.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c index 3b744ec9422f..67e935e39324 100644 --- a/trusty/storage/proxy/proxy.c +++ b/trusty/storage/proxy/proxy.c @@ -243,9 +243,12 @@ int main(int argc, char* argv[]) { * Start binder threadpool. At least one extra binder thread is needed to * connect to the wakelock service without relying on polling. If we poll on * the main thread we end up pausing for at least 1s even if the service - * starts faster. + * starts faster. We set the max thread count to 0 because startThreadPool + * "Starts one thread, PLUS those requested in setThreadPoolMaxThreadCount, + * PLUS those manually requested in joinThreadPool." We only need a single + * binder thread to receive notifications on. */ - ABinderProcess_setThreadPoolMaxThreadCount(1); + ABinderProcess_setThreadPoolMaxThreadCount(0); ABinderProcess_startThreadPool(); /* initialize secure storage directory */ From cbda2c038b742915eb96e2cd469df6f804f2693a Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 18 Jul 2023 15:04:43 -0700 Subject: [PATCH 0233/1487] Adding flag to flash only static partitions adding in --exclude-dynamic-partitions to flash only bootloader partitions and skip the rest. Super optimization will be turned off as well when this flag is enabled Test: fastboot flashall --exclude-dynamic-partitions Change-Id: I4b9d70b7f6179bf079991bf3a20aade64cfe9935 --- fastboot/fastboot.cpp | 18 +++++++++++++++++- fastboot/fastboot.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 61c7204daacd..faee5e25dad0 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1794,6 +1794,7 @@ void FlashAllTool::Flash() { CancelSnapshotIfNeeded(); tasks_ = CollectTasks(); + for (auto& task : tasks_) { task->Run(); } @@ -1808,7 +1809,18 @@ std::vector> FlashAllTool::CollectTasks() { } else { tasks = CollectTasksFromImageList(); } - + if (fp_->exclude_dynamic_partitions) { + auto is_non_static_flash_task = [](const auto& task) -> bool { + if (auto flash_task = task->AsFlashTask()) { + if (!should_flash_in_userspace(flash_task->GetPartitionAndSlot())) { + return false; + } + } + return true; + }; + tasks.erase(std::remove_if(tasks.begin(), tasks.end(), is_non_static_flash_task), + tasks.end()); + } return tasks; } @@ -2213,6 +2225,7 @@ int FastBootTool::Main(int argc, char* argv[]) { {"disable-verification", no_argument, 0, 0}, {"disable-verity", no_argument, 0, 0}, {"disable-super-optimization", no_argument, 0, 0}, + {"exclude-dynamic-partitions", no_argument, 0, 0}, {"disable-fastboot-info", no_argument, 0, 0}, {"force", no_argument, 0, 0}, {"fs-options", required_argument, 0, 0}, @@ -2254,6 +2267,9 @@ int FastBootTool::Main(int argc, char* argv[]) { g_disable_verity = true; } else if (name == "disable-super-optimization") { fp->should_optimize_flash_super = false; + } else if (name == "exclude-dynamic-partitions") { + fp->exclude_dynamic_partitions = true; + fp->should_optimize_flash_super = false; } else if (name == "disable-fastboot-info") { fp->should_use_fastboot_info = false; } else if (name == "force") { diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index f6ffb641fc69..3fb00e0fda5d 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -98,6 +98,7 @@ struct FlashingPlan { bool force_flash = false; bool should_optimize_flash_super = true; bool should_use_fastboot_info = true; + bool exclude_dynamic_partitions = false; uint64_t sparse_limit = 0; std::string slot_override; From 2493d50328a99c725e7e690fcfd3efde88f86541 Mon Sep 17 00:00:00 2001 From: Lee George Thomas Date: Tue, 25 Jul 2023 15:07:17 -0700 Subject: [PATCH 0234/1487] Create /data/misc/bootanim folder in init.rc. This folder is used to host bootanim data files. Bug: 210757252 Test: /data/misc/bootanim is correctly created. Change-Id: I9c9949316d073ad7ebac503f097c5fee6c0b2a22 --- rootdir/init.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index d2499ef3816e..8f01d932b851 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -997,7 +997,7 @@ on post-fs-data perform_apex_config # Create directories for boot animation. - mkdir /data/bootanim 0755 system system encryption=DeleteIfNecessary + mkdir /data/misc/bootanim 0755 system system encryption=DeleteIfNecessary exec_start derive_sdk From 9292f74fc1b20275e29246a12ce4913599645cd9 Mon Sep 17 00:00:00 2001 From: Yunkai Lim Date: Wed, 26 Jul 2023 06:21:30 +0000 Subject: [PATCH 0235/1487] Revert "init.rc: stop calling 'fsverity_init --load-verified-keys'" Revert submission 2662658-fsverity-init-cleanup Reason for revert: Culprit for test breakage b/293232766 Reverted changes: /q/submissionid:2662658-fsverity-init-cleanup Change-Id: I77086f955a53eec274166b7395a88b7dc0e1ad53 --- rootdir/Android.bp | 5 ++++- rootdir/init.rc | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/rootdir/Android.bp b/rootdir/Android.bp index 65865a65b4ea..e98733ada721 100644 --- a/rootdir/Android.bp +++ b/rootdir/Android.bp @@ -20,7 +20,10 @@ prebuilt_etc { name: "init.rc", src: "init.rc", sub_dir: "init/hw", - required: ["platform-bootclasspath"], + required: [ + "fsverity_init", + "platform-bootclasspath", + ], } prebuilt_etc { diff --git a/rootdir/init.rc b/rootdir/init.rc index dec763ac1df9..d2499ef3816e 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -629,6 +629,9 @@ on late-fs # HALs required before storage encryption can get unlocked (FBE) class_start early_hal + # Load trusted keys from dm-verity protected partitions + exec -- /system/bin/fsverity_init --load-verified-keys + # Only enable the bootreceiver tracing instance for kernels 5.10 and above. on late-fs && property:ro.kernel.version=4.9 setprop bootreceiver.enable 0 From a895aac5e0b3f4b715c9062860b0242a64ef487e Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Wed, 26 Jul 2023 07:50:44 -0700 Subject: [PATCH 0236/1487] Add bug component to system/core Bug: 289414897 Test: N/A Change-Id: I9709b2483988f8d7a4204d5398cc559d167f14bf --- OWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/OWNERS b/OWNERS index 682a067b3a98..96b4f54ec0b5 100644 --- a/OWNERS +++ b/OWNERS @@ -1 +1,2 @@ +# Bug component: 128577 enh@google.com From aa6158b410ca65566bcd23d30bf32bc522d9d6dc Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Wed, 26 Jul 2023 22:12:44 +0000 Subject: [PATCH 0237/1487] libprocessgroup: UIDs in linux are unsigned We missed two incorrect specifiers in the previous commit with this same title. We use the %d format specificier for uid_t, which maps to __kernel_uid32_t, which is unsigned. [1] This is undefined behavior which can lead to paths with negative UIDs when erroneously large values are passed for uid: E libprocessgroup: No such cgroup attribute: /sys/fs/cgroup/uid_-89846/cgroup.freeze Fix it with %u. [1] https://cs.android.com/search?q=typedef.*__kernel_uid32_t&ss=android%2Fplatform%2Fsuperproject%2Fmain Change-Id: Ica04b03526bd2e156f026a2797fe9912b259cd9f --- libprocessgroup/processgroup.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index 06d386f363e7..450643912e09 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -206,11 +206,11 @@ bool SetUserProfiles(uid_t uid, const std::vector& profiles) { } static std::string ConvertUidToPath(const char* cgroup, uid_t uid) { - return StringPrintf("%s/uid_%d", cgroup, uid); + return StringPrintf("%s/uid_%u", cgroup, uid); } static std::string ConvertUidPidToPath(const char* cgroup, uid_t uid, int pid) { - return StringPrintf("%s/uid_%d/pid_%d", cgroup, uid, pid); + return StringPrintf("%s/uid_%u/pid_%d", cgroup, uid, pid); } static int RemoveProcessGroup(const char* cgroup, uid_t uid, int pid, unsigned int retries) { From 8fe4f073c210b012330863ba3beda11062d3a7ed Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Thu, 27 Jul 2023 10:16:05 -0700 Subject: [PATCH 0238/1487] Add bug component to cutils Bug: 289414897 Test: N/A Change-Id: Ic7122e52c3847beba3891b121b723d19bf2076de --- libcutils/OWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/libcutils/OWNERS b/libcutils/OWNERS index 7529cb920940..e1cbe4aaf975 100644 --- a/libcutils/OWNERS +++ b/libcutils/OWNERS @@ -1 +1,2 @@ +# Bug component: 128577 include platform/system/core:/janitors/OWNERS From 35078468722cdee94fe17e57fe5f300d3ee156f4 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Tue, 25 Jul 2023 14:50:18 -0700 Subject: [PATCH 0239/1487] libprocessgroup: fix reset of file_v2_name ProfileAttribute::Reset does not reset file_v2_name, fix that. Also provide ProfileAttribute::file_name() to consolidate the code. Bug: 292636609 Signed-off-by: Suren Baghdasaryan Change-Id: I5b33ca47b4fa5cabf582c8804bd13f72f6e58411 --- libprocessgroup/task_profiles.cpp | 22 +++++++++++++--------- libprocessgroup/task_profiles.h | 8 +++++--- libprocessgroup/task_profiles_test.cpp | 7 +++---- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 1276a72a6ad0..59b135013326 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -114,9 +114,16 @@ bool FdCacheHelper::IsAppDependentPath(const std::string& path) { IProfileAttribute::~IProfileAttribute() = default; -void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name) { +const std::string& ProfileAttribute::file_name() const { + if (controller()->version() == 2 && !file_v2_name_.empty()) return file_v2_name_; + return file_name_; +} + +void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) { controller_ = controller; file_name_ = file_name; + file_v2_name_ = file_v2_name; } bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { @@ -129,12 +136,11 @@ bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { return true; } - const std::string& file_name = - controller()->version() == 2 && !file_v2_name_.empty() ? file_v2_name_ : file_name_; if (subgroup.empty()) { - *path = StringPrintf("%s/%s", controller()->path(), file_name.c_str()); + *path = StringPrintf("%s/%s", controller()->path(), file_name().c_str()); } else { - *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(), file_name.c_str()); + *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(), + file_name().c_str()); } return true; } @@ -144,9 +150,7 @@ bool ProfileAttribute::GetPathForUID(uid_t uid, std::string* path) const { return true; } - const std::string& file_name = - controller()->version() == 2 && !file_v2_name_.empty() ? file_v2_name_ : file_name_; - *path = StringPrintf("%s/uid_%u/%s", controller()->path(), uid, file_name.c_str()); + *path = StringPrintf("%s/uid_%u/%s", controller()->path(), uid, file_name().c_str()); return true; } @@ -816,7 +820,7 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { attributes_[name] = std::make_unique(controller, file_attr, file_v2_attr); } else { - iter->second->Reset(controller, file_attr); + iter->second->Reset(controller, file_attr, file_v2_attr); } } else { LOG(WARNING) << "Controller " << controller_name << " is not found"; diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index a62c5b0a9e8c..ac8918e650fc 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -32,7 +32,8 @@ class IProfileAttribute { public: virtual ~IProfileAttribute() = 0; - virtual void Reset(const CgroupController& controller, const std::string& file_name) = 0; + virtual void Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) = 0; virtual const CgroupController* controller() const = 0; virtual const std::string& file_name() const = 0; virtual bool GetPathForTask(int tid, std::string* path) const = 0; @@ -50,8 +51,9 @@ class ProfileAttribute : public IProfileAttribute { ~ProfileAttribute() = default; const CgroupController* controller() const override { return &controller_; } - const std::string& file_name() const override { return file_name_; } - void Reset(const CgroupController& controller, const std::string& file_name) override; + const std::string& file_name() const override; + void Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) override; bool GetPathForTask(int tid, std::string* path) const override; bool GetPathForUID(uid_t uid, std::string* path) const override; diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp index eadbe7697b07..da74bb012f8f 100644 --- a/libprocessgroup/task_profiles_test.cpp +++ b/libprocessgroup/task_profiles_test.cpp @@ -102,7 +102,8 @@ class ProfileAttributeMock : public IProfileAttribute { public: ProfileAttributeMock(const std::string& file_name) : file_name_(file_name) {} ~ProfileAttributeMock() override = default; - void Reset(const CgroupController& controller, const std::string& file_name) override { + void Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) override { CHECK(false); } const CgroupController* controller() const override { @@ -125,9 +126,7 @@ class ProfileAttributeMock : public IProfileAttribute { return true; }; - bool GetPathForUID(uid_t, std::string*) const override { - return false; - } + bool GetPathForUID(uid_t, std::string*) const override { return false; } private: const std::string file_name_; From 3483798fd9045f93e9095e5b09ffe4f59054c535 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Tue, 25 Jul 2023 15:45:45 -0700 Subject: [PATCH 0240/1487] libprocessgroup: optimize SetAttributeAction::ExecuteForProcess performance Current implementation of SetAttributeAction::ExecuteForProcess reuses SetAttributeAction::ExecuteForTask while not utilizing available uid/pid information. This results in a call to GetPathForTask() which is an expensive function due to it reading and parsing /proc/$pid/cgroups. This can be avoided if we utilize available uid/pid info and the fact that cgroup v2 attributes share the cgroup v2 hierarchy as process groups, which use a known path template. Bug: 292636609 Change-Id: I02e3046bd85d0dfebc68ab444f1796bb54cc69c7 Signed-off-by: Suren Baghdasaryan --- libprocessgroup/task_profiles.cpp | 45 +++++++++++++++++++------- libprocessgroup/task_profiles.h | 4 +++ libprocessgroup/task_profiles_test.cpp | 3 ++ 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 59b135013326..f51b07671bf1 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -126,6 +126,16 @@ void ProfileAttribute::Reset(const CgroupController& controller, const std::stri file_v2_name_ = file_v2_name; } +bool ProfileAttribute::GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const { + if (controller()->version() == 2) { + // all cgroup v2 attributes use the same process group hierarchy + *path = StringPrintf("%s/uid_%u/pid_%d/%s", controller()->path(), uid, pid, + file_name().c_str()); + return true; + } + return GetPathForTask(pid, path); +} + bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { std::string subgroup; if (!controller()->GetTaskGroup(tid, &subgroup)) { @@ -209,18 +219,7 @@ bool SetTimerSlackAction::ExecuteForTask(int) const { #endif -bool SetAttributeAction::ExecuteForProcess(uid_t, pid_t pid) const { - return ExecuteForTask(pid); -} - -bool SetAttributeAction::ExecuteForTask(int tid) const { - std::string path; - - if (!attribute_->GetPathForTask(tid, &path)) { - LOG(ERROR) << "Failed to find cgroup for tid " << tid; - return false; - } - +bool SetAttributeAction::WriteValueToFile(const std::string& path) const { if (!WriteStringToFile(value_, path)) { if (access(path.c_str(), F_OK) < 0) { if (optional_) { @@ -240,6 +239,28 @@ bool SetAttributeAction::ExecuteForTask(int tid) const { return true; } +bool SetAttributeAction::ExecuteForProcess(uid_t uid, pid_t pid) const { + std::string path; + + if (!attribute_->GetPathForProcess(uid, pid, &path)) { + LOG(ERROR) << "Failed to find cgroup for uid " << uid << " pid " << pid; + return false; + } + + return WriteValueToFile(path); +} + +bool SetAttributeAction::ExecuteForTask(int tid) const { + std::string path; + + if (!attribute_->GetPathForTask(tid, &path)) { + LOG(ERROR) << "Failed to find cgroup for tid " << tid; + return false; + } + + return WriteValueToFile(path); +} + bool SetAttributeAction::ExecuteForUID(uid_t uid) const { std::string path; diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index ac8918e650fc..4663f64e2a7e 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -36,6 +36,7 @@ class IProfileAttribute { const std::string& file_v2_name) = 0; virtual const CgroupController* controller() const = 0; virtual const std::string& file_name() const = 0; + virtual bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const = 0; virtual bool GetPathForTask(int tid, std::string* path) const = 0; virtual bool GetPathForUID(uid_t uid, std::string* path) const = 0; }; @@ -55,6 +56,7 @@ class ProfileAttribute : public IProfileAttribute { void Reset(const CgroupController& controller, const std::string& file_name, const std::string& file_v2_name) override; + bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const override; bool GetPathForTask(int tid, std::string* path) const override; bool GetPathForUID(uid_t uid, std::string* path) const override; @@ -133,6 +135,8 @@ class SetAttributeAction : public ProfileAction { const IProfileAttribute* attribute_; std::string value_; bool optional_; + + bool WriteValueToFile(const std::string& path) const; }; // Set cgroup profile element diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp index da74bb012f8f..99d819a7cc4c 100644 --- a/libprocessgroup/task_profiles_test.cpp +++ b/libprocessgroup/task_profiles_test.cpp @@ -111,6 +111,9 @@ class ProfileAttributeMock : public IProfileAttribute { return {}; } const std::string& file_name() const override { return file_name_; } + bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const override { + return GetPathForTask(pid, path); + } bool GetPathForTask(int tid, std::string* path) const override { #ifdef __ANDROID__ CHECK(CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, path)); From 2ffbeaef3a926b0b5fd873136588deb3ec61ef96 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Tue, 25 Jul 2023 14:50:18 -0700 Subject: [PATCH 0241/1487] libprocessgroup: fix reset of file_v2_name ProfileAttribute::Reset does not reset file_v2_name, fix that. Also provide ProfileAttribute::file_name() to consolidate the code. Bug: 292636609 Signed-off-by: Suren Baghdasaryan Change-Id: I5b33ca47b4fa5cabf582c8804bd13f72f6e58411 Merged-In: I5b33ca47b4fa5cabf582c8804bd13f72f6e58411 --- libprocessgroup/task_profiles.cpp | 22 +++++++++++++--------- libprocessgroup/task_profiles.h | 8 +++++--- libprocessgroup/task_profiles_test.cpp | 7 +++---- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 44dba2a16694..59b135013326 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -114,9 +114,16 @@ bool FdCacheHelper::IsAppDependentPath(const std::string& path) { IProfileAttribute::~IProfileAttribute() = default; -void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name) { +const std::string& ProfileAttribute::file_name() const { + if (controller()->version() == 2 && !file_v2_name_.empty()) return file_v2_name_; + return file_name_; +} + +void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) { controller_ = controller; file_name_ = file_name; + file_v2_name_ = file_v2_name; } bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { @@ -129,12 +136,11 @@ bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { return true; } - const std::string& file_name = - controller()->version() == 2 && !file_v2_name_.empty() ? file_v2_name_ : file_name_; if (subgroup.empty()) { - *path = StringPrintf("%s/%s", controller()->path(), file_name.c_str()); + *path = StringPrintf("%s/%s", controller()->path(), file_name().c_str()); } else { - *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(), file_name.c_str()); + *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(), + file_name().c_str()); } return true; } @@ -144,9 +150,7 @@ bool ProfileAttribute::GetPathForUID(uid_t uid, std::string* path) const { 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()); + *path = StringPrintf("%s/uid_%u/%s", controller()->path(), uid, file_name().c_str()); return true; } @@ -816,7 +820,7 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { attributes_[name] = std::make_unique(controller, file_attr, file_v2_attr); } else { - iter->second->Reset(controller, file_attr); + iter->second->Reset(controller, file_attr, file_v2_attr); } } else { LOG(WARNING) << "Controller " << controller_name << " is not found"; diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index a62c5b0a9e8c..ac8918e650fc 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -32,7 +32,8 @@ class IProfileAttribute { public: virtual ~IProfileAttribute() = 0; - virtual void Reset(const CgroupController& controller, const std::string& file_name) = 0; + virtual void Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) = 0; virtual const CgroupController* controller() const = 0; virtual const std::string& file_name() const = 0; virtual bool GetPathForTask(int tid, std::string* path) const = 0; @@ -50,8 +51,9 @@ class ProfileAttribute : public IProfileAttribute { ~ProfileAttribute() = default; const CgroupController* controller() const override { return &controller_; } - const std::string& file_name() const override { return file_name_; } - void Reset(const CgroupController& controller, const std::string& file_name) override; + const std::string& file_name() const override; + void Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) override; bool GetPathForTask(int tid, std::string* path) const override; bool GetPathForUID(uid_t uid, std::string* path) const override; diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp index eadbe7697b07..da74bb012f8f 100644 --- a/libprocessgroup/task_profiles_test.cpp +++ b/libprocessgroup/task_profiles_test.cpp @@ -102,7 +102,8 @@ class ProfileAttributeMock : public IProfileAttribute { public: ProfileAttributeMock(const std::string& file_name) : file_name_(file_name) {} ~ProfileAttributeMock() override = default; - void Reset(const CgroupController& controller, const std::string& file_name) override { + void Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) override { CHECK(false); } const CgroupController* controller() const override { @@ -125,9 +126,7 @@ class ProfileAttributeMock : public IProfileAttribute { return true; }; - bool GetPathForUID(uid_t, std::string*) const override { - return false; - } + bool GetPathForUID(uid_t, std::string*) const override { return false; } private: const std::string file_name_; From 961c01ce23bb886583ca8cac1640806346c09a7f Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Tue, 25 Jul 2023 15:45:45 -0700 Subject: [PATCH 0242/1487] libprocessgroup: optimize SetAttributeAction::ExecuteForProcess performance Current implementation of SetAttributeAction::ExecuteForProcess reuses SetAttributeAction::ExecuteForTask while not utilizing available uid/pid information. This results in a call to GetPathForTask() which is an expensive function due to it reading and parsing /proc/$pid/cgroups. This can be avoided if we utilize available uid/pid info and the fact that cgroup v2 attributes share the cgroup v2 hierarchy as process groups, which use a known path template. Bug: 292636609 Change-Id: I02e3046bd85d0dfebc68ab444f1796bb54cc69c7 Merged-In: I02e3046bd85d0dfebc68ab444f1796bb54cc69c7 Signed-off-by: Suren Baghdasaryan --- libprocessgroup/task_profiles.cpp | 45 +++++++++++++++++++------- libprocessgroup/task_profiles.h | 4 +++ libprocessgroup/task_profiles_test.cpp | 3 ++ 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 59b135013326..f51b07671bf1 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -126,6 +126,16 @@ void ProfileAttribute::Reset(const CgroupController& controller, const std::stri file_v2_name_ = file_v2_name; } +bool ProfileAttribute::GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const { + if (controller()->version() == 2) { + // all cgroup v2 attributes use the same process group hierarchy + *path = StringPrintf("%s/uid_%u/pid_%d/%s", controller()->path(), uid, pid, + file_name().c_str()); + return true; + } + return GetPathForTask(pid, path); +} + bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { std::string subgroup; if (!controller()->GetTaskGroup(tid, &subgroup)) { @@ -209,18 +219,7 @@ bool SetTimerSlackAction::ExecuteForTask(int) const { #endif -bool SetAttributeAction::ExecuteForProcess(uid_t, pid_t pid) const { - return ExecuteForTask(pid); -} - -bool SetAttributeAction::ExecuteForTask(int tid) const { - std::string path; - - if (!attribute_->GetPathForTask(tid, &path)) { - LOG(ERROR) << "Failed to find cgroup for tid " << tid; - return false; - } - +bool SetAttributeAction::WriteValueToFile(const std::string& path) const { if (!WriteStringToFile(value_, path)) { if (access(path.c_str(), F_OK) < 0) { if (optional_) { @@ -240,6 +239,28 @@ bool SetAttributeAction::ExecuteForTask(int tid) const { return true; } +bool SetAttributeAction::ExecuteForProcess(uid_t uid, pid_t pid) const { + std::string path; + + if (!attribute_->GetPathForProcess(uid, pid, &path)) { + LOG(ERROR) << "Failed to find cgroup for uid " << uid << " pid " << pid; + return false; + } + + return WriteValueToFile(path); +} + +bool SetAttributeAction::ExecuteForTask(int tid) const { + std::string path; + + if (!attribute_->GetPathForTask(tid, &path)) { + LOG(ERROR) << "Failed to find cgroup for tid " << tid; + return false; + } + + return WriteValueToFile(path); +} + bool SetAttributeAction::ExecuteForUID(uid_t uid) const { std::string path; diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index ac8918e650fc..4663f64e2a7e 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -36,6 +36,7 @@ class IProfileAttribute { const std::string& file_v2_name) = 0; virtual const CgroupController* controller() const = 0; virtual const std::string& file_name() const = 0; + virtual bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const = 0; virtual bool GetPathForTask(int tid, std::string* path) const = 0; virtual bool GetPathForUID(uid_t uid, std::string* path) const = 0; }; @@ -55,6 +56,7 @@ class ProfileAttribute : public IProfileAttribute { void Reset(const CgroupController& controller, const std::string& file_name, const std::string& file_v2_name) override; + bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const override; bool GetPathForTask(int tid, std::string* path) const override; bool GetPathForUID(uid_t uid, std::string* path) const override; @@ -133,6 +135,8 @@ class SetAttributeAction : public ProfileAction { const IProfileAttribute* attribute_; std::string value_; bool optional_; + + bool WriteValueToFile(const std::string& path) const; }; // Set cgroup profile element diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp index da74bb012f8f..99d819a7cc4c 100644 --- a/libprocessgroup/task_profiles_test.cpp +++ b/libprocessgroup/task_profiles_test.cpp @@ -111,6 +111,9 @@ class ProfileAttributeMock : public IProfileAttribute { return {}; } const std::string& file_name() const override { return file_name_; } + bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const override { + return GetPathForTask(pid, path); + } bool GetPathForTask(int tid, std::string* path) const override { #ifdef __ANDROID__ CHECK(CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, path)); From cac69b6cb83c2322942876db4029ab070add6f35 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Thu, 27 Jul 2023 22:15:46 +0000 Subject: [PATCH 0243/1487] trusty: keymint: Statically link Rust deps Vendor libraries can be linked dynamically now, but until more Rust components are using it, static is more efficient. Bug: 292062611 Test: TH Change-Id: I3708f5fac1ace797b6233811adf3ec71218d5738 --- trusty/keymint/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/trusty/keymint/Android.bp b/trusty/keymint/Android.bp index c19ebbd2663f..19dcc98753f4 100644 --- a/trusty/keymint/Android.bp +++ b/trusty/keymint/Android.bp @@ -35,6 +35,7 @@ rust_binary { "liblibc", "liblog_rust", ], + prefer_rlib: true, required: [ "android.hardware.hardware_keystore.xml", ], From 5ffd88f26f0bb8fe7bfa0058f70c7e40bf7e8f9f Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Fri, 28 Jul 2023 17:28:27 +0900 Subject: [PATCH 0244/1487] init: move `MarkServicesUpdate` later MarkServicesUpdate() starts delayed services which are mostly for APEXes. (e.g. start a service from APEX). But before "DefaultNamespaceReady", services are started in "bootstrap" mount namespace, which makes services from non-bootstrap APEXes fail to start. This is a quick fix for the problem before coming up with better solution in the future. Bug: 293535323 Test: add 'start adbd' before 'perform_apex_config' in init.rc adbd starts successfully. Change-Id: I846689f7c38cdca83c1f7faec0106b8174527e09 --- init/builtins.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/init/builtins.cpp b/init/builtins.cpp index 2176233aab96..fa5e36d52220 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -1297,7 +1297,6 @@ static Result do_perform_apex_config(const BuiltinArguments& args) { return create_dirs.error(); } auto parse_configs = ParseApexConfigs(/*apex_name=*/""); - ServiceList::GetInstance().MarkServicesUpdate(); if (!parse_configs.ok()) { return parse_configs.error(); } @@ -1307,6 +1306,8 @@ static Result do_perform_apex_config(const BuiltinArguments& args) { return update_linker_config.error(); } + // Now start delayed services + ServiceList::GetInstance().MarkServicesUpdate(); return {}; } From 63ec4c6180f98457bbb309d05514f2d76b91a09c Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Thu, 20 Jul 2023 10:40:00 -0700 Subject: [PATCH 0245/1487] libsnapshot: Verify the ordering of COW operations. Sequence op should contain all ordered ops followed by Replace and Zero ops. There shouldn't be any non-ordered ops embedded between ordered ops in the sequence ordering. Bug: 290159346 Test: inspect_cow , OTA Change-Id: Ia840340b0e4be07525f216838043bf0265f690c3 Signed-off-by: Akilesh Kailash --- .../libsnapshot_cow/cow_reader.cpp | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp index 489669ac0eae..f37aed1afe63 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp @@ -310,9 +310,34 @@ bool CowReader::PrepMergeOps() { bool CowReader::VerifyMergeOps() { auto itr = GetMergeOpIter(true); std::unordered_map overwritten_blocks; + bool non_ordered_op_found = false; + while (!itr->AtEnd()) { const auto& op = itr->Get(); uint64_t offset; + + // Op should not be a metadata + if (IsMetadataOp(*op)) { + LOG(ERROR) << "Metadata op: " << op << " found during merge sequence"; + return false; + } + + // Sequence ops should contain all the ordered ops followed + // by Replace and Zero ops. If we find the first op which + // is not ordered, that means all ordered ops processing + // has been completed. + if (!IsOrderedOp(*op)) { + non_ordered_op_found = true; + } + + // Since, all ordered ops processing has been completed, + // check that the subsequent ops are not ordered. + if (non_ordered_op_found && IsOrderedOp(*op)) { + LOG(ERROR) << "Invalid sequence - non-ordered and ordered ops" + << " cannot be mixed during sequence generation"; + return false; + } + if (!GetSourceOffset(op, &offset)) { itr->Next(); continue; From 750fe6a37b2ff0fcb7f54721cd92f7e2686bb807 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Fri, 28 Jul 2023 10:58:56 -0700 Subject: [PATCH 0246/1487] Adding include to functional adding include to functional since we use it in this file. Some users are reporting build issues due to missing this include Test: m fastboot Change-Id: I9ba11bdaf7dcedf5f9ebfb6fa50013be50738f48 --- fastboot/fastboot.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index f6ffb641fc69..dc57149761e9 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -27,6 +27,7 @@ */ #pragma once +#include #include #include "fastboot_driver.h" #include "fastboot_driver_interface.h" From 201801ce8eb5e001de9e669e55ee507e18bcae66 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Thu, 20 Jul 2023 17:25:47 +0900 Subject: [PATCH 0247/1487] Use /bootstrap-apex for bootstrap APEXes This new directory is bind-mounted to /apex in the bootstrap mount namespace so that apexd-bootstrap mounts bootstrap APEXes there via /apex. The directory is detached from /apex in the default mount namespace but still visible in case bootstrap APEXes are needed. However, there are (mostly, virtual) devices which don't need two mount namespaces. Those devices don't need to make /bootstrap-apex directory at all. Bug: 290148078 Test: atest VendorApexHostTestCases Test: atest MicrodroidTests Change-Id: I541cec71d9970b14971d46e01e4808b23590dbed --- init/builtins.cpp | 50 ++++++++++++++++++++++++++++++++++++++++ init/init.cpp | 6 +++++ init/mount_namespace.cpp | 39 +++++++++++++++++++++++-------- init/mount_namespace.h | 3 +++ init/selinux.cpp | 2 +- rootdir/Android.mk | 2 +- 6 files changed, 91 insertions(+), 11 deletions(-) diff --git a/init/builtins.cpp b/init/builtins.cpp index 2176233aab96..e4f0bd040ed6 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -1262,6 +1262,51 @@ static Result MountLinkerConfigForDefaultNamespace() { return {}; } + +static Result MountApexRootForDefaultNamespace() { + auto mount_namespace_id = GetCurrentMountNamespace(); + if (!mount_namespace_id.ok()) { + return mount_namespace_id.error(); + } + // There's nothing to do if it's still in the bootstrap mount namespace. + // This happens when we don't need to update APEXes (e.g. Microdroid) + // where bootstrap mount namespace == default mount namespace. + if (mount_namespace_id.value() == NS_BOOTSTRAP) { + return {}; + } + + // Now, we're in the "default" mount namespace and need a fresh /apex for + // the default mount namespace. + // + // At this point, there are two mounts at the same mount point: /apex + // - to tmpfs (private) + // - to /bootstrap-apex (shared) + // + // We need unmount the second mount so that /apex in the default mount + // namespace becomes RW/empty and "private" (we don't want mount events to + // propagate to the bootstrap mount namespace). + // + // Likewise, we don't want the unmount event itself to propagate to the + // bootstrap mount namespace. Otherwise, /apex in the bootstrap mount + // namespace would become empty due to the unmount. + // + // Hence, before unmounting, we make /apex (the second one) "private" first. + // so that the unmouting below doesn't affect to the bootstrap mount namespace. + if (mount(nullptr, "/apex", nullptr, MS_PRIVATE | MS_REC, nullptr) == -1) { + return ErrnoError() << "Failed to remount /apex as private"; + } + + // Now we can unmount /apex (bind-mount to /bootstrap-apex). This only affects + // in the default mount namespace and /apex is now seen as tmpfs mount. + // Note that /apex in the bootstrap mount namespace is still a bind-mount to + // /bootstrap-apex and holds the APEX mounts. + if (umount2("/apex", MNT_DETACH) == -1) { + return ErrnoError() << "Failed to umount /apex"; + } + + return {}; +} + static Result do_update_linker_config(const BuiltinArguments&) { return GenerateLinkerConfiguration(); } @@ -1314,6 +1359,11 @@ static Result do_enter_default_mount_ns(const BuiltinArguments& args) { if (auto result = SwitchToMountNamespaceIfNeeded(NS_DEFAULT); !result.ok()) { return result.error(); } + + if (auto result = MountApexRootForDefaultNamespace(); !result.ok()) { + return result.error(); + } + if (auto result = MountLinkerConfigForDefaultNamespace(); !result.ok()) { return result.error(); } diff --git a/init/init.cpp b/init/init.cpp index da63fdc3bda5..4bb8eecb981a 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -832,6 +832,12 @@ static void MountExtraFilesystems() { CHECKCALL(mount("tmpfs", "/apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0")); + if (NeedsTwoMountNamespaces()) { + // /bootstrap-apex is used to mount "bootstrap" APEXes. + CHECKCALL(mount("tmpfs", "/bootstrap-apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, + "mode=0755,uid=0,gid=0")); + } + // /linkerconfig is used to keep generated linker configuration CHECKCALL(mount("tmpfs", "/linkerconfig", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0")); diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp index 5b53d5092227..e069a5d3e3db 100644 --- a/init/mount_namespace.cpp +++ b/init/mount_namespace.cpp @@ -66,15 +66,6 @@ static std::string GetMountNamespaceId() { return ret; } -// In case we have two sets of APEXes (non-updatable, updatable), we need two separate mount -// namespaces. -static bool NeedsTwoMountNamespaces() { - if (IsRecoveryMode()) return false; - // In microdroid, there's only one set of APEXes in built-in directories include block devices. - if (IsMicrodroid()) return false; - return true; -} - static android::base::unique_fd bootstrap_ns_fd; static android::base::unique_fd default_ns_fd; @@ -83,6 +74,15 @@ static std::string default_ns_id; } // namespace +// In case we have two sets of APEXes (non-updatable, updatable), we need two separate mount +// namespaces. +bool NeedsTwoMountNamespaces() { + if (IsRecoveryMode()) return false; + // In microdroid, there's only one set of APEXes in built-in directories include block devices. + if (IsMicrodroid()) return false; + return true; +} + bool SetupMountNamespaces() { // Set the propagation type of / as shared so that any mounting event (e.g. // /data) is by default visible to all processes. When private mounting is @@ -96,6 +96,27 @@ bool SetupMountNamespaces() { // the bootstrap namespace get APEXes from the read-only partition. if (!(ChangeMount("/apex", MS_PRIVATE))) return false; + // However, some components (e.g. servicemanager) need to access bootstrap + // APEXes from the default mount namespace. To achieve that, we bind-mount + // /apex with /bootstrap-apex (not private) in the bootstrap mount namespace. + // Bootstrap APEXes are mounted in /apex and also visible in /bootstrap-apex. + // In the default mount namespace, we detach /bootstrap-apex from /apex and + // bootstrap APEXes are still be visible in /bootstrap-apex. + // + // The end result will look like: + // in the bootstrap mount namespace: + // /apex (== /bootstrap-apex) + // {bootstrap APEXes from the read-only partition} + // + // in the default mount namespace: + // /bootstrap-apex + // {bootstrap APEXes from the read-only partition} + // /apex + // {APEXes, can be from /data partition} + if (NeedsTwoMountNamespaces()) { + if (!(BindMount("/bootstrap-apex", "/apex"))) return false; + } + // /linkerconfig is a private mountpoint to give a different linker configuration // based on the mount namespace. Subdirectory will be bind-mounted based on current mount // namespace diff --git a/init/mount_namespace.h b/init/mount_namespace.h index 5e3dab241290..43c5476a6ab8 100644 --- a/init/mount_namespace.h +++ b/init/mount_namespace.h @@ -24,9 +24,12 @@ namespace init { enum MountNamespace { NS_BOOTSTRAP, NS_DEFAULT }; bool SetupMountNamespaces(); + base::Result SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespace); base::Result GetCurrentMountNamespace(); +bool NeedsTwoMountNamespaces(); + } // namespace init } // namespace android diff --git a/init/selinux.cpp b/init/selinux.cpp index 51093d898e8b..8532c44c1c70 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -766,7 +766,7 @@ void SelinuxRestoreContext() { selinux_android_restorecon("/dev/device-mapper", 0); selinux_android_restorecon("/apex", 0); - + selinux_android_restorecon("/bootstrap-apex", 0); selinux_android_restorecon("/linkerconfig", 0); // adb remount, snapshot-based updates, and DSUs all create files during diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 3362872c070d..52187536f3fe 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -91,7 +91,7 @@ endif # # create some directories (some are mount points) and symlinks LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \ - dev proc sys system data data_mirror odm oem acct config storage mnt apex debug_ramdisk \ + dev proc sys system data data_mirror odm oem acct config storage mnt apex bootstrap-apex debug_ramdisk \ linkerconfig second_stage_resources postinstall $(BOARD_ROOT_EXTRA_FOLDERS)); \ ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \ ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \ From 48d6e0452e1564f3a2b49e327e9f750fc50ed3d8 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Mon, 31 Jul 2023 14:24:01 -0700 Subject: [PATCH 0248/1487] Make libdebuggerd ramdisk available. Test: Builds and debuggerd unit tests pass. Change-Id: I2a5bd96e349f81ae0bec8dbffc49646c1f58bfea --- debuggerd/Android.bp | 17 ++++++++++++++--- debuggerd/proto/Android.bp | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index d20de6bbf724..5393e25e5098 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -188,6 +188,7 @@ cc_library { cc_library_static { name: "libdebuggerd", defaults: ["debuggerd_defaults"], + ramdisk_available: true, recovery_available: true, vendor_ramdisk_available: true, @@ -221,9 +222,6 @@ cc_library_static { "libbase", "libcutils", ], - runtime_libs: [ - "libdexfile", // libdexfile_support dependency - ], whole_static_libs: [ "libasync_safe", @@ -250,6 +248,19 @@ cc_library_static { "libdexfile", ], }, + ramdisk: { + exclude_static_libs: [ + "libdexfile_support", + ], + exclude_runtime_libs: [ + "libdexfile", + ], + }, + android: { + runtime_libs: [ + "libdexfile", // libdexfile_support dependency + ], + }, }, product_variables: { diff --git a/debuggerd/proto/Android.bp b/debuggerd/proto/Android.bp index 73cf5737d12e..804f8055ba60 100644 --- a/debuggerd/proto/Android.bp +++ b/debuggerd/proto/Android.bp @@ -35,6 +35,7 @@ cc_library_static { "com.android.runtime", ], + ramdisk_available: true, recovery_available: true, vendor_ramdisk_available: true, } From 72254810d9d63f8267d32d251456a78cd4891698 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Tue, 25 Jul 2023 14:50:18 -0700 Subject: [PATCH 0249/1487] libprocessgroup: fix reset of file_v2_name ProfileAttribute::Reset does not reset file_v2_name, fix that. Also provide ProfileAttribute::file_name() to consolidate the code. Bug: 292636609 Signed-off-by: Suren Baghdasaryan Change-Id: I5b33ca47b4fa5cabf582c8804bd13f72f6e58411 Merged-In: I5b33ca47b4fa5cabf582c8804bd13f72f6e58411 (cherry picked from commit 2ffbeaef3a926b0b5fd873136588deb3ec61ef96) --- libprocessgroup/task_profiles.cpp | 22 +++++++++++++--------- libprocessgroup/task_profiles.h | 8 +++++--- libprocessgroup/task_profiles_test.cpp | 7 +++---- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 44dba2a16694..59b135013326 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -114,9 +114,16 @@ bool FdCacheHelper::IsAppDependentPath(const std::string& path) { IProfileAttribute::~IProfileAttribute() = default; -void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name) { +const std::string& ProfileAttribute::file_name() const { + if (controller()->version() == 2 && !file_v2_name_.empty()) return file_v2_name_; + return file_name_; +} + +void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) { controller_ = controller; file_name_ = file_name; + file_v2_name_ = file_v2_name; } bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { @@ -129,12 +136,11 @@ bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { return true; } - const std::string& file_name = - controller()->version() == 2 && !file_v2_name_.empty() ? file_v2_name_ : file_name_; if (subgroup.empty()) { - *path = StringPrintf("%s/%s", controller()->path(), file_name.c_str()); + *path = StringPrintf("%s/%s", controller()->path(), file_name().c_str()); } else { - *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(), file_name.c_str()); + *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(), + file_name().c_str()); } return true; } @@ -144,9 +150,7 @@ bool ProfileAttribute::GetPathForUID(uid_t uid, std::string* path) const { 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()); + *path = StringPrintf("%s/uid_%u/%s", controller()->path(), uid, file_name().c_str()); return true; } @@ -816,7 +820,7 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { attributes_[name] = std::make_unique(controller, file_attr, file_v2_attr); } else { - iter->second->Reset(controller, file_attr); + iter->second->Reset(controller, file_attr, file_v2_attr); } } else { LOG(WARNING) << "Controller " << controller_name << " is not found"; diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index a62c5b0a9e8c..ac8918e650fc 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -32,7 +32,8 @@ class IProfileAttribute { public: virtual ~IProfileAttribute() = 0; - virtual void Reset(const CgroupController& controller, const std::string& file_name) = 0; + virtual void Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) = 0; virtual const CgroupController* controller() const = 0; virtual const std::string& file_name() const = 0; virtual bool GetPathForTask(int tid, std::string* path) const = 0; @@ -50,8 +51,9 @@ class ProfileAttribute : public IProfileAttribute { ~ProfileAttribute() = default; const CgroupController* controller() const override { return &controller_; } - const std::string& file_name() const override { return file_name_; } - void Reset(const CgroupController& controller, const std::string& file_name) override; + const std::string& file_name() const override; + void Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) override; bool GetPathForTask(int tid, std::string* path) const override; bool GetPathForUID(uid_t uid, std::string* path) const override; diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp index eadbe7697b07..da74bb012f8f 100644 --- a/libprocessgroup/task_profiles_test.cpp +++ b/libprocessgroup/task_profiles_test.cpp @@ -102,7 +102,8 @@ class ProfileAttributeMock : public IProfileAttribute { public: ProfileAttributeMock(const std::string& file_name) : file_name_(file_name) {} ~ProfileAttributeMock() override = default; - void Reset(const CgroupController& controller, const std::string& file_name) override { + void Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) override { CHECK(false); } const CgroupController* controller() const override { @@ -125,9 +126,7 @@ class ProfileAttributeMock : public IProfileAttribute { return true; }; - bool GetPathForUID(uid_t, std::string*) const override { - return false; - } + bool GetPathForUID(uid_t, std::string*) const override { return false; } private: const std::string file_name_; From 1e81ee13638c5ca03157db674009d4cf7c2a1263 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Tue, 25 Jul 2023 15:45:45 -0700 Subject: [PATCH 0250/1487] libprocessgroup: optimize SetAttributeAction::ExecuteForProcess performance Current implementation of SetAttributeAction::ExecuteForProcess reuses SetAttributeAction::ExecuteForTask while not utilizing available uid/pid information. This results in a call to GetPathForTask() which is an expensive function due to it reading and parsing /proc/$pid/cgroups. This can be avoided if we utilize available uid/pid info and the fact that cgroup v2 attributes share the cgroup v2 hierarchy as process groups, which use a known path template. Bug: 292636609 Change-Id: I02e3046bd85d0dfebc68ab444f1796bb54cc69c7 Merged-In: I02e3046bd85d0dfebc68ab444f1796bb54cc69c7 Signed-off-by: Suren Baghdasaryan (cherry picked from commit 961c01ce23bb886583ca8cac1640806346c09a7f) --- libprocessgroup/task_profiles.cpp | 45 +++++++++++++++++++------- libprocessgroup/task_profiles.h | 4 +++ libprocessgroup/task_profiles_test.cpp | 3 ++ 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 59b135013326..f51b07671bf1 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -126,6 +126,16 @@ void ProfileAttribute::Reset(const CgroupController& controller, const std::stri file_v2_name_ = file_v2_name; } +bool ProfileAttribute::GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const { + if (controller()->version() == 2) { + // all cgroup v2 attributes use the same process group hierarchy + *path = StringPrintf("%s/uid_%u/pid_%d/%s", controller()->path(), uid, pid, + file_name().c_str()); + return true; + } + return GetPathForTask(pid, path); +} + bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { std::string subgroup; if (!controller()->GetTaskGroup(tid, &subgroup)) { @@ -209,18 +219,7 @@ bool SetTimerSlackAction::ExecuteForTask(int) const { #endif -bool SetAttributeAction::ExecuteForProcess(uid_t, pid_t pid) const { - return ExecuteForTask(pid); -} - -bool SetAttributeAction::ExecuteForTask(int tid) const { - std::string path; - - if (!attribute_->GetPathForTask(tid, &path)) { - LOG(ERROR) << "Failed to find cgroup for tid " << tid; - return false; - } - +bool SetAttributeAction::WriteValueToFile(const std::string& path) const { if (!WriteStringToFile(value_, path)) { if (access(path.c_str(), F_OK) < 0) { if (optional_) { @@ -240,6 +239,28 @@ bool SetAttributeAction::ExecuteForTask(int tid) const { return true; } +bool SetAttributeAction::ExecuteForProcess(uid_t uid, pid_t pid) const { + std::string path; + + if (!attribute_->GetPathForProcess(uid, pid, &path)) { + LOG(ERROR) << "Failed to find cgroup for uid " << uid << " pid " << pid; + return false; + } + + return WriteValueToFile(path); +} + +bool SetAttributeAction::ExecuteForTask(int tid) const { + std::string path; + + if (!attribute_->GetPathForTask(tid, &path)) { + LOG(ERROR) << "Failed to find cgroup for tid " << tid; + return false; + } + + return WriteValueToFile(path); +} + bool SetAttributeAction::ExecuteForUID(uid_t uid) const { std::string path; diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index ac8918e650fc..4663f64e2a7e 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -36,6 +36,7 @@ class IProfileAttribute { const std::string& file_v2_name) = 0; virtual const CgroupController* controller() const = 0; virtual const std::string& file_name() const = 0; + virtual bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const = 0; virtual bool GetPathForTask(int tid, std::string* path) const = 0; virtual bool GetPathForUID(uid_t uid, std::string* path) const = 0; }; @@ -55,6 +56,7 @@ class ProfileAttribute : public IProfileAttribute { void Reset(const CgroupController& controller, const std::string& file_name, const std::string& file_v2_name) override; + bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const override; bool GetPathForTask(int tid, std::string* path) const override; bool GetPathForUID(uid_t uid, std::string* path) const override; @@ -133,6 +135,8 @@ class SetAttributeAction : public ProfileAction { const IProfileAttribute* attribute_; std::string value_; bool optional_; + + bool WriteValueToFile(const std::string& path) const; }; // Set cgroup profile element diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp index da74bb012f8f..99d819a7cc4c 100644 --- a/libprocessgroup/task_profiles_test.cpp +++ b/libprocessgroup/task_profiles_test.cpp @@ -111,6 +111,9 @@ class ProfileAttributeMock : public IProfileAttribute { return {}; } const std::string& file_name() const override { return file_name_; } + bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const override { + return GetPathForTask(pid, path); + } bool GetPathForTask(int tid, std::string* path) const override { #ifdef __ANDROID__ CHECK(CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, path)); From 7b5c38f8eb7fc83006e1cc7366397a2441c88604 Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Sat, 29 Jul 2023 17:46:32 +0800 Subject: [PATCH 0251/1487] libfstab: Unexport InRecovery() It was accidentally moved to the public header when I was previously refactoring the code. It hasn't caused any harm yet, but we probably don't want to export this, too. Bug: 293695109 Test: build Change-Id: Id81c802cc6cc697c5a4204638aa467966bea1562 --- fs_mgr/fs_mgr_priv.h | 3 +++ fs_mgr/include_fstab/fstab/fstab.h | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index c3b18c85c78f..678dd69cb3d7 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -109,6 +109,9 @@ OverlayfsValidResult fs_mgr_overlayfs_valid(); namespace android { namespace fs_mgr { + bool UnmapDevice(const std::string& name); +bool InRecovery(); + } // namespace fs_mgr } // namespace android diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h index 80b45ba93dc6..9cb1546c5aaf 100644 --- a/fs_mgr/include_fstab/fstab/fstab.h +++ b/fs_mgr/include_fstab/fstab/fstab.h @@ -131,7 +131,5 @@ std::set GetBootDevices(); // expected name. std::string GetVerityDeviceName(const FstabEntry& entry); -bool InRecovery(); - } // namespace fs_mgr } // namespace android From d838dde6aa27bc137855313798988d70f4305adf Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Sat, 22 Jul 2023 01:41:10 +0800 Subject: [PATCH 0252/1487] fs_mgr: Refactor mandatory overlayfs kernel patch checks The check result can just return the exact mount flags to use, this reduces code duplication at the caller's side. Bug: 293695109 Test: adb-remount-test Change-Id: I9b5c918968f2494c0c1be3cb8d8e6b527a9c4eb2 --- fs_mgr/fs_mgr.cpp | 45 ++++++++++++++++--------------- fs_mgr/fs_mgr_overlayfs_mount.cpp | 22 ++------------- fs_mgr/fs_mgr_priv.h | 14 +++++----- fs_mgr/fs_mgr_vendor_overlay.cpp | 8 +++--- 4 files changed, 35 insertions(+), 54 deletions(-) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index e568a9bd6b7d..d55f8d3bfd59 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -2227,8 +2227,8 @@ bool fs_mgr_create_canonical_mount_point(const std::string& mount_point) { } bool fs_mgr_mount_overlayfs_fstab_entry(const FstabEntry& entry) { - auto overlayfs_valid_result = fs_mgr_overlayfs_valid(); - if (overlayfs_valid_result == OverlayfsValidResult::kNotSupported) { + const auto overlayfs_check_result = android::fs_mgr::CheckOverlayfs(); + if (!overlayfs_check_result.supported) { LERROR << __FUNCTION__ << "(): kernel does not support overlayfs"; return false; } @@ -2280,10 +2280,7 @@ bool fs_mgr_mount_overlayfs_fstab_entry(const FstabEntry& entry) { } } - auto options = "lowerdir=" + lowerdir; - if (overlayfs_valid_result == OverlayfsValidResult::kOverrideCredsRequired) { - options += ",override_creds=off"; - } + const auto options = "lowerdir=" + lowerdir + overlayfs_check_result.mount_flags; // Use "overlay-" + entry.blk_device as the mount() source, so that adb-remout-test don't // confuse this with adb remount overlay, whose device name is "overlay". @@ -2339,30 +2336,34 @@ std::string fs_mgr_get_context(const std::string& mount_point) { return context; } -OverlayfsValidResult fs_mgr_overlayfs_valid() { - // Overlayfs available in the kernel, and patched for override_creds? - if (access("/sys/module/overlay/parameters/override_creds", F_OK) == 0) { - return OverlayfsValidResult::kOverrideCredsRequired; - } +namespace android { +namespace fs_mgr { + +OverlayfsCheckResult CheckOverlayfs() { if (!fs_mgr_filesystem_available("overlay")) { - return OverlayfsValidResult::kNotSupported; + return {.supported = false}; } struct utsname uts; if (uname(&uts) == -1) { - return OverlayfsValidResult::kNotSupported; + return {.supported = false}; } int major, minor; if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) { - return OverlayfsValidResult::kNotSupported; + return {.supported = false}; } - if (major < 4) { - return OverlayfsValidResult::kOk; - } - if (major > 4) { - return OverlayfsValidResult::kNotSupported; + // Overlayfs available in the kernel, and patched for override_creds? + if (access("/sys/module/overlay/parameters/override_creds", F_OK) == 0) { + auto mount_flags = ",override_creds=off"s; + if (major > 5 || (major == 5 && minor >= 15)) { + mount_flags += ",userxattr"s; + } + return {.supported = true, .mount_flags = mount_flags}; } - if (minor > 3) { - return OverlayfsValidResult::kNotSupported; + if (major < 4 || (major == 4 && minor <= 3)) { + return {.supported = true}; } - return OverlayfsValidResult::kOk; + return {.supported = false}; } + +} // namespace fs_mgr +} // namespace android diff --git a/fs_mgr/fs_mgr_overlayfs_mount.cpp b/fs_mgr/fs_mgr_overlayfs_mount.cpp index 37e30585a040..8fb63b17435a 100644 --- a/fs_mgr/fs_mgr_overlayfs_mount.cpp +++ b/fs_mgr/fs_mgr_overlayfs_mount.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -218,17 +217,6 @@ static std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point return ""; } -static inline bool KernelSupportsUserXattrs() { - struct utsname uts; - uname(&uts); - - int major, minor; - if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) { - return false; - } - return major > 5 || (major == 5 && minor >= 15); -} - const std::string fs_mgr_mount_point(const std::string& mount_point) { if ("/"s != mount_point) return mount_point; return "/system"; @@ -240,13 +228,7 @@ static std::string fs_mgr_get_overlayfs_options(const FstabEntry& entry) { auto candidate = fs_mgr_get_overlayfs_candidate(mount_point); if (candidate.empty()) return ""; auto ret = kLowerdirOption + mount_point + "," + kUpperdirOption + candidate + kUpperName + - ",workdir=" + candidate + kWorkName; - if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kOverrideCredsRequired) { - ret += ",override_creds=off"; - } - if (KernelSupportsUserXattrs()) { - ret += ",userxattr"; - } + ",workdir=" + candidate + kWorkName + android::fs_mgr::CheckOverlayfs().mount_flags; for (const auto& flag : android::base::Split(entry.fs_options, ",")) { if (android::base::StartsWith(flag, "context=")) { ret += "," + flag; @@ -608,7 +590,7 @@ bool OverlayfsSetupAllowed(bool verbose) { return false; } // Check mandatory kernel patches. - if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) { + if (!android::fs_mgr::CheckOverlayfs().supported) { if (verbose) { LOG(ERROR) << "Kernel does not support overlayfs"; } diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index 678dd69cb3d7..12a4a6d7f3dd 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -100,18 +100,18 @@ bool fs_mgr_is_f2fs(const std::string& blk_device); bool fs_mgr_filesystem_available(const std::string& filesystem); std::string fs_mgr_get_context(const std::string& mount_point); -enum class OverlayfsValidResult { - kNotSupported = 0, - kOk, - kOverrideCredsRequired, -}; -OverlayfsValidResult fs_mgr_overlayfs_valid(); - namespace android { namespace fs_mgr { bool UnmapDevice(const std::string& name); bool InRecovery(); +struct OverlayfsCheckResult { + bool supported; + std::string mount_flags; +}; + +OverlayfsCheckResult CheckOverlayfs(); + } // namespace fs_mgr } // namespace android diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp index 6b32b4d6fcd4..bacfa4b59bfe 100644 --- a/fs_mgr/fs_mgr_vendor_overlay.cpp +++ b/fs_mgr/fs_mgr_vendor_overlay.cpp @@ -85,10 +85,8 @@ bool fs_mgr_vendor_overlay_mount(const std::pair& moun return false; } - auto options = kLowerdirOption + source_directory + ":" + vendor_mount_point; - if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kOverrideCredsRequired) { - options += ",override_creds=off"; - } + const auto options = kLowerdirOption + source_directory + ":" + vendor_mount_point + + android::fs_mgr::CheckOverlayfs().mount_flags; auto report = "__mount(source=overlay,target="s + vendor_mount_point + ",type=overlay," + options + ")="; auto ret = mount("overlay", vendor_mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME, @@ -120,7 +118,7 @@ bool fs_mgr_vendor_overlay_mount_all() { const auto vendor_overlay_dirs = fs_mgr_get_vendor_overlay_dirs(vndk_version); if (vendor_overlay_dirs.empty()) return true; - if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) { + if (!android::fs_mgr::CheckOverlayfs().supported) { LINFO << "vendor overlay: kernel does not support overlayfs"; return false; } From c30f033b4e8d5f288114f2037be1813e29c09049 Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Tue, 25 Jul 2023 01:32:05 +0800 Subject: [PATCH 0253/1487] fs_mgr: Remove `include_dirs` declaration We aren't using anything through the removed path. We also shouldn't use `include_dirs` to begin with, as it bypasses any build system checks. Bug: 293695109 Test: build Change-Id: I06f7450c3ce545aa2583f8c3f8db18c45073f69e --- fs_mgr/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp index 0a836e43295f..7721ebf7aad3 100644 --- a/fs_mgr/Android.bp +++ b/fs_mgr/Android.bp @@ -60,7 +60,6 @@ cc_defaults { defaults: ["fs_mgr_defaults"], export_include_dirs: ["include"], local_include_dirs: ["include/"], - include_dirs: ["system/vold"], cflags: [ "-D_FILE_OFFSET_BITS=64", ], From 96126069c290b7daa408b14e1fc526c9a8e3b451 Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Mon, 24 Jul 2023 20:03:01 +0800 Subject: [PATCH 0254/1487] fs_mgr: Split libfs_mgr and libfstab The goal is to make the header definitions of the two curiously intertwined libraries less chaotic. After this change, libfstab's header would be self contained. In the sense that all symbols exported by its headers are defined in its compilation units. libfs_mgr would still embed libfstab like before, it can use internal symbols (symbols not exported by public headers) of libfstab through the libfstab/fstab_priv.h private header. Keep include_fstab/ as a symbolic link pointing to its new location. This is a temporary workaround as there are still some bad build rules (incorrectly) depending on the old include path with Android.bp `include_dirs` directive. Bug: 293695109 Test: build Change-Id: Ib70a84984ac2cbfca5f5b27fadebf6a16e58146a --- fs_mgr/Android.bp | 43 ------------- fs_mgr/fs_mgr_priv.h | 14 +---- fs_mgr/include_fstab | 1 + fs_mgr/libfstab/Android.bp | 62 +++++++++++++++++++ .../boot_config.cpp} | 11 ++-- .../{fs_mgr_fstab.cpp => libfstab/fstab.cpp} | 15 +++-- .../fstab_priv.h} | 26 ++++++-- fs_mgr/{ => libfstab}/fuzz/Android.bp | 0 .../fuzz/fs_mgr_fstab_fuzzer.cpp | 2 + fs_mgr/{ => libfstab}/fuzz/fstab.dict | 0 .../include}/fstab/fstab.h | 7 --- fs_mgr/libfstab/logging_macros.h | 40 ++++++++++++ .../slotselect.cpp} | 4 +- fs_mgr/tests/Android.bp | 2 - fs_mgr/tests/fs_mgr_test.cpp | 2 +- fs_mgr/tests/vts_fs_test.cpp | 2 + 16 files changed, 146 insertions(+), 85 deletions(-) create mode 120000 fs_mgr/include_fstab create mode 100644 fs_mgr/libfstab/Android.bp rename fs_mgr/{fs_mgr_boot_config.cpp => libfstab/boot_config.cpp} (97%) rename fs_mgr/{fs_mgr_fstab.cpp => libfstab/fstab.cpp} (98%) rename fs_mgr/{fs_mgr_priv_boot_config.h => libfstab/fstab_priv.h} (69%) rename fs_mgr/{ => libfstab}/fuzz/Android.bp (100%) rename fs_mgr/{ => libfstab}/fuzz/fs_mgr_fstab_fuzzer.cpp (98%) rename fs_mgr/{ => libfstab}/fuzz/fstab.dict (100%) rename fs_mgr/{include_fstab => libfstab/include}/fstab/fstab.h (91%) create mode 100644 fs_mgr/libfstab/logging_macros.h rename fs_mgr/{fs_mgr_slotselect.cpp => libfstab/slotselect.cpp} (98%) diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp index 7721ebf7aad3..4e4d20edc516 100644 --- a/fs_mgr/Android.bp +++ b/fs_mgr/Android.bp @@ -89,8 +89,6 @@ cc_defaults { static_libs: [ "libavb", "libfs_avb", - "libfstab", - "libdm", "libgsi", ], export_static_lib_headers: [ @@ -173,47 +171,6 @@ cc_library { ], } -cc_library_static { - // Do not ever make this a shared library as long as it is vendor_available. - // It does not have a stable interface. - name: "libfstab", - vendor_available: true, - ramdisk_available: true, - vendor_ramdisk_available: true, - recovery_available: true, - apex_available: [ - "//apex_available:anyapex", - "//apex_available:platform", - ], - host_supported: true, - defaults: ["fs_mgr_defaults"], - local_include_dirs: ["include/"], - srcs: [ - "fs_mgr_fstab.cpp", - "fs_mgr_boot_config.cpp", - "fs_mgr_slotselect.cpp", - ], - target: { - darwin: { - enabled: false, - }, - vendor: { - cflags: [ - // Skipping entries in fstab should only be done in a system - // process as the config file is in /system_ext. - // Remove the op from the vendor variant. - "-DNO_SKIP_MOUNT", - ], - }, - }, - export_include_dirs: ["include_fstab"], - header_libs: [ - "libbase_headers", - "libgsi_headers", - ], - min_sdk_version: "31", -} - cc_binary { name: "remount", defaults: ["fs_mgr_defaults"], diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index 12a4a6d7f3dd..7e4d5e54db4c 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -23,15 +23,7 @@ #include #include -#include "fs_mgr_priv_boot_config.h" - -/* The CHECK() in logging.h will use program invocation name as the tag. - * Thus, the log will have prefix "init: " when libfs_mgr is statically - * linked in the init process. This might be opaque when debugging. - * Appends "in libfs_mgr" at the end of the abort message to explicitly - * indicate the check happens in fs_mgr. - */ -#define FS_MGR_CHECK(x) CHECK(x) << "in libfs_mgr " +#include "libfstab/fstab_priv.h" #define FS_MGR_TAG "[libfs_mgr] " @@ -89,10 +81,7 @@ using namespace std::chrono_literals; bool fs_mgr_set_blk_ro(const std::string& blockdev, bool readonly = true); -bool fs_mgr_update_for_slotselect(android::fs_mgr::Fstab* fstab); bool fs_mgr_is_device_unlocked(); -const std::string& get_android_dt_dir(); -bool is_dt_compatible(); bool fs_mgr_is_ext4(const std::string& blk_device); bool fs_mgr_is_f2fs(const std::string& blk_device); @@ -104,7 +93,6 @@ namespace android { namespace fs_mgr { bool UnmapDevice(const std::string& name); -bool InRecovery(); struct OverlayfsCheckResult { bool supported; diff --git a/fs_mgr/include_fstab b/fs_mgr/include_fstab new file mode 120000 index 000000000000..728737fe589c --- /dev/null +++ b/fs_mgr/include_fstab @@ -0,0 +1 @@ +libfstab/include \ No newline at end of file diff --git a/fs_mgr/libfstab/Android.bp b/fs_mgr/libfstab/Android.bp new file mode 100644 index 000000000000..df0269c3a6af --- /dev/null +++ b/fs_mgr/libfstab/Android.bp @@ -0,0 +1,62 @@ +// +// Copyright (C) 2023 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. +// + +package { + default_applicable_licenses: [ + "Android-Apache-2.0", + "system_core_fs_mgr_license", + ], +} + +cc_library_static { + // Do not ever make this a shared library as long as it is vendor_available. + // It does not have a stable interface. + name: "libfstab", + vendor_available: true, + ramdisk_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + host_supported: true, + defaults: ["fs_mgr_defaults"], + export_include_dirs: ["include"], + header_libs: [ + "libbase_headers", + "libgsi_headers", + ], + srcs: [ + "fstab.cpp", + "boot_config.cpp", + "slotselect.cpp", + ], + target: { + darwin: { + enabled: false, + }, + vendor: { + cflags: [ + // Skipping entries in fstab should only be done in a system + // process as the config file is in /system_ext. + // Remove the op from the vendor variant. + "-DNO_SKIP_MOUNT", + ], + }, + }, + apex_available: [ + "//apex_available:anyapex", + "//apex_available:platform", + ], + min_sdk_version: "31", +} diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/libfstab/boot_config.cpp similarity index 97% rename from fs_mgr/fs_mgr_boot_config.cpp rename to fs_mgr/libfstab/boot_config.cpp index 75d1e0db69d4..8fb28c607cb9 100644 --- a/fs_mgr/fs_mgr_boot_config.cpp +++ b/fs_mgr/libfstab/boot_config.cpp @@ -20,11 +20,12 @@ #include #include +#include #include #include -#include -#include "fs_mgr_priv.h" +#include "fstab_priv.h" +#include "logging_macros.h" std::vector> fs_mgr_parse_cmdline(const std::string& cmdline) { static constexpr char quote = '"'; @@ -84,7 +85,7 @@ std::vector> fs_mgr_parse_proc_bootconfig( bool fs_mgr_get_boot_config_from_bootconfig(const std::string& bootconfig, const std::string& android_key, std::string* out_val) { - FS_MGR_CHECK(out_val != nullptr); + FSTAB_CHECK(out_val != nullptr); const std::string bootconfig_key("androidboot." + android_key); for (const auto& [key, value] : fs_mgr_parse_proc_bootconfig(bootconfig)) { @@ -100,7 +101,7 @@ bool fs_mgr_get_boot_config_from_bootconfig(const std::string& bootconfig, bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::string& android_key, std::string* out_val) { - FS_MGR_CHECK(out_val != nullptr); + FSTAB_CHECK(out_val != nullptr); const std::string cmdline_key("androidboot." + android_key); for (const auto& [key, value] : fs_mgr_parse_cmdline(cmdline)) { @@ -140,7 +141,7 @@ bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::str // kernel cmdline (in that order). Returns 'true' if successfully // found, 'false' otherwise. bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) { - FS_MGR_CHECK(out_val != nullptr); + FSTAB_CHECK(out_val != nullptr); // firstly, check the device tree if (is_dt_compatible()) { diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/libfstab/fstab.cpp similarity index 98% rename from fs_mgr/fs_mgr_fstab.cpp rename to fs_mgr/libfstab/fstab.cpp index ca27034f4451..5b5c3d26c450 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/libfstab/fstab.cpp @@ -36,7 +36,8 @@ #include #include -#include "fs_mgr_priv.h" +#include "fstab_priv.h" +#include "logging_macros.h" using android::base::EndsWith; using android::base::ParseByteCount; @@ -54,7 +55,7 @@ constexpr char kDefaultAndroidDtDir[] = "/proc/device-tree/firmware/android"; constexpr char kProcMountsPath[] = "/proc/mounts"; struct FlagList { - const char *name; + const char* name; uint64_t flag; }; @@ -80,7 +81,7 @@ FlagList kMountFlagsList[] = { off64_t CalculateZramSize(int percentage) { off64_t total; - total = sysconf(_SC_PHYS_PAGES); + total = sysconf(_SC_PHYS_PAGES); total *= percentage; total /= 100; @@ -400,7 +401,7 @@ std::string ReadFstabFromDt() { std::string mount_point; file_name = - android::base::StringPrintf("%s/%s/mnt_point", fstabdir_name.c_str(), dp->d_name); + android::base::StringPrintf("%s/%s/mnt_point", fstabdir_name.c_str(), dp->d_name); if (ReadDtFile(file_name, &value)) { LINFO << "dt_fstab: Using a specified mount point " << value << " for " << dp->d_name; mount_point = value; @@ -416,14 +417,16 @@ std::string ReadFstabFromDt() { } fstab_entry.push_back(value); - file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name); + file_name = + android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name); if (!ReadDtFile(file_name, &value)) { LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name; return {}; } fstab_entry.push_back(value); - file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name); + file_name = + android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name); if (!ReadDtFile(file_name, &value)) { LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name; return {}; diff --git a/fs_mgr/fs_mgr_priv_boot_config.h b/fs_mgr/libfstab/fstab_priv.h similarity index 69% rename from fs_mgr/fs_mgr_priv_boot_config.h rename to fs_mgr/libfstab/fstab_priv.h index 6a38401319b4..fb12b9fb1d1c 100644 --- a/fs_mgr/fs_mgr_priv_boot_config.h +++ b/fs_mgr/libfstab/fstab_priv.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2023 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. @@ -14,16 +14,17 @@ * limitations under the License. */ -#ifndef __CORE_FS_MGR_PRIV_BOOTCONFIG_H -#define __CORE_FS_MGR_PRIV_BOOTCONFIG_H +#pragma once -#include #include #include #include -std::vector> fs_mgr_parse_cmdline(const std::string& cmdline); +#include + +// Do not include logging_macros.h here as this header is used by fs_mgr, too. +std::vector> fs_mgr_parse_cmdline(const std::string& cmdline); bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::string& key, std::string* out_val); bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val); @@ -34,4 +35,17 @@ bool fs_mgr_get_boot_config_from_bootconfig(const std::string& bootconfig, const std::string* out_val); bool fs_mgr_get_boot_config_from_bootconfig_source(const std::string& key, std::string* out_val); -#endif /* __CORE_FS_MGR_PRIV_BOOTCONFIG_H */ +bool fs_mgr_update_for_slotselect(android::fs_mgr::Fstab* fstab); +const std::string& get_android_dt_dir(); +bool is_dt_compatible(); + +namespace android { +namespace fs_mgr { + +bool InRecovery(); +bool ParseFstabFromString(const std::string& fstab_str, bool proc_mounts, Fstab* fstab_out); +bool SkipMountWithConfig(const std::string& skip_config, Fstab* fstab, bool verbose); +std::string GetFstabPath(); + +} // namespace fs_mgr +} // namespace android diff --git a/fs_mgr/fuzz/Android.bp b/fs_mgr/libfstab/fuzz/Android.bp similarity index 100% rename from fs_mgr/fuzz/Android.bp rename to fs_mgr/libfstab/fuzz/Android.bp diff --git a/fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp b/fs_mgr/libfstab/fuzz/fs_mgr_fstab_fuzzer.cpp similarity index 98% rename from fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp rename to fs_mgr/libfstab/fuzz/fs_mgr_fstab_fuzzer.cpp index b5fdad4d54b6..b09b273df584 100644 --- a/fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp +++ b/fs_mgr/libfstab/fuzz/fs_mgr_fstab_fuzzer.cpp @@ -20,6 +20,8 @@ #include #include +#include "../fstab_priv.h" + extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FuzzedDataProvider fdp(data, size); diff --git a/fs_mgr/fuzz/fstab.dict b/fs_mgr/libfstab/fuzz/fstab.dict similarity index 100% rename from fs_mgr/fuzz/fstab.dict rename to fs_mgr/libfstab/fuzz/fstab.dict diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/libfstab/include/fstab/fstab.h similarity index 91% rename from fs_mgr/include_fstab/fstab/fstab.h rename to fs_mgr/libfstab/include/fstab/fstab.h index 9cb1546c5aaf..e0683ac284cb 100644 --- a/fs_mgr/include_fstab/fstab/fstab.h +++ b/fs_mgr/libfstab/include/fstab/fstab.h @@ -93,13 +93,6 @@ struct FstabEntry { // Unless explicitly requested, a lookup on mount point should always return the 1st one. using Fstab = std::vector; -// Exported for testability. Regular users should use ReadFstabFromFile(). -bool ParseFstabFromString(const std::string& fstab_str, bool proc_mounts, Fstab* fstab_out); -// Exported for testability. Regular users should use ReadDefaultFstab(). -std::string GetFstabPath(); -// Exported for testability. -bool SkipMountWithConfig(const std::string& skip_config, Fstab* fstab, bool verbose); - bool ReadFstabFromFile(const std::string& path, Fstab* fstab); bool ReadFstabFromProcMounts(Fstab* fstab); bool ReadFstabFromDt(Fstab* fstab, bool verbose = true); diff --git a/fs_mgr/libfstab/logging_macros.h b/fs_mgr/libfstab/logging_macros.h new file mode 100644 index 000000000000..7ea1b7720a54 --- /dev/null +++ b/fs_mgr/libfstab/logging_macros.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2023 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. + */ + +#pragma once + +#include + +#define FSTAB_TAG "[libfstab] " + +/* The CHECK() in logging.h will use program invocation name as the tag. + * Thus, the log will have prefix "init: " when libfs_mgr is statically + * linked in the init process. This might be opaque when debugging. + * Append a library name tag at the end of the abort message to aid debugging. + */ +#define FSTAB_CHECK(x) CHECK(x) << "in " << FSTAB_TAG + +// Logs a message to kernel +#define LINFO LOG(INFO) << FSTAB_TAG +#define LWARNING LOG(WARNING) << FSTAB_TAG +#define LERROR LOG(ERROR) << FSTAB_TAG +#define LFATAL LOG(FATAL) << FSTAB_TAG + +// Logs a message with strerror(errno) at the end +#define PINFO PLOG(INFO) << FSTAB_TAG +#define PWARNING PLOG(WARNING) << FSTAB_TAG +#define PERROR PLOG(ERROR) << FSTAB_TAG +#define PFATAL PLOG(FATAL) << FSTAB_TAG diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/libfstab/slotselect.cpp similarity index 98% rename from fs_mgr/fs_mgr_slotselect.cpp rename to fs_mgr/libfstab/slotselect.cpp index 09c1b7e20e97..97b2ba1f575f 100644 --- a/fs_mgr/fs_mgr_slotselect.cpp +++ b/fs_mgr/libfstab/slotselect.cpp @@ -18,8 +18,8 @@ #include -#include "fs_mgr.h" -#include "fs_mgr_priv.h" +#include "fstab_priv.h" +#include "logging_macros.h" // Realistically, this file should be part of the android::fs_mgr namespace; using namespace android::fs_mgr; diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp index b9bae2513e70..b7f792fe6235 100644 --- a/fs_mgr/tests/Android.bp +++ b/fs_mgr/tests/Android.bp @@ -38,7 +38,6 @@ cc_test { ], static_libs: [ "libfs_mgr", - "libfstab", ], srcs: [ "file_wait_test.cpp", @@ -109,7 +108,6 @@ cc_test { ], static_libs: [ "libfs_mgr", - "libfstab", "libgmock", "libgtest", ], diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp index 5f889caee5e7..c51df2a7ef1a 100644 --- a/fs_mgr/tests/fs_mgr_test.cpp +++ b/fs_mgr/tests/fs_mgr_test.cpp @@ -31,7 +31,7 @@ #include #include -#include "../fs_mgr_priv_boot_config.h" +#include "../fs_mgr_priv.h" using namespace android::fs_mgr; diff --git a/fs_mgr/tests/vts_fs_test.cpp b/fs_mgr/tests/vts_fs_test.cpp index 4d771fa046d6..32947b53a6d1 100644 --- a/fs_mgr/tests/vts_fs_test.cpp +++ b/fs_mgr/tests/vts_fs_test.cpp @@ -23,6 +23,8 @@ #include #include +#include "../fs_mgr_priv.h" + using testing::Contains; using testing::Not; From 840691be716bfd95f4d7b536c13a0a6a5204471a Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Tue, 1 Aug 2023 09:06:42 +0000 Subject: [PATCH 0255/1487] Revert "Use /bootstrap-apex for bootstrap APEXes" Revert submission 2666915-share-bootstrap Reason for revert: b/293949266 vold_prepare_subdirs fails to create apexdata directories. Reverted changes: /q/submissionid:2666915-share-bootstrap Change-Id: I3e97e8511755844de4b54f51ff20afc154bd8e74 --- init/builtins.cpp | 50 ---------------------------------------- init/init.cpp | 6 ----- init/mount_namespace.cpp | 39 ++++++++----------------------- init/mount_namespace.h | 3 --- init/selinux.cpp | 2 +- rootdir/Android.mk | 2 +- 6 files changed, 11 insertions(+), 91 deletions(-) diff --git a/init/builtins.cpp b/init/builtins.cpp index e4f0bd040ed6..2176233aab96 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -1262,51 +1262,6 @@ static Result MountLinkerConfigForDefaultNamespace() { return {}; } - -static Result MountApexRootForDefaultNamespace() { - auto mount_namespace_id = GetCurrentMountNamespace(); - if (!mount_namespace_id.ok()) { - return mount_namespace_id.error(); - } - // There's nothing to do if it's still in the bootstrap mount namespace. - // This happens when we don't need to update APEXes (e.g. Microdroid) - // where bootstrap mount namespace == default mount namespace. - if (mount_namespace_id.value() == NS_BOOTSTRAP) { - return {}; - } - - // Now, we're in the "default" mount namespace and need a fresh /apex for - // the default mount namespace. - // - // At this point, there are two mounts at the same mount point: /apex - // - to tmpfs (private) - // - to /bootstrap-apex (shared) - // - // We need unmount the second mount so that /apex in the default mount - // namespace becomes RW/empty and "private" (we don't want mount events to - // propagate to the bootstrap mount namespace). - // - // Likewise, we don't want the unmount event itself to propagate to the - // bootstrap mount namespace. Otherwise, /apex in the bootstrap mount - // namespace would become empty due to the unmount. - // - // Hence, before unmounting, we make /apex (the second one) "private" first. - // so that the unmouting below doesn't affect to the bootstrap mount namespace. - if (mount(nullptr, "/apex", nullptr, MS_PRIVATE | MS_REC, nullptr) == -1) { - return ErrnoError() << "Failed to remount /apex as private"; - } - - // Now we can unmount /apex (bind-mount to /bootstrap-apex). This only affects - // in the default mount namespace and /apex is now seen as tmpfs mount. - // Note that /apex in the bootstrap mount namespace is still a bind-mount to - // /bootstrap-apex and holds the APEX mounts. - if (umount2("/apex", MNT_DETACH) == -1) { - return ErrnoError() << "Failed to umount /apex"; - } - - return {}; -} - static Result do_update_linker_config(const BuiltinArguments&) { return GenerateLinkerConfiguration(); } @@ -1359,11 +1314,6 @@ static Result do_enter_default_mount_ns(const BuiltinArguments& args) { if (auto result = SwitchToMountNamespaceIfNeeded(NS_DEFAULT); !result.ok()) { return result.error(); } - - if (auto result = MountApexRootForDefaultNamespace(); !result.ok()) { - return result.error(); - } - if (auto result = MountLinkerConfigForDefaultNamespace(); !result.ok()) { return result.error(); } diff --git a/init/init.cpp b/init/init.cpp index 4bb8eecb981a..da63fdc3bda5 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -832,12 +832,6 @@ static void MountExtraFilesystems() { CHECKCALL(mount("tmpfs", "/apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0")); - if (NeedsTwoMountNamespaces()) { - // /bootstrap-apex is used to mount "bootstrap" APEXes. - CHECKCALL(mount("tmpfs", "/bootstrap-apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, - "mode=0755,uid=0,gid=0")); - } - // /linkerconfig is used to keep generated linker configuration CHECKCALL(mount("tmpfs", "/linkerconfig", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0")); diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp index e069a5d3e3db..5b53d5092227 100644 --- a/init/mount_namespace.cpp +++ b/init/mount_namespace.cpp @@ -66,23 +66,23 @@ static std::string GetMountNamespaceId() { return ret; } -static android::base::unique_fd bootstrap_ns_fd; -static android::base::unique_fd default_ns_fd; - -static std::string bootstrap_ns_id; -static std::string default_ns_id; - -} // namespace - // In case we have two sets of APEXes (non-updatable, updatable), we need two separate mount // namespaces. -bool NeedsTwoMountNamespaces() { +static bool NeedsTwoMountNamespaces() { if (IsRecoveryMode()) return false; // In microdroid, there's only one set of APEXes in built-in directories include block devices. if (IsMicrodroid()) return false; return true; } +static android::base::unique_fd bootstrap_ns_fd; +static android::base::unique_fd default_ns_fd; + +static std::string bootstrap_ns_id; +static std::string default_ns_id; + +} // namespace + bool SetupMountNamespaces() { // Set the propagation type of / as shared so that any mounting event (e.g. // /data) is by default visible to all processes. When private mounting is @@ -96,27 +96,6 @@ bool SetupMountNamespaces() { // the bootstrap namespace get APEXes from the read-only partition. if (!(ChangeMount("/apex", MS_PRIVATE))) return false; - // However, some components (e.g. servicemanager) need to access bootstrap - // APEXes from the default mount namespace. To achieve that, we bind-mount - // /apex with /bootstrap-apex (not private) in the bootstrap mount namespace. - // Bootstrap APEXes are mounted in /apex and also visible in /bootstrap-apex. - // In the default mount namespace, we detach /bootstrap-apex from /apex and - // bootstrap APEXes are still be visible in /bootstrap-apex. - // - // The end result will look like: - // in the bootstrap mount namespace: - // /apex (== /bootstrap-apex) - // {bootstrap APEXes from the read-only partition} - // - // in the default mount namespace: - // /bootstrap-apex - // {bootstrap APEXes from the read-only partition} - // /apex - // {APEXes, can be from /data partition} - if (NeedsTwoMountNamespaces()) { - if (!(BindMount("/bootstrap-apex", "/apex"))) return false; - } - // /linkerconfig is a private mountpoint to give a different linker configuration // based on the mount namespace. Subdirectory will be bind-mounted based on current mount // namespace diff --git a/init/mount_namespace.h b/init/mount_namespace.h index 43c5476a6ab8..5e3dab241290 100644 --- a/init/mount_namespace.h +++ b/init/mount_namespace.h @@ -24,12 +24,9 @@ namespace init { enum MountNamespace { NS_BOOTSTRAP, NS_DEFAULT }; bool SetupMountNamespaces(); - base::Result SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespace); base::Result GetCurrentMountNamespace(); -bool NeedsTwoMountNamespaces(); - } // namespace init } // namespace android diff --git a/init/selinux.cpp b/init/selinux.cpp index 8532c44c1c70..51093d898e8b 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -766,7 +766,7 @@ void SelinuxRestoreContext() { selinux_android_restorecon("/dev/device-mapper", 0); selinux_android_restorecon("/apex", 0); - selinux_android_restorecon("/bootstrap-apex", 0); + selinux_android_restorecon("/linkerconfig", 0); // adb remount, snapshot-based updates, and DSUs all create files during diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 52187536f3fe..3362872c070d 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -91,7 +91,7 @@ endif # # create some directories (some are mount points) and symlinks LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \ - dev proc sys system data data_mirror odm oem acct config storage mnt apex bootstrap-apex debug_ramdisk \ + dev proc sys system data data_mirror odm oem acct config storage mnt apex debug_ramdisk \ linkerconfig second_stage_resources postinstall $(BOARD_ROOT_EXTRA_FOLDERS)); \ ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \ ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \ From f4b1d698b1d3fd4592c68464923912d902460509 Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Tue, 25 Jul 2023 22:08:55 +0800 Subject: [PATCH 0256/1487] init: Unify duplicated get_android_dt_dir with libfs_mgr init and libfs_mgr both defines get_android_dt_dir() with subtle differences. Merge the two implementations into libfs_mgr to reduce code duplication (in terms of source code and code gen) Note: init's implementation checks the kernel cmdline first and then the kernel bootconfig, while libfs_mgr's order is the opposite. Realistically I don't think this order matter much though. If any, we should prioritize bootconfig over kernel cmdline most of the time. Bug: 293695109 Test: Presubmit Change-Id: Ic8d2c965c62f9e873ccdaf77d67c7708f25a7b56 (cherry picked from https://android-review.googlesource.com/q/commit:d7c67b40a9b6a5e72d54adf37da22238381182f7) Ignore-AOSP-First: Fix merge conflict --- fs_mgr/libfstab/boot_config.cpp | 29 +++++++++++++++++++- fs_mgr/libfstab/fstab.cpp | 29 ++++---------------- fs_mgr/libfstab/fstab_priv.h | 1 - fs_mgr/libfstab/include/fstab/fstab.h | 4 +++ init/Android.bp | 1 + init/property_service.cpp | 6 +++-- init/util.cpp | 39 +++++---------------------- init/util.h | 3 --- 8 files changed, 49 insertions(+), 63 deletions(-) diff --git a/fs_mgr/libfstab/boot_config.cpp b/fs_mgr/libfstab/boot_config.cpp index 8fb28c607cb9..fee40158b709 100644 --- a/fs_mgr/libfstab/boot_config.cpp +++ b/fs_mgr/libfstab/boot_config.cpp @@ -27,6 +27,33 @@ #include "fstab_priv.h" #include "logging_macros.h" +namespace android { +namespace fs_mgr { + +const std::string& GetAndroidDtDir() { + // Set once and saves time for subsequent calls to this function + static const std::string kAndroidDtDir = [] { + std::string android_dt_dir; + if ((fs_mgr_get_boot_config_from_bootconfig_source("android_dt_dir", &android_dt_dir) || + fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) && + !android_dt_dir.empty()) { + // Ensure the returned path ends with a / + if (android_dt_dir.back() != '/') { + android_dt_dir.push_back('/'); + } + } else { + // Fall back to the standard procfs-based path + android_dt_dir = "/proc/device-tree/firmware/android/"; + } + LINFO << "Using Android DT directory " << android_dt_dir; + return android_dt_dir; + }(); + return kAndroidDtDir; +} + +} // namespace fs_mgr +} // namespace android + std::vector> fs_mgr_parse_cmdline(const std::string& cmdline) { static constexpr char quote = '"'; @@ -145,7 +172,7 @@ bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) { // firstly, check the device tree if (is_dt_compatible()) { - std::string file_name = get_android_dt_dir() + "/" + key; + std::string file_name = android::fs_mgr::GetAndroidDtDir() + key; if (android::base::ReadFileToString(file_name, out_val)) { if (!out_val->empty()) { out_val->pop_back(); // Trims the trailing '\0' out. diff --git a/fs_mgr/libfstab/fstab.cpp b/fs_mgr/libfstab/fstab.cpp index 5b5c3d26c450..86ba03148838 100644 --- a/fs_mgr/libfstab/fstab.cpp +++ b/fs_mgr/libfstab/fstab.cpp @@ -51,7 +51,6 @@ namespace android { namespace fs_mgr { namespace { -constexpr char kDefaultAndroidDtDir[] = "/proc/device-tree/firmware/android"; constexpr char kProcMountsPath[] = "/proc/mounts"; struct FlagList { @@ -337,25 +336,14 @@ bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) { return true; } -std::string InitAndroidDtDir() { - std::string android_dt_dir; - // The platform may specify a custom Android DT path in kernel cmdline - if (!fs_mgr_get_boot_config_from_bootconfig_source("android_dt_dir", &android_dt_dir) && - !fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) { - // Fall back to the standard procfs-based path - android_dt_dir = kDefaultAndroidDtDir; - } - return android_dt_dir; -} - bool IsDtFstabCompatible() { std::string dt_value; - std::string file_name = get_android_dt_dir() + "/fstab/compatible"; + std::string file_name = GetAndroidDtDir() + "fstab/compatible"; if (ReadDtFile(file_name, &dt_value) && dt_value == "android,fstab") { // If there's no status property or its set to "ok" or "okay", then we use the DT fstab. std::string status_value; - std::string status_file_name = get_android_dt_dir() + "/fstab/status"; + std::string status_file_name = GetAndroidDtDir() + "fstab/status"; return !ReadDtFile(status_file_name, &status_value) || status_value == "ok" || status_value == "okay"; } @@ -368,7 +356,7 @@ std::string ReadFstabFromDt() { return {}; } - std::string fstabdir_name = get_android_dt_dir() + "/fstab"; + std::string fstabdir_name = GetAndroidDtDir() + "fstab"; std::unique_ptr fstabdir(opendir(fstabdir_name.c_str()), closedir); if (!fstabdir) return {}; @@ -876,7 +864,7 @@ const FstabEntry* GetEntryForMountPoint(const Fstab* fstab, const std::string& p std::set GetBootDevices() { // First check bootconfig, then kernel commandline, then the device tree - std::string dt_file_name = get_android_dt_dir() + "/boot_devices"; + std::string dt_file_name = GetAndroidDtDir() + "boot_devices"; std::string value; if (fs_mgr_get_boot_config_from_bootconfig_source("boot_devices", &value) || fs_mgr_get_boot_config_from_bootconfig_source("boot_device", &value)) { @@ -948,15 +936,8 @@ bool InRecovery() { } // namespace fs_mgr } // namespace android -// FIXME: The same logic is duplicated in system/core/init/ -const std::string& get_android_dt_dir() { - // Set once and saves time for subsequent calls to this function - static const std::string kAndroidDtDir = android::fs_mgr::InitAndroidDtDir(); - return kAndroidDtDir; -} - bool is_dt_compatible() { - std::string file_name = get_android_dt_dir() + "/compatible"; + std::string file_name = android::fs_mgr::GetAndroidDtDir() + "compatible"; std::string dt_value; if (android::fs_mgr::ReadDtFile(file_name, &dt_value)) { if (dt_value == "android,firmware") { diff --git a/fs_mgr/libfstab/fstab_priv.h b/fs_mgr/libfstab/fstab_priv.h index fb12b9fb1d1c..5d226f8798f6 100644 --- a/fs_mgr/libfstab/fstab_priv.h +++ b/fs_mgr/libfstab/fstab_priv.h @@ -36,7 +36,6 @@ bool fs_mgr_get_boot_config_from_bootconfig(const std::string& bootconfig, const bool fs_mgr_get_boot_config_from_bootconfig_source(const std::string& key, std::string* out_val); bool fs_mgr_update_for_slotselect(android::fs_mgr::Fstab* fstab); -const std::string& get_android_dt_dir(); bool is_dt_compatible(); namespace android { diff --git a/fs_mgr/libfstab/include/fstab/fstab.h b/fs_mgr/libfstab/include/fstab/fstab.h index e0683ac284cb..0a45fe87ad3e 100644 --- a/fs_mgr/libfstab/include/fstab/fstab.h +++ b/fs_mgr/libfstab/include/fstab/fstab.h @@ -124,5 +124,9 @@ std::set GetBootDevices(); // expected name. std::string GetVerityDeviceName(const FstabEntry& entry); +// Returns the Android Device Tree directory as specified in the kernel bootconfig or cmdline. +// If the platform does not configure a custom DT path, returns the standard one (based in procfs). +const std::string& GetAndroidDtDir(); + } // namespace fs_mgr } // namespace android diff --git a/init/Android.bp b/init/Android.bp index ee34215d750e..d4852d6483be 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -539,6 +539,7 @@ cc_defaults { "libprotobuf-cpp-lite", ], static_libs: [ + "libfs_mgr", "libhidl-gen-utils", ], } diff --git a/init/property_service.cpp b/init/property_service.cpp index 3e9a6d9f342e..87ab13b3c3c5 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -1324,7 +1325,8 @@ static void ProcessKernelDt() { return; } - std::unique_ptr dir(opendir(get_android_dt_dir().c_str()), closedir); + std::unique_ptr dir(opendir(android::fs_mgr::GetAndroidDtDir().c_str()), + closedir); if (!dir) return; std::string dt_file; @@ -1335,7 +1337,7 @@ static void ProcessKernelDt() { continue; } - std::string file_name = get_android_dt_dir() + dp->d_name; + std::string file_name = android::fs_mgr::GetAndroidDtDir() + dp->d_name; android::base::ReadFileToString(file_name, &dt_file); std::replace(dt_file.begin(), dt_file.end(), ',', '.'); diff --git a/init/util.cpp b/init/util.cpp index d0478e80d005..61d59a4801d0 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -42,6 +42,10 @@ #include #include +#if defined(__ANDROID__) +#include +#endif + #ifdef INIT_FULL_SOURCES #include #include @@ -60,8 +64,6 @@ using namespace std::literals::string_literals; namespace android { namespace init { -const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android/"); - const std::string kDataDirPrefix("/data/"); void (*trigger_shutdown)(const std::string& command) = nullptr; @@ -375,45 +377,18 @@ Result ExpandProps(const std::string& src) { return dst; } -static std::string init_android_dt_dir() { - // Use the standard procfs-based path by default - std::string android_dt_dir = kDefaultAndroidDtDir; - // The platform may specify a custom Android DT path in kernel cmdline - ImportKernelCmdline([&](const std::string& key, const std::string& value) { - if (key == "androidboot.android_dt_dir") { - android_dt_dir = value; - } - }); - // ..Or bootconfig - if (android_dt_dir == kDefaultAndroidDtDir) { - ImportBootconfig([&](const std::string& key, const std::string& value) { - if (key == "androidboot.android_dt_dir") { - android_dt_dir = value; - } - }); - } - - LOG(INFO) << "Using Android DT directory " << android_dt_dir; - return android_dt_dir; -} - -// FIXME: The same logic is duplicated in system/core/fs_mgr/ -const std::string& get_android_dt_dir() { - // Set once and saves time for subsequent calls to this function - static const std::string kAndroidDtDir = init_android_dt_dir(); - return kAndroidDtDir; -} - // Reads the content of device tree file under the platform's Android DT directory. // Returns true if the read is success, false otherwise. bool read_android_dt_file(const std::string& sub_path, std::string* dt_content) { - const std::string file_name = get_android_dt_dir() + sub_path; +#if defined(__ANDROID__) + const std::string file_name = android::fs_mgr::GetAndroidDtDir() + sub_path; if (android::base::ReadFileToString(file_name, dt_content)) { if (!dt_content->empty()) { dt_content->pop_back(); // Trims the trailing '\0' out. return true; } } +#endif return false; } diff --git a/init/util.h b/init/util.h index 3f0a4e023f08..1c00a3efc0b1 100644 --- a/init/util.h +++ b/init/util.h @@ -60,9 +60,6 @@ bool make_dir(const std::string& path, mode_t mode); bool is_dir(const char* pathname); Result ExpandProps(const std::string& src); -// Returns the platform's Android DT directory as specified in the kernel cmdline. -// If the platform does not configure a custom DT path, returns the standard one (based in procfs). -const std::string& get_android_dt_dir(); // Reads or compares the content of device tree file under the platform's Android DT directory. bool read_android_dt_file(const std::string& sub_path, std::string* dt_content); bool is_android_dt_value_expected(const std::string& sub_path, const std::string& expected_content); From b8c23259b15b85feec119e4e770e232c5cc74fcd Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Tue, 25 Jul 2023 22:08:55 +0800 Subject: [PATCH 0257/1487] init: Unify duplicated get_android_dt_dir with libfs_mgr init and libfs_mgr both defines get_android_dt_dir() with subtle differences. Merge the two implementations into libfs_mgr to reduce code duplication (in terms of source code and code gen) Note: init's implementation checks the kernel cmdline first and then the kernel bootconfig, while libfs_mgr's order is the opposite. Realistically I don't think this order matter much though. If any, we should prioritize bootconfig over kernel cmdline most of the time. Bug: 293695109 Test: Presubmit Merged-In: Ic8d2c965c62f9e873ccdaf77d67c7708f25a7b56 Change-Id: Ic8d2c965c62f9e873ccdaf77d67c7708f25a7b56 --- fs_mgr/libfstab/boot_config.cpp | 29 +++++++++++++++++++- fs_mgr/libfstab/fstab.cpp | 29 ++++---------------- fs_mgr/libfstab/fstab_priv.h | 1 - fs_mgr/libfstab/include/fstab/fstab.h | 4 +++ init/Android.bp | 1 + init/property_service.cpp | 6 +++-- init/util.cpp | 39 +++++---------------------- init/util.h | 3 --- 8 files changed, 49 insertions(+), 63 deletions(-) diff --git a/fs_mgr/libfstab/boot_config.cpp b/fs_mgr/libfstab/boot_config.cpp index 8fb28c607cb9..fee40158b709 100644 --- a/fs_mgr/libfstab/boot_config.cpp +++ b/fs_mgr/libfstab/boot_config.cpp @@ -27,6 +27,33 @@ #include "fstab_priv.h" #include "logging_macros.h" +namespace android { +namespace fs_mgr { + +const std::string& GetAndroidDtDir() { + // Set once and saves time for subsequent calls to this function + static const std::string kAndroidDtDir = [] { + std::string android_dt_dir; + if ((fs_mgr_get_boot_config_from_bootconfig_source("android_dt_dir", &android_dt_dir) || + fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) && + !android_dt_dir.empty()) { + // Ensure the returned path ends with a / + if (android_dt_dir.back() != '/') { + android_dt_dir.push_back('/'); + } + } else { + // Fall back to the standard procfs-based path + android_dt_dir = "/proc/device-tree/firmware/android/"; + } + LINFO << "Using Android DT directory " << android_dt_dir; + return android_dt_dir; + }(); + return kAndroidDtDir; +} + +} // namespace fs_mgr +} // namespace android + std::vector> fs_mgr_parse_cmdline(const std::string& cmdline) { static constexpr char quote = '"'; @@ -145,7 +172,7 @@ bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) { // firstly, check the device tree if (is_dt_compatible()) { - std::string file_name = get_android_dt_dir() + "/" + key; + std::string file_name = android::fs_mgr::GetAndroidDtDir() + key; if (android::base::ReadFileToString(file_name, out_val)) { if (!out_val->empty()) { out_val->pop_back(); // Trims the trailing '\0' out. diff --git a/fs_mgr/libfstab/fstab.cpp b/fs_mgr/libfstab/fstab.cpp index 5b5c3d26c450..86ba03148838 100644 --- a/fs_mgr/libfstab/fstab.cpp +++ b/fs_mgr/libfstab/fstab.cpp @@ -51,7 +51,6 @@ namespace android { namespace fs_mgr { namespace { -constexpr char kDefaultAndroidDtDir[] = "/proc/device-tree/firmware/android"; constexpr char kProcMountsPath[] = "/proc/mounts"; struct FlagList { @@ -337,25 +336,14 @@ bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) { return true; } -std::string InitAndroidDtDir() { - std::string android_dt_dir; - // The platform may specify a custom Android DT path in kernel cmdline - if (!fs_mgr_get_boot_config_from_bootconfig_source("android_dt_dir", &android_dt_dir) && - !fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) { - // Fall back to the standard procfs-based path - android_dt_dir = kDefaultAndroidDtDir; - } - return android_dt_dir; -} - bool IsDtFstabCompatible() { std::string dt_value; - std::string file_name = get_android_dt_dir() + "/fstab/compatible"; + std::string file_name = GetAndroidDtDir() + "fstab/compatible"; if (ReadDtFile(file_name, &dt_value) && dt_value == "android,fstab") { // If there's no status property or its set to "ok" or "okay", then we use the DT fstab. std::string status_value; - std::string status_file_name = get_android_dt_dir() + "/fstab/status"; + std::string status_file_name = GetAndroidDtDir() + "fstab/status"; return !ReadDtFile(status_file_name, &status_value) || status_value == "ok" || status_value == "okay"; } @@ -368,7 +356,7 @@ std::string ReadFstabFromDt() { return {}; } - std::string fstabdir_name = get_android_dt_dir() + "/fstab"; + std::string fstabdir_name = GetAndroidDtDir() + "fstab"; std::unique_ptr fstabdir(opendir(fstabdir_name.c_str()), closedir); if (!fstabdir) return {}; @@ -876,7 +864,7 @@ const FstabEntry* GetEntryForMountPoint(const Fstab* fstab, const std::string& p std::set GetBootDevices() { // First check bootconfig, then kernel commandline, then the device tree - std::string dt_file_name = get_android_dt_dir() + "/boot_devices"; + std::string dt_file_name = GetAndroidDtDir() + "boot_devices"; std::string value; if (fs_mgr_get_boot_config_from_bootconfig_source("boot_devices", &value) || fs_mgr_get_boot_config_from_bootconfig_source("boot_device", &value)) { @@ -948,15 +936,8 @@ bool InRecovery() { } // namespace fs_mgr } // namespace android -// FIXME: The same logic is duplicated in system/core/init/ -const std::string& get_android_dt_dir() { - // Set once and saves time for subsequent calls to this function - static const std::string kAndroidDtDir = android::fs_mgr::InitAndroidDtDir(); - return kAndroidDtDir; -} - bool is_dt_compatible() { - std::string file_name = get_android_dt_dir() + "/compatible"; + std::string file_name = android::fs_mgr::GetAndroidDtDir() + "compatible"; std::string dt_value; if (android::fs_mgr::ReadDtFile(file_name, &dt_value)) { if (dt_value == "android,firmware") { diff --git a/fs_mgr/libfstab/fstab_priv.h b/fs_mgr/libfstab/fstab_priv.h index fb12b9fb1d1c..5d226f8798f6 100644 --- a/fs_mgr/libfstab/fstab_priv.h +++ b/fs_mgr/libfstab/fstab_priv.h @@ -36,7 +36,6 @@ bool fs_mgr_get_boot_config_from_bootconfig(const std::string& bootconfig, const bool fs_mgr_get_boot_config_from_bootconfig_source(const std::string& key, std::string* out_val); bool fs_mgr_update_for_slotselect(android::fs_mgr::Fstab* fstab); -const std::string& get_android_dt_dir(); bool is_dt_compatible(); namespace android { diff --git a/fs_mgr/libfstab/include/fstab/fstab.h b/fs_mgr/libfstab/include/fstab/fstab.h index e0683ac284cb..0a45fe87ad3e 100644 --- a/fs_mgr/libfstab/include/fstab/fstab.h +++ b/fs_mgr/libfstab/include/fstab/fstab.h @@ -124,5 +124,9 @@ std::set GetBootDevices(); // expected name. std::string GetVerityDeviceName(const FstabEntry& entry); +// Returns the Android Device Tree directory as specified in the kernel bootconfig or cmdline. +// If the platform does not configure a custom DT path, returns the standard one (based in procfs). +const std::string& GetAndroidDtDir(); + } // namespace fs_mgr } // namespace android diff --git a/init/Android.bp b/init/Android.bp index ee34215d750e..d4852d6483be 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -539,6 +539,7 @@ cc_defaults { "libprotobuf-cpp-lite", ], static_libs: [ + "libfs_mgr", "libhidl-gen-utils", ], } diff --git a/init/property_service.cpp b/init/property_service.cpp index 8da69822ccb9..0e82022a0e83 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -1317,7 +1318,8 @@ static void ProcessKernelDt() { return; } - std::unique_ptr dir(opendir(get_android_dt_dir().c_str()), closedir); + std::unique_ptr dir(opendir(android::fs_mgr::GetAndroidDtDir().c_str()), + closedir); if (!dir) return; std::string dt_file; @@ -1328,7 +1330,7 @@ static void ProcessKernelDt() { continue; } - std::string file_name = get_android_dt_dir() + dp->d_name; + std::string file_name = android::fs_mgr::GetAndroidDtDir() + dp->d_name; android::base::ReadFileToString(file_name, &dt_file); std::replace(dt_file.begin(), dt_file.end(), ',', '.'); diff --git a/init/util.cpp b/init/util.cpp index d0478e80d005..61d59a4801d0 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -42,6 +42,10 @@ #include #include +#if defined(__ANDROID__) +#include +#endif + #ifdef INIT_FULL_SOURCES #include #include @@ -60,8 +64,6 @@ using namespace std::literals::string_literals; namespace android { namespace init { -const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android/"); - const std::string kDataDirPrefix("/data/"); void (*trigger_shutdown)(const std::string& command) = nullptr; @@ -375,45 +377,18 @@ Result ExpandProps(const std::string& src) { return dst; } -static std::string init_android_dt_dir() { - // Use the standard procfs-based path by default - std::string android_dt_dir = kDefaultAndroidDtDir; - // The platform may specify a custom Android DT path in kernel cmdline - ImportKernelCmdline([&](const std::string& key, const std::string& value) { - if (key == "androidboot.android_dt_dir") { - android_dt_dir = value; - } - }); - // ..Or bootconfig - if (android_dt_dir == kDefaultAndroidDtDir) { - ImportBootconfig([&](const std::string& key, const std::string& value) { - if (key == "androidboot.android_dt_dir") { - android_dt_dir = value; - } - }); - } - - LOG(INFO) << "Using Android DT directory " << android_dt_dir; - return android_dt_dir; -} - -// FIXME: The same logic is duplicated in system/core/fs_mgr/ -const std::string& get_android_dt_dir() { - // Set once and saves time for subsequent calls to this function - static const std::string kAndroidDtDir = init_android_dt_dir(); - return kAndroidDtDir; -} - // Reads the content of device tree file under the platform's Android DT directory. // Returns true if the read is success, false otherwise. bool read_android_dt_file(const std::string& sub_path, std::string* dt_content) { - const std::string file_name = get_android_dt_dir() + sub_path; +#if defined(__ANDROID__) + const std::string file_name = android::fs_mgr::GetAndroidDtDir() + sub_path; if (android::base::ReadFileToString(file_name, dt_content)) { if (!dt_content->empty()) { dt_content->pop_back(); // Trims the trailing '\0' out. return true; } } +#endif return false; } diff --git a/init/util.h b/init/util.h index 3f0a4e023f08..1c00a3efc0b1 100644 --- a/init/util.h +++ b/init/util.h @@ -60,9 +60,6 @@ bool make_dir(const std::string& path, mode_t mode); bool is_dir(const char* pathname); Result ExpandProps(const std::string& src); -// Returns the platform's Android DT directory as specified in the kernel cmdline. -// If the platform does not configure a custom DT path, returns the standard one (based in procfs). -const std::string& get_android_dt_dir(); // Reads or compares the content of device tree file under the platform's Android DT directory. bool read_android_dt_file(const std::string& sub_path, std::string* dt_content); bool is_android_dt_value_expected(const std::string& sub_path, const std::string& expected_content); From a637416a87c0ac5444bd0fa33d484790deb94294 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 23 Jul 2023 10:00:40 -0700 Subject: [PATCH 0258/1487] libsnapshot: Introduce a dynamically linked version of libsnapshot. This will cut down on the binary sizes of update_engine, snapshotctl, and lpdumpd. Bug: 291688516 Test: treehugger Change-Id: Idae5ea075ab21c2bd4fdb839eb065d865cb07d58 --- fs_mgr/libfiemap/fiemap_writer_test.cpp | 4 +++- fs_mgr/libsnapshot/Android.bp | 26 +++++++++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/fs_mgr/libfiemap/fiemap_writer_test.cpp b/fs_mgr/libfiemap/fiemap_writer_test.cpp index bd97a78ae8f7..c37329c36e40 100644 --- a/fs_mgr/libfiemap/fiemap_writer_test.cpp +++ b/fs_mgr/libfiemap/fiemap_writer_test.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -518,7 +519,8 @@ class FsTest : public ::testing::Test { ASSERT_EQ(ret, 0); // mount the file system - ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint_.c_str(), "f2fs", 0, nullptr), 0); + ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint_.c_str(), "f2fs", 0, nullptr), 0) + << strerror(errno); } void TearDown() override { diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index 8f353818ce08..bd017ff10bfa 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -101,7 +101,7 @@ cc_library_headers { } cc_library_static { - name: "libsnapshot", + name: "libsnapshot_static", defaults: [ "libsnapshot_defaults", "libsnapshot_hal_deps", @@ -112,6 +112,25 @@ cc_library_static { ], } +cc_library { + name: "libsnapshot", + defaults: [ + "libsnapshot_defaults", + "libsnapshot_cow_defaults", + "libsnapshot_hal_deps", + ], + srcs: [":libsnapshot_sources"], + shared_libs: [ + "libfs_mgr_binder", + "liblp", + "libprotobuf-cpp-lite", + ], + static_libs: [ + "libc++fs", + "libsnapshot_cow", + ] +} + cc_library_static { name: "libsnapshot_init", native_coverage : true, @@ -247,7 +266,7 @@ cc_defaults { "libgsi", "libgmock", "liblp", - "libsnapshot", + "libsnapshot_static", "libsnapshot_cow", "libsnapshot_test_helpers", "libsparse", @@ -330,8 +349,6 @@ cc_binary { "libbrotli", "libc++fs", "libfstab", - "libsnapshot", - "libsnapshot_cow", "libz", "update_metadata-protos", ], @@ -344,6 +361,7 @@ cc_binary { "liblog", "liblp", "libprotobuf-cpp-lite", + "libsnapshot", "libstatslog", "libutils", ], From 79ad1e2e9bf1628c141c8cd2fbb4f3df61a6ba75 Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Sat, 29 Jul 2023 17:37:23 +0800 Subject: [PATCH 0259/1487] init: Unify kernel bootconfig parser with libfs_mgr Right now there are two bootconfig parsers that gets linked into `init`. One is from libinit itself and the other is from libfs_mgr. The one in libinit removes all space characters between list elements, so `key = "val1", "val2"` gets unquoted and squeezed into: `key=val1,val2` The one in libfs_mgr doesn't remove spaces, it only unquotes: `key=val1, val2` The libinit behavior is due to existing systems (such as sysprop) expect the config value to be in the same format as kernel cmdline. (aosp/1757971) THe libfs_mgr behavior is due to the `androidboot.boot_device[s]` format explicitly allows quoted comma appear in its list value, thus relies on space, not comma, as the list value delimeter. This commit merges the two parsers into libfs_mgr. Since all usages in libfs_mgr besides `boot_device[s]` do not care about how list value are delimited, and most usages in init expects the bootconfig value format to be the same format as cmdline. We just special case the `boot_device` scenario. Also harden the test cases to cover all the different config value format and expected result. Note: The format of kernel bootconfig is described here https://docs.kernel.org/admin-guide/bootconfig.html Bug: 293695109 Test: CtsFsMgrTestCases Change-Id: I42b9bf626e8de38a60e8e09fac0693126b7efd91 --- fs_mgr/libfstab/boot_config.cpp | 113 ++++++++++++++------------ fs_mgr/libfstab/fstab.cpp | 12 ++- fs_mgr/libfstab/fstab_priv.h | 12 +-- fs_mgr/libfstab/include/fstab/fstab.h | 9 ++ fs_mgr/tests/Android.bp | 2 + fs_mgr/tests/fs_mgr_test.cpp | 112 +++++++++++++++---------- init/devices.cpp | 3 +- init/property_service.cpp | 2 +- init/reboot_utils.cpp | 17 ++-- init/selinux.cpp | 10 +-- init/util.cpp | 15 ---- init/util.h | 1 - 12 files changed, 165 insertions(+), 143 deletions(-) diff --git a/fs_mgr/libfstab/boot_config.cpp b/fs_mgr/libfstab/boot_config.cpp index fee40158b709..53c843e9338e 100644 --- a/fs_mgr/libfstab/boot_config.cpp +++ b/fs_mgr/libfstab/boot_config.cpp @@ -34,7 +34,7 @@ const std::string& GetAndroidDtDir() { // Set once and saves time for subsequent calls to this function static const std::string kAndroidDtDir = [] { std::string android_dt_dir; - if ((fs_mgr_get_boot_config_from_bootconfig_source("android_dt_dir", &android_dt_dir) || + if ((GetBootconfig("androidboot.android_dt_dir", &android_dt_dir) || fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) && !android_dt_dir.empty()) { // Ensure the returned path ends with a / @@ -51,6 +51,65 @@ const std::string& GetAndroidDtDir() { return kAndroidDtDir; } +void ImportBootconfigFromString(const std::string& bootconfig, + const std::function& fn) { + for (std::string_view line : android::base::Split(bootconfig, "\n")) { + const auto equal_pos = line.find('='); + std::string key = android::base::Trim(line.substr(0, equal_pos)); + if (key.empty()) { + continue; + } + std::string value; + if (equal_pos != line.npos) { + value = android::base::Trim(line.substr(equal_pos + 1)); + // If the value is a comma-delimited list, the kernel would insert a space between the + // list elements when read from /proc/bootconfig. + // BoardConfig.mk: + // BOARD_BOOTCONFIG := key=value1,value2,value3 + // /proc/bootconfig: + // key = "value1", "value2", "value3" + if (key == "androidboot.boot_device" || key == "androidboot.boot_devices") { + // boot_device[s] is a special case where a list element can contain comma and the + // caller expects a space-delimited list, so don't remove space here. + value.erase(std::remove(value.begin(), value.end(), '"'), value.end()); + } else { + // In order to not break the expectations of existing code, we modify the value to + // keep the format consistent with the kernel cmdline by removing quote and space. + std::string_view sv(value); + android::base::ConsumePrefix(&sv, "\""); + android::base::ConsumeSuffix(&sv, "\""); + value = android::base::StringReplace(sv, R"(", ")", ",", true); + } + } + // "key" and "key =" means empty value. + fn(std::move(key), std::move(value)); + } +} + +bool GetBootconfigFromString(const std::string& bootconfig, const std::string& key, + std::string* out) { + bool found = false; + ImportBootconfigFromString(bootconfig, [&](std::string config_key, std::string value) { + if (!found && config_key == key) { + *out = std::move(value); + found = true; + } + }); + return found; +} + +void ImportBootconfig(const std::function& fn) { + std::string bootconfig; + android::base::ReadFileToString("/proc/bootconfig", &bootconfig); + ImportBootconfigFromString(bootconfig, fn); +} + +bool GetBootconfig(const std::string& key, std::string* out) { + std::string bootconfig; + android::base::ReadFileToString("/proc/bootconfig", &bootconfig); + return GetBootconfigFromString(bootconfig, key, out); +} + } // namespace fs_mgr } // namespace android @@ -88,44 +147,6 @@ std::vector> fs_mgr_parse_cmdline(const std: return result; } -std::vector> fs_mgr_parse_proc_bootconfig( - const std::string& cmdline) { - static constexpr char quote = '"'; - - std::vector> result; - for (auto& line : android::base::Split(cmdline, "\n")) { - line.erase(std::remove(line.begin(), line.end(), quote), line.end()); - auto equal_sign = line.find('='); - if (equal_sign == line.npos) { - if (!line.empty()) { - // no difference between and = - result.emplace_back(std::move(line), ""); - } - } else { - result.emplace_back(android::base::Trim(line.substr(0, equal_sign)), - android::base::Trim(line.substr(equal_sign + 1))); - } - } - - return result; -} - -bool fs_mgr_get_boot_config_from_bootconfig(const std::string& bootconfig, - const std::string& android_key, std::string* out_val) { - FSTAB_CHECK(out_val != nullptr); - - const std::string bootconfig_key("androidboot." + android_key); - for (const auto& [key, value] : fs_mgr_parse_proc_bootconfig(bootconfig)) { - if (key == bootconfig_key) { - *out_val = value; - return true; - } - } - - *out_val = ""; - return false; -} - bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::string& android_key, std::string* out_val) { FSTAB_CHECK(out_val != nullptr); @@ -142,17 +163,6 @@ bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::s return false; } -// Tries to get the given boot config value from bootconfig. -// Returns true if successfully found, false otherwise. -bool fs_mgr_get_boot_config_from_bootconfig_source(const std::string& key, std::string* out_val) { - std::string bootconfig; - if (!android::base::ReadFileToString("/proc/bootconfig", &bootconfig)) return false; - if (!bootconfig.empty() && bootconfig.back() == '\n') { - bootconfig.pop_back(); - } - return fs_mgr_get_boot_config_from_bootconfig(bootconfig, key, out_val); -} - // Tries to get the given boot config value from kernel cmdline. // Returns true if successfully found, false otherwise. bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val) { @@ -188,7 +198,8 @@ bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) { } // next, check if we have the property in bootconfig - if (fs_mgr_get_boot_config_from_bootconfig_source(key, out_val)) { + const std::string config_key = "androidboot." + key; + if (android::fs_mgr::GetBootconfig(config_key, out_val)) { return true; } diff --git a/fs_mgr/libfstab/fstab.cpp b/fs_mgr/libfstab/fstab.cpp index 86ba03148838..3cbd8c819e9e 100644 --- a/fs_mgr/libfstab/fstab.cpp +++ b/fs_mgr/libfstab/fstab.cpp @@ -864,21 +864,19 @@ const FstabEntry* GetEntryForMountPoint(const Fstab* fstab, const std::string& p std::set GetBootDevices() { // First check bootconfig, then kernel commandline, then the device tree - std::string dt_file_name = GetAndroidDtDir() + "boot_devices"; std::string value; - if (fs_mgr_get_boot_config_from_bootconfig_source("boot_devices", &value) || - fs_mgr_get_boot_config_from_bootconfig_source("boot_device", &value)) { + if (GetBootconfig("androidboot.boot_devices", &value) || + GetBootconfig("androidboot.boot_device", &value)) { std::set boot_devices; - // remove quotes and split by spaces - auto boot_device_strings = base::Split(base::StringReplace(value, "\"", "", true), " "); - for (std::string_view device : boot_device_strings) { - // trim the trailing comma, keep the rest. + // split by spaces and trim the trailing comma. + for (std::string_view device : android::base::Split(value, " ")) { base::ConsumeSuffix(&device, ","); boot_devices.emplace(device); } return boot_devices; } + std::string dt_file_name = GetAndroidDtDir() + "boot_devices"; if (fs_mgr_get_boot_config_from_kernel_cmdline("boot_devices", &value) || ReadDtFile(dt_file_name, &value)) { auto boot_devices = Split(value, ","); diff --git a/fs_mgr/libfstab/fstab_priv.h b/fs_mgr/libfstab/fstab_priv.h index 5d226f8798f6..cc5682567548 100644 --- a/fs_mgr/libfstab/fstab_priv.h +++ b/fs_mgr/libfstab/fstab_priv.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include @@ -29,11 +30,6 @@ bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::s std::string* out_val); bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val); bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val); -std::vector> fs_mgr_parse_proc_bootconfig( - const std::string& bootconfig); -bool fs_mgr_get_boot_config_from_bootconfig(const std::string& bootconfig, const std::string& key, - std::string* out_val); -bool fs_mgr_get_boot_config_from_bootconfig_source(const std::string& key, std::string* out_val); bool fs_mgr_update_for_slotselect(android::fs_mgr::Fstab* fstab); bool is_dt_compatible(); @@ -46,5 +42,11 @@ bool ParseFstabFromString(const std::string& fstab_str, bool proc_mounts, Fstab* bool SkipMountWithConfig(const std::string& skip_config, Fstab* fstab, bool verbose); std::string GetFstabPath(); +void ImportBootconfigFromString(const std::string& bootconfig, + const std::function& fn); + +bool GetBootconfigFromString(const std::string& bootconfig, const std::string& key, + std::string* out); + } // namespace fs_mgr } // namespace android diff --git a/fs_mgr/libfstab/include/fstab/fstab.h b/fs_mgr/libfstab/include/fstab/fstab.h index 0a45fe87ad3e..79a07eef2a14 100644 --- a/fs_mgr/libfstab/include/fstab/fstab.h +++ b/fs_mgr/libfstab/include/fstab/fstab.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -128,5 +129,13 @@ std::string GetVerityDeviceName(const FstabEntry& entry); // If the platform does not configure a custom DT path, returns the standard one (based in procfs). const std::string& GetAndroidDtDir(); +// Import the kernel bootconfig by calling the callback |fn| with each key-value pair. +void ImportBootconfig(const std::function& fn); + +// Get the kernel bootconfig value for |key|. +// Returns true if |key| is found in bootconfig. +// Otherwise returns false and |*out| is not modified. +bool GetBootconfig(const std::string& key, std::string* out); + } // namespace fs_mgr } // namespace android diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp index b7f792fe6235..2aeba0acd6a1 100644 --- a/fs_mgr/tests/Android.bp +++ b/fs_mgr/tests/Android.bp @@ -38,6 +38,8 @@ cc_test { ], static_libs: [ "libfs_mgr", + "libgmock", + "libgtest", ], srcs: [ "file_wait_test.cpp", diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp index c51df2a7ef1a..fbed3716074a 100644 --- a/fs_mgr/tests/fs_mgr_test.cpp +++ b/fs_mgr/tests/fs_mgr_test.cpp @@ -29,11 +29,13 @@ #include #include #include +#include #include #include "../fs_mgr_priv.h" using namespace android::fs_mgr; +using namespace testing; namespace { @@ -119,37 +121,42 @@ const std::vector> result_space = { {"terminator", "truncated"}, }; -const std::string bootconfig = - "androidboot.bootdevice = \"1d84000.ufshc\"\n" - "androidboot.boot_devices = \"dev1\", \"dev2,withcomma\", \"dev3\"\n" - "androidboot.baseband = \"sdy\"\n" - "androidboot.keymaster = \"1\"\n" - "androidboot.serialno = \"BLAHBLAHBLAH\"\n" - "androidboot.slot_suffix = \"_a\"\n" - "androidboot.hardware.platform = \"sdw813\"\n" - "androidboot.hardware = \"foo\"\n" - "androidboot.revision = \"EVT1.0\"\n" - "androidboot.bootloader = \"burp-0.1-7521\"\n" - "androidboot.hardware.sku = \"mary\"\n" - "androidboot.hardware.radio.subtype = \"0\"\n" - "androidboot.dtbo_idx = \"2\"\n" - "androidboot.mode = \"normal\"\n" - "androidboot.hardware.ddr = \"1GB,combuchi,LPDDR4X\"\n" - "androidboot.ddr_info = \"combuchiandroidboot.ddr_size=2GB\"\n" - "androidboot.hardware.ufs = \"2GB,combushi\"\n" - "androidboot.boottime = \"0BLE:58,1BLL:22,1BLE:571,2BLL:105,ODT:0,AVB:123\"\n" - "androidboot.ramdump = \"disabled\"\n" - "androidboot.vbmeta.device = \"PARTUUID=aa08f1a4-c7c9-402e-9a66-9707cafa9ceb\"\n" - "androidboot.vbmeta.avb_version = \"1.1\"\n" - "androidboot.vbmeta.device_state = \"unlocked\"\n" - "androidboot.vbmeta.hash_alg = \"sha256\"\n" - "androidboot.vbmeta.size = \"5248\"\n" - "androidboot.vbmeta.digest = \"" - "ac13147e959861c20f2a6da97d25fe79e60e902c022a371c5c039d31e7c68860\"\n" - "androidboot.vbmeta.invalidate_on_error = \"yes\"\n" - "androidboot.veritymode = \"enforcing\"\n" - "androidboot.verifiedbootstate = \"orange\"\n" - "androidboot.space = \"sha256 5248 androidboot.nospace = nope\"\n"; +const std::string bootconfig = R"( +androidboot.bootdevice = "1d84000.ufshc" +androidboot.boot_devices = "dev1", "dev2,withcomma", "dev3" +androidboot.baseband = "sdy" +androidboot.keymaster = "1" +androidboot.serialno = "BLAHBLAHBLAH" +androidboot.slot_suffix = "_a" +androidboot.hardware.platform = "sdw813" +androidboot.hardware = "foo" +androidboot.revision = "EVT1.0" +androidboot.bootloader = "burp-0.1-7521" +androidboot.hardware.sku = "mary" +androidboot.hardware.radio.subtype = "0" +androidboot.dtbo_idx = "2" +androidboot.mode = "normal" +androidboot.hardware.ddr = "1GB,combuchi,LPDDR4X" +androidboot.ddr_info = "combuchiandroidboot.ddr_size=2GB" +androidboot.hardware.ufs = "2GB,combushi" +androidboot.boottime = "0BLE:58,1BLL:22,1BLE:571,2BLL:105,ODT:0,AVB:123" +androidboot.ramdump = "disabled" +androidboot.vbmeta.device = "PARTUUID=aa08f1a4-c7c9-402e-9a66-9707cafa9ceb" +androidboot.vbmeta.avb_version = "1.1" +androidboot.vbmeta.device_state = "unlocked" +androidboot.vbmeta.hash_alg = "sha256" +androidboot.vbmeta.size = "5248" +androidboot.vbmeta.digest = "ac13147e959861c20f2a6da97d25fe79e60e902c022a371c5c039d31e7c68860" +androidboot.vbmeta.invalidate_on_error = "yes" +androidboot.veritymode = "enforcing" +androidboot.verifiedbootstate = "orange" +androidboot.space = "sha256 5248 androidboot.nospace = nope" +just.key +key.empty.value = +dessert.value = "ice, cream" +dessert.list = "ice", "cream" +ambiguous.list = ", ", ", " +)"; const std::vector> bootconfig_result_space = { {"androidboot.bootdevice", "1d84000.ufshc"}, @@ -182,6 +189,11 @@ const std::vector> bootconfig_result_space = {"androidboot.veritymode", "enforcing"}, {"androidboot.verifiedbootstate", "orange"}, {"androidboot.space", "sha256 5248 androidboot.nospace = nope"}, + {"just.key", ""}, + {"key.empty.value", ""}, + {"dessert.value", "ice, cream"}, + {"dessert.list", "ice,cream"}, + {"ambiguous.list", ", ,, "}, }; bool CompareFlags(FstabEntry::FsMgrFlags& lhs, FstabEntry::FsMgrFlags& rhs) { @@ -231,25 +243,35 @@ TEST(fs_mgr, fs_mgr_get_boot_config_from_kernel_cmdline) { EXPECT_TRUE(content.empty()) << content; } -TEST(fs_mgr, fs_mgr_parse_bootconfig) { - EXPECT_EQ(bootconfig_result_space, fs_mgr_parse_proc_bootconfig(bootconfig)); +TEST(fs_mgr, ImportBootconfig) { + std::vector> result; + ImportBootconfigFromString(bootconfig, [&](std::string key, std::string value) { + result.emplace_back(key, value); + }); + EXPECT_THAT(result, ContainerEq(bootconfig_result_space)); } -TEST(fs_mgr, fs_mgr_get_boot_config_from_bootconfig) { +TEST(fs_mgr, GetBootconfig) { std::string content; - for (const auto& entry : bootconfig_result_space) { - static constexpr char androidboot[] = "androidboot."; - if (!android::base::StartsWith(entry.first, androidboot)) continue; - auto key = entry.first.substr(strlen(androidboot)); - EXPECT_TRUE(fs_mgr_get_boot_config_from_bootconfig(bootconfig, key, &content)) - << " for " << key; - EXPECT_EQ(entry.second, content); + for (const auto& [key, value] : bootconfig_result_space) { + EXPECT_TRUE(GetBootconfigFromString(bootconfig, key, &content)) << " for " << key; + EXPECT_EQ(content, value); } - EXPECT_FALSE(fs_mgr_get_boot_config_from_bootconfig(bootconfig, "vbmeta.avb_versio", &content)); - EXPECT_TRUE(content.empty()) << content; - EXPECT_FALSE(fs_mgr_get_boot_config_from_bootconfig(bootconfig, "nospace", &content)); - EXPECT_TRUE(content.empty()) << content; + const std::string kUnmodifiedToken = ""; + content = kUnmodifiedToken; + EXPECT_FALSE(android::fs_mgr::GetBootconfigFromString(bootconfig, "", &content)); + EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden"; + + content = kUnmodifiedToken; + EXPECT_FALSE(android::fs_mgr::GetBootconfigFromString( + bootconfig, "androidboot.vbmeta.avb_versio", &content)); + EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden"; + + content = kUnmodifiedToken; + EXPECT_FALSE( + android::fs_mgr::GetBootconfigFromString(bootconfig, "androidboot.nospace", &content)); + EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden"; } TEST(fs_mgr, fs_mgr_read_fstab_file_proc_mounts) { diff --git a/init/devices.cpp b/init/devices.cpp index 7c234924b450..6b8474eaa302 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -204,7 +205,7 @@ std::string DeviceHandler::GetPartitionNameForDevice(const std::string& query_de } }; ImportKernelCmdline(parser); - ImportBootconfig(parser); + android::fs_mgr::ImportBootconfig(parser); return partition_map; }(); diff --git a/init/property_service.cpp b/init/property_service.cpp index 0e82022a0e83..35577874f6da 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -1351,7 +1351,7 @@ static void ProcessKernelCmdline() { static void ProcessBootconfig() { - ImportBootconfig([&](const std::string& key, const std::string& value) { + android::fs_mgr::ImportBootconfig([&](const std::string& key, const std::string& value) { if (StartsWith(key, ANDROIDBOOT_PREFIX)) { InitPropertySet("ro.boot." + key.substr(ANDROIDBOOT_PREFIX.size()), value); } diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp index e6b868e797ae..547b1869f3c4 100644 --- a/init/reboot_utils.cpp +++ b/init/reboot_utils.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "capabilities.h" @@ -48,13 +49,9 @@ void SetFatalRebootTarget(const std::optional& reboot_target) { const std::string kInitFatalPanicParamString = "androidboot.init_fatal_panic"; if (cmdline.find(kInitFatalPanicParamString) == std::string::npos) { - init_fatal_panic = false; - ImportBootconfig( - [kInitFatalPanicParamString](const std::string& key, const std::string& value) { - if (key == kInitFatalPanicParamString && value == "true") { - init_fatal_panic = true; - } - }); + std::string value; + init_fatal_panic = (android::fs_mgr::GetBootconfig(kInitFatalPanicParamString, &value) && + value == "true"); } else { const std::string kInitFatalPanicString = kInitFatalPanicParamString + "=true"; init_fatal_panic = cmdline.find(kInitFatalPanicString) != std::string::npos; @@ -68,11 +65,7 @@ void SetFatalRebootTarget(const std::optional& reboot_target) { const std::string kRebootTargetString = "androidboot.init_fatal_reboot_target"; auto start_pos = cmdline.find(kRebootTargetString); if (start_pos == std::string::npos) { - ImportBootconfig([kRebootTargetString](const std::string& key, const std::string& value) { - if (key == kRebootTargetString) { - init_fatal_reboot_target = value; - } - }); + android::fs_mgr::GetBootconfig(kRebootTargetString, &init_fatal_reboot_target); // We already default to bootloader if no setting is provided. } else { const std::string kRebootTargetStringPattern = kRebootTargetString + "="; diff --git a/init/selinux.cpp b/init/selinux.cpp index 51093d898e8b..6fb028b169fe 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -110,11 +110,11 @@ EnforcingStatus StatusFromProperty() { }); if (status == SELINUX_ENFORCING) { - ImportBootconfig([&](const std::string& key, const std::string& value) { - if (key == "androidboot.selinux" && value == "permissive") { - status = SELINUX_PERMISSIVE; - } - }); + std::string value; + if (android::fs_mgr::GetBootconfig("androidboot.selinux", &value) && + value == "permissive") { + status = SELINUX_PERMISSIVE; + } } return status; diff --git a/init/util.cpp b/init/util.cpp index 61d59a4801d0..b34d45d70f42 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -254,21 +254,6 @@ void ImportKernelCmdline(const std::function& fn) { - std::string bootconfig; - android::base::ReadFileToString("/proc/bootconfig", &bootconfig); - - for (const auto& entry : android::base::Split(bootconfig, "\n")) { - std::vector pieces = android::base::Split(entry, "="); - if (pieces.size() == 2) { - // get rid of the extra space between a list of values and remove the quotes. - std::string value = android::base::StringReplace(pieces[1], "\", \"", ",", true); - value.erase(std::remove(value.begin(), value.end(), '"'), value.end()); - fn(android::base::Trim(pieces[0]), android::base::Trim(value)); - } - } -} - bool make_dir(const std::string& path, mode_t mode) { std::string secontext; if (SelabelLookupFileContext(path, mode, &secontext) && !secontext.empty()) { diff --git a/init/util.h b/init/util.h index 1c00a3efc0b1..0b0ef632b109 100644 --- a/init/util.h +++ b/init/util.h @@ -55,7 +55,6 @@ Result DecodeUid(const std::string& name); bool mkdir_recursive(const std::string& pathname, mode_t mode); int wait_for_file(const char *filename, std::chrono::nanoseconds timeout); void ImportKernelCmdline(const std::function&); -void ImportBootconfig(const std::function&); bool make_dir(const std::string& path, mode_t mode); bool is_dir(const char* pathname); Result ExpandProps(const std::string& src); From da5323e2d6be16470b7ce2be118d41a497c7d9a6 Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Wed, 2 Aug 2023 01:08:23 +0800 Subject: [PATCH 0260/1487] init: Use libfs_mgr kernel cmdline parser Bug: 293695109 Test: CtsFsMgrTestCases Change-Id: Ie2567d84cb80c392ad68aef0c438d8acc03a311e --- fs_mgr/libfstab/boot_config.cpp | 65 ++++++++++++--------------- fs_mgr/libfstab/fstab.cpp | 28 +++++------- fs_mgr/libfstab/fstab_priv.h | 12 ++--- fs_mgr/libfstab/include/fstab/fstab.h | 8 ++++ fs_mgr/tests/fs_mgr_test.cpp | 43 ++++++++++-------- init/devices.cpp | 2 +- init/property_service.cpp | 2 +- init/selinux.cpp | 23 +++------- init/util.cpp | 12 ----- init/util.h | 3 +- 10 files changed, 89 insertions(+), 109 deletions(-) diff --git a/fs_mgr/libfstab/boot_config.cpp b/fs_mgr/libfstab/boot_config.cpp index 53c843e9338e..ae537b5d2560 100644 --- a/fs_mgr/libfstab/boot_config.cpp +++ b/fs_mgr/libfstab/boot_config.cpp @@ -17,11 +17,9 @@ #include #include #include -#include #include #include -#include #include #include "fstab_priv.h" @@ -35,7 +33,7 @@ const std::string& GetAndroidDtDir() { static const std::string kAndroidDtDir = [] { std::string android_dt_dir; if ((GetBootconfig("androidboot.android_dt_dir", &android_dt_dir) || - fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) && + GetKernelCmdline("androidboot.android_dt_dir", &android_dt_dir)) && !android_dt_dir.empty()) { // Ensure the returned path ends with a / if (android_dt_dir.back() != '/') { @@ -110,13 +108,10 @@ bool GetBootconfig(const std::string& key, std::string* out) { return GetBootconfigFromString(bootconfig, key, out); } -} // namespace fs_mgr -} // namespace android - -std::vector> fs_mgr_parse_cmdline(const std::string& cmdline) { +void ImportKernelCmdlineFromString(const std::string& cmdline, + const std::function& fn) { static constexpr char quote = '"'; - std::vector> result; size_t base = 0; while (true) { // skip quoted spans @@ -135,48 +130,46 @@ std::vector> fs_mgr_parse_cmdline(const std: if (equal_sign == piece.npos) { if (!piece.empty()) { // no difference between and = - result.emplace_back(std::move(piece), ""); + fn(std::move(piece), ""); } } else { - result.emplace_back(piece.substr(0, equal_sign), piece.substr(equal_sign + 1)); + fn(piece.substr(0, equal_sign), piece.substr(equal_sign + 1)); } if (found == cmdline.npos) break; base = found + 1; } - - return result; } -bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::string& android_key, - std::string* out_val) { - FSTAB_CHECK(out_val != nullptr); - - const std::string cmdline_key("androidboot." + android_key); - for (const auto& [key, value] : fs_mgr_parse_cmdline(cmdline)) { - if (key == cmdline_key) { - *out_val = value; - return true; +bool GetKernelCmdlineFromString(const std::string& cmdline, const std::string& key, + std::string* out) { + bool found = false; + ImportKernelCmdlineFromString(cmdline, [&](std::string config_key, std::string value) { + if (!found && config_key == key) { + *out = std::move(value); + found = true; } - } + }); + return found; +} - *out_val = ""; - return false; +void ImportKernelCmdline(const std::function& fn) { + std::string cmdline; + android::base::ReadFileToString("/proc/cmdline", &cmdline); + ImportKernelCmdlineFromString(android::base::Trim(cmdline), fn); } -// Tries to get the given boot config value from kernel cmdline. -// Returns true if successfully found, false otherwise. -bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val) { +bool GetKernelCmdline(const std::string& key, std::string* out) { std::string cmdline; - if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) return false; - if (!cmdline.empty() && cmdline.back() == '\n') { - cmdline.pop_back(); - } - return fs_mgr_get_boot_config_from_kernel(cmdline, key, out_val); + android::base::ReadFileToString("/proc/cmdline", &cmdline); + return GetKernelCmdlineFromString(android::base::Trim(cmdline), key, out); } -// Tries to get the boot config value in device tree, properties and -// kernel cmdline (in that order). Returns 'true' if successfully -// found, 'false' otherwise. +} // namespace fs_mgr +} // namespace android + +// Tries to get the boot config value in device tree, properties, kernel bootconfig and kernel +// cmdline (in that order). +// Returns 'true' if successfully found, 'false' otherwise. bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) { FSTAB_CHECK(out_val != nullptr); @@ -204,7 +197,7 @@ bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) { } // finally, fallback to kernel cmdline, properties may not be ready yet - if (fs_mgr_get_boot_config_from_kernel_cmdline(key, out_val)) { + if (android::fs_mgr::GetKernelCmdline(config_key, out_val)) { return true; } diff --git a/fs_mgr/libfstab/fstab.cpp b/fs_mgr/libfstab/fstab.cpp index 3cbd8c819e9e..21b002434391 100644 --- a/fs_mgr/libfstab/fstab.cpp +++ b/fs_mgr/libfstab/fstab.cpp @@ -863,11 +863,11 @@ const FstabEntry* GetEntryForMountPoint(const Fstab* fstab, const std::string& p } std::set GetBootDevices() { + std::set boot_devices; // First check bootconfig, then kernel commandline, then the device tree std::string value; if (GetBootconfig("androidboot.boot_devices", &value) || GetBootconfig("androidboot.boot_device", &value)) { - std::set boot_devices; // split by spaces and trim the trailing comma. for (std::string_view device : android::base::Split(value, " ")) { base::ConsumeSuffix(&device, ","); @@ -876,25 +876,19 @@ std::set GetBootDevices() { return boot_devices; } - std::string dt_file_name = GetAndroidDtDir() + "boot_devices"; - if (fs_mgr_get_boot_config_from_kernel_cmdline("boot_devices", &value) || - ReadDtFile(dt_file_name, &value)) { - auto boot_devices = Split(value, ","); - return std::set(boot_devices.begin(), boot_devices.end()); + const std::string dt_file_name = GetAndroidDtDir() + "boot_devices"; + if (GetKernelCmdline("androidboot.boot_devices", &value) || ReadDtFile(dt_file_name, &value)) { + auto boot_devices_list = Split(value, ","); + return {boot_devices_list.begin(), boot_devices_list.end()}; } - std::string cmdline; - if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) { - std::set boot_devices; - const std::string cmdline_key = "androidboot.boot_device"; - for (const auto& [key, value] : fs_mgr_parse_cmdline(cmdline)) { - if (key == cmdline_key) { - boot_devices.emplace(value); - } - } - if (!boot_devices.empty()) { - return boot_devices; + ImportKernelCmdline([&](std::string key, std::string value) { + if (key == "androidboot.boot_device") { + boot_devices.emplace(std::move(value)); } + }); + if (!boot_devices.empty()) { + return boot_devices; } // Fallback to extract boot devices from fstab. diff --git a/fs_mgr/libfstab/fstab_priv.h b/fs_mgr/libfstab/fstab_priv.h index cc5682567548..5105da001031 100644 --- a/fs_mgr/libfstab/fstab_priv.h +++ b/fs_mgr/libfstab/fstab_priv.h @@ -18,17 +18,11 @@ #include #include -#include -#include #include // Do not include logging_macros.h here as this header is used by fs_mgr, too. -std::vector> fs_mgr_parse_cmdline(const std::string& cmdline); -bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::string& key, - std::string* out_val); -bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val); bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val); bool fs_mgr_update_for_slotselect(android::fs_mgr::Fstab* fstab); @@ -48,5 +42,11 @@ void ImportBootconfigFromString(const std::string& bootconfig, bool GetBootconfigFromString(const std::string& bootconfig, const std::string& key, std::string* out); +void ImportKernelCmdlineFromString(const std::string& cmdline, + const std::function& fn); + +bool GetKernelCmdlineFromString(const std::string& cmdline, const std::string& key, + std::string* out); + } // namespace fs_mgr } // namespace android diff --git a/fs_mgr/libfstab/include/fstab/fstab.h b/fs_mgr/libfstab/include/fstab/fstab.h index 79a07eef2a14..150a47da350c 100644 --- a/fs_mgr/libfstab/include/fstab/fstab.h +++ b/fs_mgr/libfstab/include/fstab/fstab.h @@ -137,5 +137,13 @@ void ImportBootconfig(const std::function& fn); // Otherwise returns false and |*out| is not modified. bool GetBootconfig(const std::string& key, std::string* out); +// Import the kernel cmdline by calling the callback |fn| with each key-value pair. +void ImportKernelCmdline(const std::function& fn); + +// Get the kernel cmdline value for |key|. +// Returns true if |key| is found in the kernel cmdline. +// Otherwise returns false and |*out| is not modified. +bool GetKernelCmdline(const std::string& key, std::string* out); + } // namespace fs_mgr } // namespace android diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp index fbed3716074a..322bf1b08930 100644 --- a/fs_mgr/tests/fs_mgr_test.cpp +++ b/fs_mgr/tests/fs_mgr_test.cpp @@ -224,23 +224,32 @@ bool CompareFlags(FstabEntry::FsMgrFlags& lhs, FstabEntry::FsMgrFlags& rhs) { } // namespace -TEST(fs_mgr, fs_mgr_parse_cmdline) { - EXPECT_EQ(result_space, fs_mgr_parse_cmdline(cmdline)); +TEST(fs_mgr, ImportKernelCmdline) { + std::vector> result; + ImportKernelCmdlineFromString( + cmdline, [&](std::string key, std::string value) { result.emplace_back(key, value); }); + EXPECT_THAT(result, ContainerEq(result_space)); } -TEST(fs_mgr, fs_mgr_get_boot_config_from_kernel_cmdline) { +TEST(fs_mgr, GetKernelCmdline) { std::string content; - for (const auto& entry : result_space) { - static constexpr char androidboot[] = "androidboot."; - if (!android::base::StartsWith(entry.first, androidboot)) continue; - auto key = entry.first.substr(strlen(androidboot)); - EXPECT_TRUE(fs_mgr_get_boot_config_from_kernel(cmdline, key, &content)) << " for " << key; - EXPECT_EQ(entry.second, content); + for (const auto& [key, value] : result_space) { + EXPECT_TRUE(GetKernelCmdlineFromString(cmdline, key, &content)) << " for " << key; + EXPECT_EQ(content, value); } - EXPECT_FALSE(fs_mgr_get_boot_config_from_kernel(cmdline, "vbmeta.avb_versio", &content)); - EXPECT_TRUE(content.empty()) << content; - EXPECT_FALSE(fs_mgr_get_boot_config_from_kernel(cmdline, "nospace", &content)); - EXPECT_TRUE(content.empty()) << content; + + const std::string kUnmodifiedToken = ""; + content = kUnmodifiedToken; + EXPECT_FALSE(GetKernelCmdlineFromString(cmdline, "", &content)); + EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden"; + + content = kUnmodifiedToken; + EXPECT_FALSE(GetKernelCmdlineFromString(cmdline, "androidboot.vbmeta.avb_versio", &content)); + EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden"; + + content = kUnmodifiedToken; + EXPECT_FALSE(GetKernelCmdlineFromString(bootconfig, "androidboot.nospace", &content)); + EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden"; } TEST(fs_mgr, ImportBootconfig) { @@ -260,17 +269,15 @@ TEST(fs_mgr, GetBootconfig) { const std::string kUnmodifiedToken = ""; content = kUnmodifiedToken; - EXPECT_FALSE(android::fs_mgr::GetBootconfigFromString(bootconfig, "", &content)); + EXPECT_FALSE(GetBootconfigFromString(bootconfig, "", &content)); EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden"; content = kUnmodifiedToken; - EXPECT_FALSE(android::fs_mgr::GetBootconfigFromString( - bootconfig, "androidboot.vbmeta.avb_versio", &content)); + EXPECT_FALSE(GetBootconfigFromString(bootconfig, "androidboot.vbmeta.avb_versio", &content)); EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden"; content = kUnmodifiedToken; - EXPECT_FALSE( - android::fs_mgr::GetBootconfigFromString(bootconfig, "androidboot.nospace", &content)); + EXPECT_FALSE(GetBootconfigFromString(bootconfig, "androidboot.nospace", &content)); EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden"; } diff --git a/init/devices.cpp b/init/devices.cpp index 6b8474eaa302..e76786a6d495 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -204,7 +204,7 @@ std::string DeviceHandler::GetPartitionNameForDevice(const std::string& query_de partition_map.emplace_back(map_pieces[0], map_pieces[1]); } }; - ImportKernelCmdline(parser); + android::fs_mgr::ImportKernelCmdline(parser); android::fs_mgr::ImportBootconfig(parser); return partition_map; }(); diff --git a/init/property_service.cpp b/init/property_service.cpp index 35577874f6da..f5de17d82bf1 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -1342,7 +1342,7 @@ static void ProcessKernelDt() { constexpr auto ANDROIDBOOT_PREFIX = "androidboot."sv; static void ProcessKernelCmdline() { - ImportKernelCmdline([&](const std::string& key, const std::string& value) { + android::fs_mgr::ImportKernelCmdline([&](const std::string& key, const std::string& value) { if (StartsWith(key, ANDROIDBOOT_PREFIX)) { InitPropertySet("ro.boot." + key.substr(ANDROIDBOOT_PREFIX.size()), value); } diff --git a/init/selinux.cpp b/init/selinux.cpp index 6fb028b169fe..f34474f85093 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -101,23 +101,14 @@ namespace { enum EnforcingStatus { SELINUX_PERMISSIVE, SELINUX_ENFORCING }; EnforcingStatus StatusFromProperty() { - EnforcingStatus status = SELINUX_ENFORCING; - - ImportKernelCmdline([&](const std::string& key, const std::string& value) { - if (key == "androidboot.selinux" && value == "permissive") { - status = SELINUX_PERMISSIVE; - } - }); - - if (status == SELINUX_ENFORCING) { - std::string value; - if (android::fs_mgr::GetBootconfig("androidboot.selinux", &value) && - value == "permissive") { - status = SELINUX_PERMISSIVE; - } + std::string value; + if (android::fs_mgr::GetKernelCmdline("androidboot.selinux", &value) && value == "permissive") { + return SELINUX_PERMISSIVE; } - - return status; + if (android::fs_mgr::GetBootconfig("androidboot.selinux", &value) && value == "permissive") { + return SELINUX_PERMISSIVE; + } + return SELINUX_ENFORCING; } bool IsEnforcing() { diff --git a/init/util.cpp b/init/util.cpp index b34d45d70f42..e760a5969f5a 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -242,18 +242,6 @@ int wait_for_file(const char* filename, std::chrono::nanoseconds timeout) { return -1; } -void ImportKernelCmdline(const std::function& fn) { - std::string cmdline; - android::base::ReadFileToString("/proc/cmdline", &cmdline); - - for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) { - std::vector pieces = android::base::Split(entry, "="); - if (pieces.size() == 2) { - fn(pieces[0], pieces[1]); - } - } -} - bool make_dir(const std::string& path, mode_t mode) { std::string secontext; if (SelabelLookupFileContext(path, mode, &secontext) && !secontext.empty()) { diff --git a/init/util.h b/init/util.h index 0b0ef632b109..2d021827165f 100644 --- a/init/util.h +++ b/init/util.h @@ -53,8 +53,7 @@ Result WriteFile(const std::string& path, const std::string& content); Result DecodeUid(const std::string& name); bool mkdir_recursive(const std::string& pathname, mode_t mode); -int wait_for_file(const char *filename, std::chrono::nanoseconds timeout); -void ImportKernelCmdline(const std::function&); +int wait_for_file(const char* filename, std::chrono::nanoseconds timeout); bool make_dir(const std::string& path, mode_t mode); bool is_dir(const char* pathname); Result ExpandProps(const std::string& src); From d865493814bb172d7100920b1cbce0b6ccfa17e7 Mon Sep 17 00:00:00 2001 From: "Ray-cy.lee" Date: Mon, 31 Jul 2023 20:00:43 +0800 Subject: [PATCH 0261/1487] Add snapuserd_ramdisk execute permission Bug: 294192189 Test: th Change-Id: I42ff176ffb7eae0ac05e7f9cc54090c82df982b5 --- libcutils/fs_config.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp index f90a1bc3ca98..26ac576070fc 100644 --- a/libcutils/fs_config.cpp +++ b/libcutils/fs_config.cpp @@ -214,6 +214,7 @@ static const struct fs_path_config android_files[] = { #endif { 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/resize2fs" }, { 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/snapuserd" }, + { 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/snapuserd_ramdisk" }, { 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/tune2fs" }, { 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/fsck.f2fs" }, // generic defaults From e54c0be60f5aa32ce06f4366a3c55db45c41093c Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Wed, 2 Aug 2023 15:18:35 +0800 Subject: [PATCH 0262/1487] libfstab: Optimize out C++ object copy * Edit / truncate string objects in-place, don't copy a temporary string object just for storing intermeidate results. * Replace copy construct semantics with move semantics. * Use range-based std::vector::insert() to move whole range. Bug: 293695109 Test: CtsFsMgrTestCases Change-Id: I5437303ba9900dbad3276a981413cba138f17157 --- fs_mgr/libfstab/boot_config.cpp | 10 +++++----- fs_mgr/libfstab/fstab.cpp | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/fs_mgr/libfstab/boot_config.cpp b/fs_mgr/libfstab/boot_config.cpp index ae537b5d2560..b21495ecd9e7 100644 --- a/fs_mgr/libfstab/boot_config.cpp +++ b/fs_mgr/libfstab/boot_config.cpp @@ -122,10 +122,8 @@ void ImportKernelCmdlineFromString(const std::string& cmdline, if ((found = cmdline.find(quote, found + 1)) == cmdline.npos) break; ++found; } - std::string piece; - auto source = cmdline.substr(base, found - base); - std::remove_copy(source.begin(), source.end(), - std::back_insert_iterator(piece), quote); + std::string piece = cmdline.substr(base, found - base); + piece.erase(std::remove(piece.begin(), piece.end(), quote), piece.end()); auto equal_sign = piece.find('='); if (equal_sign == piece.npos) { if (!piece.empty()) { @@ -133,7 +131,9 @@ void ImportKernelCmdlineFromString(const std::string& cmdline, fn(std::move(piece), ""); } } else { - fn(piece.substr(0, equal_sign), piece.substr(equal_sign + 1)); + std::string value = piece.substr(equal_sign + 1); + piece.resize(equal_sign); + fn(std::move(piece), std::move(value)); } if (found == cmdline.npos) break; base = found + 1; diff --git a/fs_mgr/libfstab/fstab.cpp b/fs_mgr/libfstab/fstab.cpp index 21b002434391..32460b17b5e1 100644 --- a/fs_mgr/libfstab/fstab.cpp +++ b/fs_mgr/libfstab/fstab.cpp @@ -831,9 +831,8 @@ bool ReadDefaultFstab(Fstab* fstab) { Fstab default_fstab; const std::string default_fstab_path = GetFstabPath(); if (!default_fstab_path.empty() && ReadFstabFromFile(default_fstab_path, &default_fstab)) { - for (auto&& entry : default_fstab) { - fstab->emplace_back(std::move(entry)); - } + fstab->insert(fstab->end(), std::make_move_iterator(default_fstab.begin()), + std::make_move_iterator(default_fstab.end())); } else { LINFO << __FUNCTION__ << "(): failed to find device default fstab"; } @@ -879,7 +878,8 @@ std::set GetBootDevices() { const std::string dt_file_name = GetAndroidDtDir() + "boot_devices"; if (GetKernelCmdline("androidboot.boot_devices", &value) || ReadDtFile(dt_file_name, &value)) { auto boot_devices_list = Split(value, ","); - return {boot_devices_list.begin(), boot_devices_list.end()}; + return {std::make_move_iterator(boot_devices_list.begin()), + std::make_move_iterator(boot_devices_list.end())}; } ImportKernelCmdline([&](std::string key, std::string value) { From 59442132d1c16b0350aa70ec56684d4605a06bd0 Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Thu, 3 Aug 2023 01:51:57 +0800 Subject: [PATCH 0263/1487] remount: Replace ServiceManager::getService with checkService Address this build log message: ``` [ 18% 2/11] //system/core/fs_mgr:remount clang++ fs_mgr_remount.cpp system/core/fs_mgr/fs_mgr_remount.cpp:133:31: warning: 'getService' is deprecated: this polls for 5s, prefer waitForService or checkService [-Wdeprecated-declarations] if (auto binder = sm->getService(android::String16("vold"))) { ^ ``` Bug: 293695109 Test: adb-remount-test Change-Id: I3b5c7d338e9307dee58edeb0f6a00ba9a73d46f6 --- fs_mgr/fs_mgr_remount.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp index 4c458283a537..4b3a5d3ea0fe 100644 --- a/fs_mgr/fs_mgr_remount.cpp +++ b/fs_mgr/fs_mgr_remount.cpp @@ -128,12 +128,11 @@ class MyLogger { } static android::sp GetVold() { + auto sm = android::defaultServiceManager(); while (true) { - if (auto sm = android::defaultServiceManager()) { - if (auto binder = sm->getService(android::String16("vold"))) { - if (auto vold = android::interface_cast(binder)) { - return vold; - } + if (auto binder = sm->checkService(android::String16("vold"))) { + if (auto vold = android::interface_cast(binder)) { + return vold; } } std::this_thread::sleep_for(2s); From fbc5f597377ef2955fa8a801aac040d3ff1b595d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 Aug 2023 19:53:25 -0700 Subject: [PATCH 0264/1487] libsnapshot: Fix missing return keyword in error path. Bug: 288273605 Test: vts_libsnapshot_test Change-Id: I0bee5ee1ebfb61f17d2a495440048d02e2c347b1 --- fs_mgr/libsnapshot/include/libsnapshot/snapshot.h | 2 +- fs_mgr/libsnapshot/snapshot.cpp | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h index df532ee2152a..c056a19f83a1 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h @@ -624,7 +624,7 @@ class SnapshotManager final : public ISnapshotManager { bool CollapseSnapshotDevice(LockedFile* lock, const std::string& name, const SnapshotStatus& status); - struct MergeResult { + struct [[nodiscard]] MergeResult { explicit MergeResult(UpdateState state, MergeFailureCode failure_code = MergeFailureCode::Ok) : state(state), failure_code(failure_code) {} diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index 09d35cff104d..86ff5f710da7 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -1248,14 +1248,12 @@ auto SnapshotManager::CheckTargetMergeState(LockedFile* lock, const std::string& GetMetadataPartitionState(*current_metadata, name) == MetadataPartitionState::Updated); if (UpdateUsesUserSnapshots(lock)) { - std::string merge_status; - if (EnsureSnapuserdConnected()) { - // Query the snapshot status from the daemon - merge_status = snapuserd_client_->QuerySnapshotStatus(name); - } else { - MergeResult(UpdateState::MergeFailed, MergeFailureCode::QuerySnapshotStatus); + if (!EnsureSnapuserdConnected()) { + return MergeResult(UpdateState::MergeFailed, MergeFailureCode::QuerySnapshotStatus); } + // Query the snapshot status from the daemon + const auto merge_status = snapuserd_client_->QuerySnapshotStatus(name); if (merge_status == "snapshot-merge-failed") { return MergeResult(UpdateState::MergeFailed, MergeFailureCode::UnknownTargetType); } From 355ae4154efa87bc791a83ceb8fe90998165ad2b Mon Sep 17 00:00:00 2001 From: Cole Faust Date: Thu, 3 Aug 2023 10:54:59 -0700 Subject: [PATCH 0265/1487] Remove references to the pdk product variable pdk is deprecated and has no effect as of aosp/1319667. Test: Presubmits Change-Id: I78d7afaaa71b93e575dcd5c20716ffb295b9f522 --- bootstat/Android.bp | 3 --- 1 file changed, 3 deletions(-) diff --git a/bootstat/Android.bp b/bootstat/Android.bp index ca59ef39bb95..0c8760c2d1b4 100644 --- a/bootstat/Android.bp +++ b/bootstat/Android.bp @@ -72,9 +72,6 @@ cc_binary { ], init_rc: ["bootstat.rc"], product_variables: { - pdk: { - enabled: false, - }, debuggable: { init_rc: ["bootstat-debug.rc"], }, From 21a071661320806bd521f4d5e6259601627fd531 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Tue, 25 Jul 2023 12:57:45 -0700 Subject: [PATCH 0266/1487] Remove gettid declaration from cutils Bug: 289414897 Test: it builds Change-Id: I22d93406cf065c0e3c7d94e800763974d228ee21 --- libcutils/include/cutils/threads.h | 15 --------------- libcutils/threads.cpp | 6 ++++-- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/libcutils/include/cutils/threads.h b/libcutils/include/cutils/threads.h index 18861840e28d..92564b8db9a7 100644 --- a/libcutils/include/cutils/threads.h +++ b/libcutils/include/cutils/threads.h @@ -23,18 +23,3 @@ #else #include #endif - -#ifdef __cplusplus -extern "C" { -#endif - -// -// Deprecated: use android::base::GetThreadId instead, which doesn't truncate on Mac/Windows. -// -#if !defined(__GLIBC__) || __GLIBC__ >= 2 && __GLIBC_MINOR__ < 30 -extern pid_t gettid(); -#endif - -#ifdef __cplusplus -} -#endif diff --git a/libcutils/threads.cpp b/libcutils/threads.cpp index 2638720847d8..cca50c191c14 100644 --- a/libcutils/threads.cpp +++ b/libcutils/threads.cpp @@ -14,11 +14,13 @@ ** limitations under the License. */ -#include +#include #if defined(__APPLE__) +#include #include #elif defined(__linux__) +#include #include #include #elif defined(_WIN32) @@ -29,7 +31,7 @@ // No definition needed for Android because we'll just pick up bionic's copy. // No definition needed for Glibc >= 2.30 because it exposes its own copy. #else -pid_t gettid() { +extern "C" pid_t gettid() { #if defined(__APPLE__) uint64_t tid; pthread_threadid_np(NULL, &tid); From d22098f65d93a394f22139459eef717058f285f3 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Tue, 25 Jul 2023 13:16:06 -0700 Subject: [PATCH 0267/1487] Remove sub-includes from libcutils/threads.h This will drop any incentive to use this header Bug: 289414897 Test: it builds Change-Id: I3d7f56ac027f59794cb4cf533847c5fda5529906 --- libcutils/include/cutils/threads.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/libcutils/include/cutils/threads.h b/libcutils/include/cutils/threads.h index 92564b8db9a7..9bc3429bec29 100644 --- a/libcutils/include/cutils/threads.h +++ b/libcutils/include/cutils/threads.h @@ -13,13 +13,3 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -#pragma once - -#include - -#if defined(_WIN32) -#include -#else -#include -#endif From 8b0160868eefc2997155906aa361470fb9a6c9ab Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 28 Jul 2023 12:37:10 -0700 Subject: [PATCH 0268/1487] Remove gettid symbol from cutils Bug: 289414897 Test: it builds Change-Id: I3b4c8b35dbf47e41d1fb0912fedc05e6545bd3d7 --- libcutils/Android.bp | 1 - libcutils/threads.cpp | 45 ------------------------------------------- 2 files changed, 46 deletions(-) delete mode 100644 libcutils/threads.cpp diff --git a/libcutils/Android.bp b/libcutils/Android.bp index 92486e3357a8..55a8694ffc31 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -162,7 +162,6 @@ cc_library { "properties.cpp", "record_stream.cpp", "strlcpy.c", - "threads.cpp", ], target: { diff --git a/libcutils/threads.cpp b/libcutils/threads.cpp deleted file mode 100644 index cca50c191c14..000000000000 --- a/libcutils/threads.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* -** Copyright (C) 2007, 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 - -#if defined(__APPLE__) -#include -#include -#elif defined(__linux__) -#include -#include -#include -#elif defined(_WIN32) -#include -#endif - -#if defined(__BIONIC__) || defined(__GLIBC__) && __GLIBC_MINOR__ >= 30 -// No definition needed for Android because we'll just pick up bionic's copy. -// No definition needed for Glibc >= 2.30 because it exposes its own copy. -#else -extern "C" pid_t gettid() { -#if defined(__APPLE__) - uint64_t tid; - pthread_threadid_np(NULL, &tid); - return tid; -#elif defined(__linux__) - return syscall(__NR_gettid); -#elif defined(_WIN32) - return GetCurrentThreadId(); -#endif -} -#endif From 75c5deed5264fed76ef57efa1ad9e25e3b8ce944 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 30 Jun 2023 10:22:34 -0700 Subject: [PATCH 0269/1487] snapuserd: Rename libsnapshot_snapuserd to libsnapuserd_client. We don't need this on the host, since the host will not be running snapuserd as a server. Rename it for clarity and remove it where we can. Bug: 288273605 Test: snapuserd_test Change-Id: I679ef668a89411c670fea8d3b758bde589623548 --- fs_mgr/libfiemap/Android.bp | 1 + fs_mgr/libsnapshot/Android.bp | 2 +- fs_mgr/libsnapshot/snapuserd/Android.bp | 15 +++++++++------ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp index ddda648d8e88..c8d575630262 100644 --- a/fs_mgr/libfiemap/Android.bp +++ b/fs_mgr/libfiemap/Android.bp @@ -24,6 +24,7 @@ cc_library_headers { vendor_ramdisk_available: true, recovery_available: true, export_include_dirs: ["include"], + host_supported: true, } filegroup { diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index bd017ff10bfa..04b5a021ad5f 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -44,7 +44,7 @@ cc_defaults { "libext2_uuid", "libext4_utils", "libfstab", - "libsnapshot_snapuserd", + "libsnapuserd_client", "libz", ], header_libs: [ diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index a9b96e2efc7f..20eef71af51d 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -19,7 +19,7 @@ package { } cc_defaults { - name: "libsnapshot_snapuserd_defaults", + name: "libsnapuserd_client_defaults", defaults: [ "fs_mgr_defaults", ], @@ -33,10 +33,10 @@ cc_defaults { } cc_library_static { - name: "libsnapshot_snapuserd", + name: "libsnapuserd_client", defaults: [ "fs_mgr_defaults", - "libsnapshot_snapuserd_defaults", + "libsnapuserd_client_defaults", ], recovery_available: true, static_libs: [ @@ -80,6 +80,7 @@ cc_library_static { "liburing", ], include_dirs: ["bionic/libc/kernel"], + export_include_dirs: ["include"], header_libs: [ "libstorage_literals_headers", ], @@ -108,8 +109,8 @@ cc_defaults { "libgflags", "liblog", "libsnapshot_cow", - "libsnapshot_snapuserd", "libsnapuserd", + "libsnapuserd_client", "libz", "liblz4", "libext4_utils", @@ -144,6 +145,9 @@ cc_binary { init_rc: [ "snapuserd.rc", ], + static_libs: [ + "libsnapuserd_client", + ], ramdisk_available: false, vendor_ramdisk_available: true, } @@ -186,7 +190,7 @@ cc_test { "libbrotli", "libgtest", "libsnapshot_cow", - "libsnapshot_snapuserd", + "libsnapuserd_client", "libcutils_sockets", "libz", "libfs_mgr", @@ -226,7 +230,6 @@ cc_test { "libgflags", "libgtest", "libsnapshot_cow", - "libsnapshot_snapuserd", "libsnapuserd", "liburing", "libz", From c132bf80aec74e362826e895c25d9eaf69a08cb9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 30 Jun 2023 10:24:37 -0700 Subject: [PATCH 0270/1487] snapuserd: Remove dependence on libfs_mgr. The only function we use from libfs_mgr is WaitForFile, so factor that out into libfs_mgr_file_wait. libfs_mgr has too much dependence on AOSP internals to build on the host. Bug: 288273605 Test: builds Change-Id: I8e5eb4075ae01b9ca64074422171a487179e7943 --- fs_mgr/Android.bp | 19 +++++++++++++++++++ fs_mgr/libsnapshot/snapuserd/Android.bp | 12 ++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp index 4e4d20edc516..87db98b0877d 100644 --- a/fs_mgr/Android.bp +++ b/fs_mgr/Android.bp @@ -171,6 +171,25 @@ cc_library { ], } +cc_library_static { + name: "libfs_mgr_file_wait", + defaults: ["fs_mgr_defaults"], + export_include_dirs: ["include"], + cflags: [ + "-D_FILE_OFFSET_BITS=64", + ], + srcs: [ + "file_wait.cpp", + ], + shared_libs: [ + "libbase", + ], + host_supported: true, + ramdisk_available: true, + vendor_ramdisk_available: true, + recovery_available: true, +} + cc_binary { name: "remount", defaults: ["fs_mgr_defaults"], diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 20eef71af51d..dddc9075771d 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -41,7 +41,7 @@ cc_library_static { recovery_available: true, static_libs: [ "libcutils_sockets", - "libfs_mgr", + "libfs_mgr_file_wait", ], shared_libs: [ "libbase", @@ -75,6 +75,7 @@ cc_library_static { static_libs: [ "libbase", "libdm", + "libext2_uuid", "libext4_utils", "libsnapshot_cow", "liburing", @@ -105,7 +106,8 @@ cc_defaults { "libbrotli", "libcutils_sockets", "libdm", - "libfs_mgr", + "libext2_uuid", + "libfs_mgr_file_wait", "libgflags", "liblog", "libsnapshot_cow", @@ -193,9 +195,10 @@ cc_test { "libsnapuserd_client", "libcutils_sockets", "libz", - "libfs_mgr", "libdm", + "libext2_uuid", "libext4_utils", + "libfs_mgr_file_wait", ], header_libs: [ "libstorage_literals_headers", @@ -225,8 +228,9 @@ cc_test { "libbrotli", "libcutils_sockets", "libdm", + "libext2_uuid", "libext4_utils", - "libfs_mgr", + "libfs_mgr_file_wait", "libgflags", "libgtest", "libsnapshot_cow", From 95f46b07580e484d8c7b091c162e1fc6322b6957 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 28 Jun 2023 10:34:30 -0700 Subject: [PATCH 0271/1487] snapuserd: Split Tempdevice into a separate file. Bug: 288273605 Test: snapuserd_test Change-Id: I3f1b01de8986d22de03bb31355ec09fe48c9204b --- fs_mgr/libsnapshot/snapuserd/Android.bp | 5 +- .../snapuserd/testing/temp_device.h | 72 +++++++++++++++++++ .../user-space-merge/snapuserd_test.cpp | 44 +----------- 3 files changed, 77 insertions(+), 44 deletions(-) create mode 100644 fs_mgr/libsnapshot/snapuserd/testing/temp_device.h diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index dddc9075771d..f63579b9b372 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -238,7 +238,10 @@ cc_test { "liburing", "libz", ], - include_dirs: ["bionic/libc/kernel"], + include_dirs: [ + "bionic/libc/kernel", + ".", + ], header_libs: [ "libstorage_literals_headers", "libfiemap_headers", diff --git a/fs_mgr/libsnapshot/snapuserd/testing/temp_device.h b/fs_mgr/libsnapshot/snapuserd/testing/temp_device.h new file mode 100644 index 000000000000..2a6d3eaac5e4 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/testing/temp_device.h @@ -0,0 +1,72 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include +#include + +#include + +namespace android { +namespace snapshot { + +using android::dm::DeviceMapper; +using android::dm::DmTable; + +class Tempdevice { + public: + Tempdevice(const std::string& name, const DmTable& table) + : dm_(DeviceMapper::Instance()), name_(name), valid_(false) { + valid_ = dm_.CreateDevice(name, table, &path_, std::chrono::seconds(5)); + } + Tempdevice(Tempdevice&& other) noexcept + : dm_(other.dm_), name_(other.name_), path_(other.path_), valid_(other.valid_) { + other.valid_ = false; + } + ~Tempdevice() { + if (valid_) { + dm_.DeleteDeviceIfExists(name_); + } + } + bool Destroy() { + if (!valid_) { + return true; + } + valid_ = false; + return dm_.DeleteDeviceIfExists(name_); + } + const std::string& path() const { return path_; } + const std::string& name() const { return name_; } + bool valid() const { return valid_; } + + Tempdevice(const Tempdevice&) = delete; + Tempdevice& operator=(const Tempdevice&) = delete; + + Tempdevice& operator=(Tempdevice&& other) noexcept { + name_ = other.name_; + valid_ = other.valid_; + other.valid_ = false; + return *this; + } + + private: + DeviceMapper& dm_; + std::string name_; + std::string path_; + bool valid_; +}; + +} // namespace snapshot +} // namespace android 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 efe0c1443215..f3c3f671199d 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -41,6 +41,7 @@ #include "handler_manager.h" #include "snapuserd_core.h" +#include "testing/temp_device.h" DEFINE_string(force_config, "", "Force testing mode with iouring disabled"); @@ -54,49 +55,6 @@ using namespace std::chrono_literals; using namespace android::dm; using namespace std; -class Tempdevice { - public: - Tempdevice(const std::string& name, const DmTable& table) - : dm_(DeviceMapper::Instance()), name_(name), valid_(false) { - valid_ = dm_.CreateDevice(name, table, &path_, std::chrono::seconds(5)); - } - Tempdevice(Tempdevice&& other) noexcept - : dm_(other.dm_), name_(other.name_), path_(other.path_), valid_(other.valid_) { - other.valid_ = false; - } - ~Tempdevice() { - if (valid_) { - dm_.DeleteDeviceIfExists(name_); - } - } - bool Destroy() { - if (!valid_) { - return true; - } - valid_ = false; - return dm_.DeleteDeviceIfExists(name_); - } - const std::string& path() const { return path_; } - const std::string& name() const { return name_; } - bool valid() const { return valid_; } - - Tempdevice(const Tempdevice&) = delete; - Tempdevice& operator=(const Tempdevice&) = delete; - - Tempdevice& operator=(Tempdevice&& other) noexcept { - name_ = other.name_; - valid_ = other.valid_; - other.valid_ = false; - return *this; - } - - private: - DeviceMapper& dm_; - std::string name_; - std::string path_; - bool valid_; -}; - class SnapuserdTest : public ::testing::Test { public: bool SetupDefault(); From 48d1c39da7663561b54d8244e2b967fc984d41ea Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 5 Jul 2023 13:35:12 -0700 Subject: [PATCH 0272/1487] snapuserd: Move GetNumSectors call to snapuserd_server. Calling this in snapuserd_core fails when the base path is a regular file. Since the value is only read once, just call it from snapuserd_server instead, which also means we don't have to add an S_ISBLK check here. Bug: 288273605 Test: snapuserd_test Change-Id: Ic26bf807b24611f2d97829d1b4eb1d0ede2feb6a --- .../include/snapuserd/snapuserd_kernel.h | 1 + .../user-space-merge/snapuserd_core.cpp | 30 ++++++++++--------- .../user-space-merge/snapuserd_core.h | 4 +-- .../user-space-merge/snapuserd_server.cpp | 7 ++++- .../user-space-merge/snapuserd_test.cpp | 2 ++ 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h index 46952c4ed98e..0d83f4789625 100644 --- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h +++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h @@ -40,6 +40,7 @@ static constexpr uint32_t SNAPSHOT_VALID = 1; * multiple of 512 bytes. Hence these two constants. */ static constexpr uint32_t SECTOR_SHIFT = 9; +static constexpr uint64_t SECTOR_SIZE = (1ULL << SECTOR_SHIFT); static constexpr size_t BLOCK_SZ = 4096; static constexpr size_t BLOCK_SHIFT = (__builtin_ffs(BLOCK_SZ) - 1); 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 2dd2ec09d6ce..12d095afec05 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -280,20 +280,6 @@ bool SnapshotHandler::InitCowDevice() { return false; } - unique_fd fd(TEMP_FAILURE_RETRY(open(base_path_merge_.c_str(), O_RDONLY | O_CLOEXEC))); - if (fd < 0) { - SNAP_LOG(ERROR) << "Cannot open block device"; - return false; - } - - uint64_t dev_sz = get_block_device_size(fd.get()); - if (!dev_sz) { - SNAP_LOG(ERROR) << "Failed to find block device size: " << base_path_merge_; - return false; - } - - num_sectors_ = dev_sz >> SECTOR_SHIFT; - return ReadMetadata(); } @@ -460,5 +446,21 @@ void SnapshotHandler::FreeResources() { merge_thread_ = nullptr; } +uint64_t SnapshotHandler::GetNumSectors() const { + unique_fd fd(TEMP_FAILURE_RETRY(open(base_path_merge_.c_str(), O_RDONLY | O_CLOEXEC))); + if (fd < 0) { + SNAP_LOG(ERROR) << "Cannot open base path: " << base_path_merge_; + return false; + } + + uint64_t dev_sz = get_block_device_size(fd.get()); + if (!dev_sz) { + SNAP_LOG(ERROR) << "Failed to find block device size: " << base_path_merge_; + return false; + } + + return dev_sz / SECTOR_SIZE; +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index cdc38c01665e..5fe0a709af8e 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -109,7 +109,7 @@ class SnapshotHandler : public std::enable_shared_from_this { const std::string& GetControlDevicePath() { return control_device_; } const std::string& GetMiscName() { return misc_name_; } - const uint64_t& GetNumSectors() { return num_sectors_; } + uint64_t GetNumSectors() const; const bool& IsAttached() const { return attached_; } void AttachControlDevice() { attached_ = true; } @@ -202,8 +202,6 @@ class SnapshotHandler : public std::enable_shared_from_this { unique_fd cow_fd_; - uint64_t num_sectors_; - std::unique_ptr reader_; // chunk_vec stores the pseudo mapping of sector 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 c953f1a053bd..f2585eab1d81 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp @@ -130,7 +130,12 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st return Sendmsg(fd, "fail"); } - auto retval = "success," + std::to_string(handler->snapuserd()->GetNumSectors()); + auto num_sectors = handler->snapuserd()->GetNumSectors(); + if (!num_sectors) { + return Sendmsg(fd, "fail"); + } + + auto retval = "success," + std::to_string(num_sectors); return Sendmsg(fd, retval); } else if (cmd == "start") { // Message format: 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 f3c3f671199d..16f9ed87f7ac 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -540,7 +540,9 @@ void SnapuserdTest::InitCowDevice() { base_loop_->device(), 1, use_iouring, false); ASSERT_NE(handler, nullptr); ASSERT_NE(handler->snapuserd(), nullptr); +#ifdef __ANDROID__ ASSERT_NE(handler->snapuserd()->GetNumSectors(), 0); +#endif } void SnapuserdTest::SetDeviceControlName() { From ed34b6e2324122f5fe02f4d3b873ac9888b8ef47 Mon Sep 17 00:00:00 2001 From: Snehal Date: Fri, 30 Jun 2023 14:49:48 +0000 Subject: [PATCH 0273/1487] Coverage library on the NS side for the coverage controller Bug: 289520358 Change-Id: I6c2c0e5db9e8d9a0edec93d2fb123d185c7c4416 --- trusty/line-coverage/Android.bp | 36 ++++ trusty/line-coverage/coverage.cpp | 191 ++++++++++++++++++ .../include/trusty/line-coverage/coverage.h | 61 ++++++ .../include/trusty/line-coverage/tipc.h | 140 +++++++++++++ .../include/trusty/line-coverage/uuid.h | 37 ++++ 5 files changed, 465 insertions(+) create mode 100644 trusty/line-coverage/Android.bp create mode 100644 trusty/line-coverage/coverage.cpp create mode 100644 trusty/line-coverage/include/trusty/line-coverage/coverage.h create mode 100644 trusty/line-coverage/include/trusty/line-coverage/tipc.h create mode 100644 trusty/line-coverage/include/trusty/line-coverage/uuid.h diff --git a/trusty/line-coverage/Android.bp b/trusty/line-coverage/Android.bp new file mode 100644 index 000000000000..36a73aada8cc --- /dev/null +++ b/trusty/line-coverage/Android.bp @@ -0,0 +1,36 @@ +// Copyright (C) 2023 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. + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_library { + name: "libtrusty_line_coverage", + vendor_available: true, + srcs: [ + "coverage.cpp", + ], + export_include_dirs: [ + "include", + ], + shared_libs: [ + "libbase", + "libext2_uuid", + "liblog", + "libdmabufheap", + "libtrusty", + ], +} + diff --git a/trusty/line-coverage/coverage.cpp b/trusty/line-coverage/coverage.cpp new file mode 100644 index 000000000000..57b702510da7 --- /dev/null +++ b/trusty/line-coverage/coverage.cpp @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2023 The Android Open Sourete 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. + */ + +#define LOG_TAG "line-coverage" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LINE_COVERAGE_CLIENT_PORT "com.android.trusty.linecoverage.client" + +struct control { + /* Written by controller, read by instrumented TA */ + uint64_t cntrl_flags; + + /* Written by instrumented TA, read by controller */ + uint64_t oper_flags; + uint64_t write_buffer_start_count; + uint64_t write_buffer_complete_count; +}; + +namespace android { +namespace trusty { +namespace line_coverage { + +using ::android::base::ErrnoError; +using ::android::base::Error; +using ::std::string; + +static inline uintptr_t RoundPageUp(uintptr_t val) { + return (val + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); +} + +CoverageRecord::CoverageRecord(string tipc_dev, struct uuid* uuid) + : tipc_dev_(std::move(tipc_dev)), + coverage_srv_fd_(-1), + uuid_(*uuid), + record_len_(0), + shm_(NULL), + shm_len_(0) {} + +CoverageRecord::~CoverageRecord() { + if (shm_) { + munmap((void*)shm_, shm_len_); + } +} + +volatile void *CoverageRecord::getShm() { + if(!IsOpen()) { + fprintf(stderr, "Warning! SHM is NULL!\n"); + } + return shm_; +} + +Result CoverageRecord::Rpc(struct line_coverage_client_req* req, \ + int req_fd, \ + struct line_coverage_client_resp* resp) { + int rc; + + if (req_fd < 0) { + rc = write(coverage_srv_fd_, req, sizeof(*req)); + } else { + iovec iov = { + .iov_base = req, + .iov_len = sizeof(*req), + }; + + trusty_shm shm = { + .fd = req_fd, + .transfer = TRUSTY_SHARE, + }; + + rc = tipc_send(coverage_srv_fd_, &iov, 1, &shm, 1); + } + + if (rc != (int)sizeof(*req)) { + return ErrnoError() << "failed to send request to coverage server: "; + } + + rc = read(coverage_srv_fd_, resp, sizeof(*resp)); + if (rc != (int)sizeof(*resp)) { + return ErrnoError() << "failed to read reply from coverage server: "; + } + + if (resp->hdr.cmd != (req->hdr.cmd | LINE_COVERAGE_CLIENT_CMD_RESP_BIT)) { + return ErrnoError() << "unknown response cmd: " << resp->hdr.cmd; + } + + return {}; +} + +Result CoverageRecord::Open(int fd) { + struct line_coverage_client_req req; + struct line_coverage_client_resp resp; + + if (shm_) { + return {}; /* already initialized */ + } + + coverage_srv_fd_= fd; + + req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_OPEN; + req.open_args.uuid = uuid_; + auto ret = Rpc(&req, -1, &resp); + if (!ret.ok()) { + return Error() << "failed to open coverage client: " << ret.error(); + } + record_len_ = resp.open_args.record_len; + shm_len_ = RoundPageUp(record_len_); + + BufferAllocator allocator; + + fd = allocator.Alloc("system", shm_len_); + if (fd < 0) { + return ErrnoError() << "failed to create dmabuf of size " << shm_len_ + << " err code: " << fd; + } + unique_fd dma_buf(fd); + + void* shm = mmap(0, shm_len_, PROT_READ | PROT_WRITE, MAP_SHARED, dma_buf, 0); + if (shm == MAP_FAILED) { + return ErrnoError() << "failed to map memfd: "; + } + + req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_SHARE_RECORD; + req.share_record_args.shm_len = shm_len_; + ret = Rpc(&req, dma_buf, &resp); + if (!ret.ok()) { + return Error() << "failed to send shared memory: " << ret.error(); + } + + shm_ = shm; + + req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_OPEN; + req.open_args.uuid = uuid_; + ret = Rpc(&req, -1, &resp); + if (!ret.ok()) { + return Error() << "failed to open coverage client: " << ret.error(); + } + + return {}; +} + +bool CoverageRecord::IsOpen() { + return shm_; +} + +Result CoverageRecord::SaveFile(const std::string& filename) { + if(!IsOpen()) { + return ErrnoError() << "Warning! SHM is NULL!"; + } + android::base::unique_fd output_fd(TEMP_FAILURE_RETRY(creat(filename.c_str(), 00644))); + if (!output_fd.ok()) { + return ErrnoError() << "Could not open output file"; + } + + uintptr_t* begin = (uintptr_t*)((char *)shm_ + sizeof(struct control)); + bool ret = WriteFully(output_fd, begin, record_len_); + if(!ret) { + fprintf(stderr, "Coverage write to file failed\n"); + } + + return {}; +} + +} // namespace line_coverage +} // namespace trusty +} // namespace android diff --git a/trusty/line-coverage/include/trusty/line-coverage/coverage.h b/trusty/line-coverage/include/trusty/line-coverage/coverage.h new file mode 100644 index 000000000000..53901beb74bf --- /dev/null +++ b/trusty/line-coverage/include/trusty/line-coverage/coverage.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2023 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. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace android { +namespace trusty { +namespace line_coverage { + +using android::base::Result; +using android::base::unique_fd; + +class CoverageRecord { + public: + CoverageRecord(std::string tipc_dev, struct uuid* uuid); + + ~CoverageRecord(); + Result Open(int fd); + bool IsOpen(); + Result SaveFile(const std::string& filename); + volatile void* getShm(); + + private: + Result Rpc(struct line_coverage_client_req* req, \ + int req_fd, \ + struct line_coverage_client_resp* resp); + + Result> GetRegionBounds(uint32_t region_type); + + std::string tipc_dev_; + int coverage_srv_fd_; + struct uuid uuid_; + size_t record_len_; + volatile void* shm_; + size_t shm_len_; +}; + +} // namespace line_coverage +} // namespace trusty +} // namespace android diff --git a/trusty/line-coverage/include/trusty/line-coverage/tipc.h b/trusty/line-coverage/include/trusty/line-coverage/tipc.h new file mode 100644 index 000000000000..20e855cbfdb6 --- /dev/null +++ b/trusty/line-coverage/include/trusty/line-coverage/tipc.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This file needs to be kept in-sync with its counterpart on Trusty side */ + +#pragma once + +#include +#include + + +#define LINE_COVERAGE_CLIENT_PORT "com.android.trusty.linecoverage.client" + +/** + * enum line_coverage_client_cmd - command identifiers for coverage client interface + * @LINE_COVERAGE_CLIENT_CMD_RESP_BIT: response bit set as part of response + * @LINE_COVERAGE_CLIENT_CMD_SHIFT: number of bits used by response bit + * @LINE_COVERAGE_CLIENT_CMD_OPEN: command to open coverage record + * @LINE_COVERAGE_CLIENT_CMD_SHARE_RECORD: command to register a shared memory region + * where coverage record will be written to + */ +enum line_coverage_client_cmd { + LINE_COVERAGE_CLIENT_CMD_RESP_BIT = 1U, + LINE_COVERAGE_CLIENT_CMD_SHIFT = 1U, + LINE_COVERAGE_CLIENT_CMD_OPEN = (1U << LINE_COVERAGE_CLIENT_CMD_SHIFT), + LINE_COVERAGE_CLIENT_CMD_SHARE_RECORD = (2U << LINE_COVERAGE_CLIENT_CMD_SHIFT), + LINE_COVERAGE_CLIENT_CMD_SEND_LIST = (3U << LINE_COVERAGE_CLIENT_CMD_SHIFT), +}; + +/** + * struct line_coverage_client_hdr - header for coverage client messages + * @cmd: command identifier + * + * Note that no messages return a status code. Any error on the server side + * results in the connection being closed. So, operations can be assumed to be + * successful if they return a response. + */ +struct line_coverage_client_hdr { + uint32_t cmd; +}; + +/** + * struct line_coverage_client_open_req - arguments for request to open coverage + * record + * @uuid: UUID of target TA + * + * There is one coverage record per TA. @uuid is used to identify both the TA + * and corresponding coverage record. + */ +struct line_coverage_client_open_req { + struct uuid uuid; +}; + +/** + * struct line_coverage_client_open_resp - arguments for response to open coverage + * record + * @record_len: length of coverage record that will be emitted by target TA + * + * Shared memory allocated for this coverage record must larger than + * @record_len. + */ +struct line_coverage_client_open_resp { + uint32_t record_len; +}; + +/** + * struct line_coverage_client_send_list_resp - arguments for response to send list + * record + * @uuid: UUID of TA that connected to aggregator + */ +struct line_coverage_client_send_list_resp { + struct uuid uuid; +}; + +/** + * struct line_coverage_client_send_list_resp - arguments for response to send list + * record + * @index: index of the list being requested + */ +struct line_coverage_client_send_list_req { + uint32_t index; +}; + +/** + * struct line_coverage_client_share_record_req - arguments for request to share + * memory for coverage record + * @shm_len: length of memory region being shared + * + * A handle to a memory region must be sent along with this message. This memory + * is used to store coverage record. + * + * Upon success, this memory region can be assumed to be shared between the + * client and target TA. + */ +struct line_coverage_client_share_record_req { + uint32_t shm_len; +}; + +/** + * struct line_coverage_client_req - structure for a coverage client request + * @hdr: message header + * @open_args: arguments for %COVERAGE_CLIENT_CMD_OPEN request + * @share_record_args: arguments for %COVERAGE_CLIENT_CMD_SHARE_RECORD request + * @index: arguments for %COVERAGE_CLIENT_CMD_SHARE_RECORD request + */ +struct line_coverage_client_req { + struct line_coverage_client_hdr hdr; + union { + struct line_coverage_client_open_req open_args; + struct line_coverage_client_share_record_req share_record_args; + struct line_coverage_client_send_list_req send_list_args; + }; +}; + +/** + * struct line_coverage_client_resp - structure for a coverage client response + * @hdr: message header + * @open_args: arguments for %COVERAGE_CLIENT_CMD_OPEN response + * @send_list_args: arguments for %COVERAGE_CLIENT_CMD_SHARE_RECORD response + */ +struct line_coverage_client_resp { + struct line_coverage_client_hdr hdr; + union { + struct line_coverage_client_open_resp open_args; + struct line_coverage_client_send_list_resp send_list_args; + }; +}; diff --git a/trusty/line-coverage/include/trusty/line-coverage/uuid.h b/trusty/line-coverage/include/trusty/line-coverage/uuid.h new file mode 100644 index 000000000000..187398014767 --- /dev/null +++ b/trusty/line-coverage/include/trusty/line-coverage/uuid.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2023 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. + */ + +#pragma once + +#include +#include + +#define UUCMP(u1, u2) if (u1 != u2) return u1 < u2 + +struct uuid { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_and_node[8]; + + bool operator<(const struct uuid& rhs) const + { + UUCMP(time_low, rhs.time_low); + UUCMP(time_mid, rhs.time_mid); + UUCMP(time_hi_and_version, rhs.time_hi_and_version); + return memcmp(clock_seq_and_node, rhs.clock_seq_and_node, 8); + } +}; From 806e70bb941acc590d9bd9c1f29a77d648d5f928 Mon Sep 17 00:00:00 2001 From: Snehal Date: Fri, 30 Jun 2023 15:23:14 +0000 Subject: [PATCH 0274/1487] Add Coverage controller Bug: 289523068 Change-Id: I5b36c274acc7da4e2d6b9cf91409a7b1af5f0d34 --- trusty/utils/coverage-controller/Android.bp | 34 ++++ .../utils/coverage-controller/controller.cpp | 164 ++++++++++++++++++ trusty/utils/coverage-controller/controller.h | 64 +++++++ 3 files changed, 262 insertions(+) create mode 100644 trusty/utils/coverage-controller/Android.bp create mode 100644 trusty/utils/coverage-controller/controller.cpp create mode 100644 trusty/utils/coverage-controller/controller.h diff --git a/trusty/utils/coverage-controller/Android.bp b/trusty/utils/coverage-controller/Android.bp new file mode 100644 index 000000000000..1aa88cc12086 --- /dev/null +++ b/trusty/utils/coverage-controller/Android.bp @@ -0,0 +1,34 @@ +// Copyright (C) 2023 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. + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_binary { + name: "coverage-controller", + vendor: true, + + srcs: ["controller.cpp"], + shared_libs: [ + "libc", + "liblog", + "libbase", + "libdmabufheap", + ], + static_libs: [ + "libtrusty", + "libtrusty_line_coverage", + ], +} diff --git a/trusty/utils/coverage-controller/controller.cpp b/trusty/utils/coverage-controller/controller.cpp new file mode 100644 index 000000000000..730c0109b0ca --- /dev/null +++ b/trusty/utils/coverage-controller/controller.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2023 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 +#include +#include +#include +#include +#include + +#include "controller.h" + +#define READ_ONCE(x) (*((volatile __typeof__(x) *) &(x))) +#define WRITE_ONCE(x, val) (*((volatile __typeof__(val) *) &(x)) = (val)) + +namespace android { +namespace trusty { +namespace controller { + +using ::android::trusty::line_coverage::CoverageRecord; + +void Controller::run(std::string output_dir) { + connectCoverageServer(); + struct control *control; + uint64_t complete_cnt = 0, start_cnt = 0, flags; + + while(1) { + setUpShm(); + + for (int index = 0; index < record_list_.size(); index++) { + control = (struct control *)record_list_[index]->getShm(); + start_cnt = READ_ONCE((control->write_buffer_start_count)); + complete_cnt = READ_ONCE(control->write_buffer_complete_count); + flags = READ_ONCE(control->cntrl_flags); + + if (complete_cnt != counters[index] && start_cnt == complete_cnt) { + WRITE_ONCE(control->cntrl_flags, FLAG_NONE); + std::string fmt = "/%d.%lu.profraw"; + int sz = std::snprintf(nullptr, 0, fmt.c_str(), index, counters[index]); + std::string filename(sz+1, '.'); + std::sprintf(filename.data(), fmt.c_str(), index, counters[index]); + filename.insert(0, output_dir); + android::base::Result res = record_list_[index]->SaveFile(filename); + counters[index]++; + } + if(complete_cnt == counters[index] && + !(flags & FLAG_RUN)) { + flags |= FLAG_RUN; + WRITE_ONCE(control->cntrl_flags, flags); + } + } + } +} + +void Controller::connectCoverageServer() { + coverage_srv_fd = tipc_connect(TIPC_DEV, LINE_COVERAGE_CLIENT_PORT); + if (coverage_srv_fd < 0) { + fprintf(stderr, \ + "Error: Failed to connect to Trusty coverage server: %d\n", coverage_srv_fd); + return; + } +} + +void Controller::setUpShm() { + struct line_coverage_client_req req; + struct line_coverage_client_resp resp; + uint32_t cur_index = record_list_.size(); + struct uuid zero_uuid = {0, 0, 0, { 0 }}; + req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_SEND_LIST; + int rc = write(coverage_srv_fd, &req, sizeof(req)); + if (rc != (int)sizeof(req)) { + fprintf(stderr, "failed to send request to coverage server: %d\n", rc); + return; + } + + while(1) { + rc = read(coverage_srv_fd, &resp, sizeof(resp)); + if (rc != (int)sizeof(resp)) { + fprintf(stderr, "failed to read reply from coverage server:: %d\n", rc); + } + + if (resp.hdr.cmd == (req.hdr.cmd | LINE_COVERAGE_CLIENT_CMD_RESP_BIT)) { + if (!memcmp(&resp.send_list_args.uuid, &zero_uuid, sizeof(struct uuid))) { + break; + } + if(uuid_set_.find(resp.send_list_args.uuid) == uuid_set_.end()) { + uuid_set_.insert(resp.send_list_args.uuid); + record_list_.push_back(std::make_unique(TIPC_DEV, + &resp.send_list_args.uuid)); + counters.push_back(0); + } + } + else { + fprintf(stderr, "Unknown response header\n"); + } + cur_index++; + req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_SEND_LIST; + req.send_list_args.index = cur_index; + int rc = write(coverage_srv_fd, &req, sizeof(req)); + if (rc != (int)sizeof(req)) { + fprintf(stderr, "failed to send request to coverage server: %d\n", rc); + } + } + + for(int ind = 0 ; ind < record_list_.size() ; ind++) { + record_list_[ind]->Open(coverage_srv_fd); + } +} + + +} // namespace controller +} // namespace trusty +} // namespace android + +int main(int argc, char* argv[]) { + + std::string optarg = ""; + do { + int c; + c = getopt(argc, argv, "o"); + + if (c == -1) { + break; + } + + switch (c) { + case 'o': + break; + default: + fprintf(stderr, "usage: %s -o [output_directory]\n", argv[0]); + exit(EXIT_FAILURE); + } + } while (1); + + if (argc > optind + 1) { + fprintf(stderr, "%s: too many arguments\n", argv[0]); + exit(EXIT_FAILURE); + } + + if (argc > optind) { + optarg = argv[optind]; + } + if (optarg.size()==0) { + optarg = "data/local/tmp"; + } + + android::trusty::controller::Controller cur; + cur.run(optarg); + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/trusty/utils/coverage-controller/controller.h b/trusty/utils/coverage-controller/controller.h new file mode 100644 index 000000000000..b771c16150d8 --- /dev/null +++ b/trusty/utils/coverage-controller/controller.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2023 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#define TIPC_DEV "/dev/trusty-ipc-dev0" +#define TEST_SRV_PORT "com.android.trusty.sancov.test.srv" +#define TEST_SRV_MODULE "srv.syms.elf" + +#define FLAG_NONE 0x0 +#define FLAG_RUN 0x1 +#define FLAG_TOGGLE_CLEAR 0x2 + +struct control { + /* Written by controller, read by instrumented TA */ + uint64_t cntrl_flags; + + /* Written by instrumented TA, read by controller */ + uint64_t oper_flags; + uint64_t write_buffer_start_count; + uint64_t write_buffer_complete_count; +}; + +namespace android { +namespace trusty { +namespace controller { + +class Controller { + public: + public: + void run(std::string output_dir); + + private: + std::vector>record_list_; + std::setuuid_set_; + std::vector counters; + int coverage_srv_fd; + + void connectCoverageServer(); + void setUpShm(); +}; + +} // namespace controller +} // namespace trusty +} // namespace android From 6367e8953aaace4967643a7f2f78d36ae84b1a9c Mon Sep 17 00:00:00 2001 From: Alexander Koskovich Date: Sat, 5 Aug 2023 00:38:29 -0400 Subject: [PATCH 0275/1487] core: fastboot: Fix data not being wiped on do_update * With platform-tools-34.0.4 if you try to wipe data as apart of the fastboot update command it will not work, will just reboot to userspace without running the wipe task. Test: fastboot -w update image.zip, observe that data gets wiped. Also verified 'fastboot update image.zip' does *not* wipe data. Change-Id: I57a2c64029fd4f78968324bdf60251e1e962b3fd --- fastboot/fastboot.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 0bd07ed8054a..3644d9537d77 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1944,7 +1944,6 @@ static void do_update(const char* filename, FlashingPlan* fp) { } ZipImageSource zp = ZipImageSource(zip); fp->source = &zp; - fp->wants_wipe = false; FlashAllTool tool(fp); tool.Flash(); From 76094b499cf630fa55f2dec6aa595abeb6545e92 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 7 Aug 2023 10:12:05 -0700 Subject: [PATCH 0276/1487] snapuserd: Rename snapuserd_merge to merge_worker. This follows the recently added names read_worker and worker. Bug: 288273605 Test: builds Change-Id: Ie75e94405a018dd0068aa24aefd268adb1aee17e --- fs_mgr/libsnapshot/snapuserd/Android.bp | 2 +- .../libsnapshot/snapuserd/user-space-merge/handler_manager.cpp | 2 +- .../user-space-merge/{snapuserd_merge.cpp => merge_worker.cpp} | 2 +- .../user-space-merge/{snapuserd_merge.h => merge_worker.h} | 0 .../libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename fs_mgr/libsnapshot/snapuserd/user-space-merge/{snapuserd_merge.cpp => merge_worker.cpp} (99%) rename fs_mgr/libsnapshot/snapuserd/user-space-merge/{snapuserd_merge.h => merge_worker.h} (100%) diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index f63579b9b372..3d76aceadc2f 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -64,9 +64,9 @@ cc_library_static { "dm-snapshot-merge/snapuserd_readahead.cpp", "snapuserd_buffer.cpp", "user-space-merge/handler_manager.cpp", + "user-space-merge/merge_worker.cpp", "user-space-merge/read_worker.cpp", "user-space-merge/snapuserd_core.cpp", - "user-space-merge/snapuserd_merge.cpp", "user-space-merge/snapuserd_readahead.cpp", "user-space-merge/snapuserd_transitions.cpp", "user-space-merge/snapuserd_verify.cpp", 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 4105b4b4836a..041e5169918e 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp @@ -18,9 +18,9 @@ #include +#include "merge_worker.h" #include "read_worker.h" #include "snapuserd_core.h" -#include "snapuserd_merge.h" namespace android { namespace snapshot { diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp similarity index 99% rename from fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp rename to fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp index 517148d36730..2305a1c485a6 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "snapuserd_merge.h" +#include "merge_worker.h" #include "snapuserd_core.h" diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.h similarity index 100% rename from fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h rename to fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.h 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 12d095afec05..6d09bc9b3d5b 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -23,8 +23,8 @@ #include #include +#include "merge_worker.h" #include "read_worker.h" -#include "snapuserd_merge.h" namespace android { namespace snapshot { From e9277f91f85f1371b1eb6efa67d9b58542ee1c8c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 27 Jun 2023 13:26:43 -0700 Subject: [PATCH 0277/1487] snapuserd: Add an IBlockServer abstraction around dm-user. This adds the planned interface that will abstract around dm-user (for now), and later ublk at which point it can be adjusted as needed. This declares the interface and implements it, but does not yet switch snapuserd to use it. The implementation is copied from read_worker.cpp. Bug: 288273605 Test: snapuserd_test Change-Id: I060788c91dba78e52d315b5616b84b37eaf4040f --- fs_mgr/libsnapshot/snapuserd/Android.bp | 3 +- .../snapuserd/dm_user_block_server.cpp | 146 ++++++++++++++++++ .../include/snapuserd/block_server.h | 87 +++++++++++ .../include/snapuserd/dm_user_block_server.h | 63 ++++++++ .../libsnapshot/snapuserd/snapuserd_logging.h | 20 +++ 5 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp create mode 100644 fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h create mode 100644 fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h create mode 100644 fs_mgr/libsnapshot/snapuserd/snapuserd_logging.h diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 3d76aceadc2f..40dcc2a8e5b3 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -60,8 +60,9 @@ cc_library_static { local_include_dirs: ["include/"], srcs: [ "dm-snapshot-merge/snapuserd.cpp", - "dm-snapshot-merge/snapuserd_worker.cpp", "dm-snapshot-merge/snapuserd_readahead.cpp", + "dm-snapshot-merge/snapuserd_worker.cpp", + "dm_user_block_server.cpp", "snapuserd_buffer.cpp", "user-space-merge/handler_manager.cpp", "user-space-merge/merge_worker.cpp", diff --git a/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp b/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp new file mode 100644 index 000000000000..ae62bc6ba077 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp @@ -0,0 +1,146 @@ +// Copyright (C) 2023 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 + +#include +#include +#include +#include "snapuserd_logging.h" + +namespace android { +namespace snapshot { + +using android::base::unique_fd; + +DmUserBlockServer::DmUserBlockServer(const std::string& misc_name, unique_fd&& ctrl_fd, + Delegate* delegate, size_t buffer_size) + : misc_name_(misc_name), ctrl_fd_(std::move(ctrl_fd)), delegate_(delegate) { + buffer_.Initialize(sizeof(struct dm_user_header) + buffer_size); +} + +bool DmUserBlockServer::ProcessRequests() { + struct dm_user_header* header = buffer_.GetHeaderPtr(); + if (!android::base::ReadFully(ctrl_fd_, header, sizeof(*header))) { + if (errno != ENOTBLK) { + SNAP_PLOG(ERROR) << "Control-read failed"; + } + + SNAP_PLOG(DEBUG) << "ReadDmUserHeader failed...."; + return false; + } + + SNAP_LOG(DEBUG) << "Daemon: msg->seq: " << std::dec << header->seq; + SNAP_LOG(DEBUG) << "Daemon: msg->len: " << std::dec << header->len; + SNAP_LOG(DEBUG) << "Daemon: msg->sector: " << std::dec << header->sector; + SNAP_LOG(DEBUG) << "Daemon: msg->type: " << std::dec << header->type; + SNAP_LOG(DEBUG) << "Daemon: msg->flags: " << std::dec << header->flags; + + if (!ProcessRequest(header)) { + if (header->type != DM_USER_RESP_ERROR) { + SendError(); + } + return false; + } + return true; +} + +bool DmUserBlockServer::ProcessRequest(dm_user_header* header) { + // Use the same header buffer as the response header. + int request_type = header->type; + header->type = DM_USER_RESP_SUCCESS; + header_response_ = true; + + // Reset the output buffer. + buffer_.ResetBufferOffset(); + + switch (request_type) { + case DM_USER_REQ_MAP_READ: + return delegate_->RequestSectors(header->sector, header->len); + + case DM_USER_REQ_MAP_WRITE: + // We should not get any write request to dm-user as we mount all + // partitions as read-only. + SNAP_LOG(ERROR) << "Unexpected write request from dm-user"; + return false; + + default: + SNAP_LOG(ERROR) << "Unexpected request from dm-user: " << request_type; + return false; + } +} + +void* DmUserBlockServer::GetResponseBuffer(size_t size, size_t to_write) { + return buffer_.AcquireBuffer(size, to_write); +} + +bool DmUserBlockServer::SendBufferedIo() { + return WriteDmUserPayload(buffer_.GetPayloadBytesWritten()); +} + +void DmUserBlockServer::SendError() { + struct dm_user_header* header = buffer_.GetHeaderPtr(); + header->type = DM_USER_RESP_ERROR; + // This is an issue with the dm-user interface. There + // is no way to propagate the I/O error back to dm-user + // if we have already communicated the header back. Header + // is responded once at the beginning; however I/O can + // be processed in chunks. If we encounter an I/O error + // somewhere in the middle of the processing, we can't communicate + // this back to dm-user. + // + // TODO: Fix the interface + CHECK(header_response_); + + WriteDmUserPayload(0); +} + +bool DmUserBlockServer::WriteDmUserPayload(size_t size) { + size_t payload_size = size; + void* buf = buffer_.GetPayloadBufPtr(); + if (header_response_) { + payload_size += sizeof(struct dm_user_header); + buf = buffer_.GetBufPtr(); + } + + if (!android::base::WriteFully(ctrl_fd_, buf, payload_size)) { + SNAP_PLOG(ERROR) << "Write to dm-user failed size: " << payload_size; + return false; + } + + // After the first header is sent in response to a request, we cannot + // send any additional headers. + header_response_ = false; + + // Reset the buffer for use by the next request. + buffer_.ResetBufferOffset(); + return true; +} + +DmUserBlockServerOpener::DmUserBlockServerOpener(const std::string& misc_name, + const std::string& dm_user_path) + : misc_name_(misc_name), dm_user_path_(dm_user_path) {} + +std::unique_ptr DmUserBlockServerOpener::Open(IBlockServer::Delegate* delegate, + size_t buffer_size) { + unique_fd fd(open(dm_user_path_.c_str(), O_RDWR | O_CLOEXEC)); + if (fd < 0) { + SNAP_PLOG(ERROR) << "Could not open dm-user path: " << dm_user_path_; + return nullptr; + } + return std::make_unique(misc_name_, std::move(fd), delegate, buffer_size); +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h new file mode 100644 index 000000000000..3be6d1c3e844 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h @@ -0,0 +1,87 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include +#include + +#include + +namespace android { +namespace snapshot { + +// These interfaces model the block device driver component of snapuserd (eg, +// dm-user). + +// An open connection to a userspace block device control +class IBlockServer { + public: + class Delegate { + public: + virtual ~Delegate() {} + + // Respond to a request for reading a contiguous run of sectors. This + // call should be followed by calls to GetResponseBuffer/CommitBuffer + // until the |size| is fulfilled. + // + // If false is returned, an error will be automatically reported unless + // SendError was called. + virtual bool RequestSectors(uint64_t sector, size_t size) = 0; + }; + + virtual ~IBlockServer() {} + + // Process I/O requests. This can block the worker thread until either a + // request is available or the underlying connection has been destroyed. + // + // True indicates that one or more requests was processed. False indicates + // an unrecoverable condition and processing should stop. + virtual bool ProcessRequests() = 0; + + // Return a buffer for fulfilling a RequestSectors request. This buffer + // is valid until calling SendBufferedIo. This cannot be called outside + // of RequestSectors(). + // + // "to_write" must be <= "size". If it is < size, the excess bytes are + // available for writing, but will not be send via SendBufferedIo, and + // may be reallocated in the next call to GetResponseBuffer. + // + // All buffers returned are invalidated after SendBufferedIo or returning + // control from RequestSectors. + virtual void* GetResponseBuffer(size_t size, size_t to_write) = 0; + + // Send all outstanding buffers to the driver, in order. This should + // be called at least once in response to RequestSectors. This returns + // ownership of any buffers returned by GetResponseBuffer. + // + // If false is returned, an error is automatically reported to the driver. + virtual bool SendBufferedIo() = 0; + + void* GetResponseBuffer(size_t size) { return GetResponseBuffer(size, size); } +}; + +class IBlockServerOpener { + public: + virtual ~IBlockServerOpener() = default; + + // Open a connection to the service. This is called on the daemon thread. + // + // buffer_size is the maximum amount of buffered I/O to use. + virtual std::unique_ptr Open(IBlockServer::Delegate* delegate, + size_t buffer_size) = 0; +}; + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h new file mode 100644 index 000000000000..6aecf500d4a2 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h @@ -0,0 +1,63 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include + +#include + +#include +#include + +namespace android { +namespace snapshot { + +class DmUserBlockServer : public IBlockServer { + public: + DmUserBlockServer(const std::string& misc_name, android::base::unique_fd&& ctrl_fd, + Delegate* delegate, size_t buffer_size); + + bool ProcessRequests() override; + void* GetResponseBuffer(size_t size, size_t to_write) override; + bool SendBufferedIo() override; + void SendError(); + + private: + bool ProcessRequest(dm_user_header* header); + bool WriteDmUserPayload(size_t size); + + std::string misc_name_; + android::base::unique_fd ctrl_fd_; + Delegate* delegate_; + + // Per-request state. + BufferSink buffer_; + bool header_response_ = false; +}; + +class DmUserBlockServerOpener : public IBlockServerOpener { + public: + DmUserBlockServerOpener(const std::string& misc_name, const std::string& dm_user_path); + + std::unique_ptr Open(IBlockServer::Delegate* delegate, + size_t buffer_size) override; + + private: + std::string misc_name_; + std::string dm_user_path_; +}; + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_logging.h b/fs_mgr/libsnapshot/snapuserd/snapuserd_logging.h new file mode 100644 index 000000000000..bc470ce1076c --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_logging.h @@ -0,0 +1,20 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include + +#define SNAP_LOG(level) LOG(level) << misc_name_ << ": " +#define SNAP_PLOG(level) PLOG(level) << misc_name_ << ": " From a392fa3c7823d59d0c2e5dae1695969a1ca0e486 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 27 Jun 2023 16:31:20 -0700 Subject: [PATCH 0278/1487] snapuserd: Remove dm-user specific code from ReadWorker. This uses the new IBlockServer abstraction layer instead. Bug: 288273605 Test: snapuserd_test Change-Id: Ie9a781e44da7447426706d4874644aabf1be1946 --- .../include/snapuserd/block_server.h | 2 +- .../user-space-merge/read_worker.cpp | 129 +++--------------- .../snapuserd/user-space-merge/read_worker.h | 19 ++- .../user-space-merge/snapuserd_core.cpp | 6 +- 4 files changed, 31 insertions(+), 125 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h index 3be6d1c3e844..72b73fc0b5f0 100644 --- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h +++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h @@ -38,7 +38,7 @@ class IBlockServer { // // If false is returned, an error will be automatically reported unless // SendError was called. - virtual bool RequestSectors(uint64_t sector, size_t size) = 0; + virtual bool RequestSectors(uint64_t sector, uint64_t size) = 0; }; virtual ~IBlockServer() {} diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp index 7d2e3a613746..ce4be4348f8b 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp @@ -26,18 +26,18 @@ using namespace android::dm; using android::base::unique_fd; void ReadWorker::CloseFds() { - ctrl_fd_ = {}; + block_server_ = {}; backing_store_fd_ = {}; Worker::CloseFds(); } ReadWorker::ReadWorker(const std::string& cow_device, const std::string& backing_device, - const std::string& control_device, const std::string& misc_name, - const std::string& base_path_merge, - std::shared_ptr snapuserd) + const std::string& misc_name, const std::string& base_path_merge, + std::shared_ptr snapuserd, + std::shared_ptr opener) : Worker(cow_device, misc_name, base_path_merge, snapuserd), backing_store_device_(backing_device), - control_device_(control_device) {} + block_server_opener_(opener) {} // Start the replace operation. This will read the // internal COW format and if the block is compressed, @@ -197,9 +197,9 @@ bool ReadWorker::Init() { return false; } - ctrl_fd_.reset(open(control_device_.c_str(), O_RDWR)); - if (ctrl_fd_ < 0) { - SNAP_PLOG(ERROR) << "Unable to open " << control_device_; + block_server_ = block_server_opener_->Open(this, PAYLOAD_BUFFER_SZ); + if (!block_server_) { + SNAP_PLOG(ERROR) << "Unable to open block server"; return false; } return true; @@ -214,7 +214,7 @@ bool ReadWorker::Run() { // Start serving IO while (true) { - if (!ProcessIORequest()) { + if (!block_server_->ProcessRequests()) { break; } } @@ -225,29 +225,6 @@ bool ReadWorker::Run() { return true; } -// Send the payload/data back to dm-user misc device. -bool ReadWorker::WriteDmUserPayload(size_t size) { - size_t payload_size = size; - void* buf = bufsink_.GetPayloadBufPtr(); - if (header_response_) { - payload_size += sizeof(struct dm_user_header); - buf = bufsink_.GetBufPtr(); - } - - if (!android::base::WriteFully(ctrl_fd_, buf, payload_size)) { - SNAP_PLOG(ERROR) << "Write to dm-user failed size: " << payload_size; - return false; - } - - // After the first header is sent in response to a request, we cannot - // send any additional headers. - header_response_ = false; - - // Reset the buffer for use by the next request. - bufsink_.ResetBufferOffset(); - return true; -} - bool ReadWorker::ReadDataFromBaseDevice(sector_t sector, void* buffer, size_t read_size) { CHECK(read_size <= BLOCK_SZ); @@ -281,7 +258,7 @@ bool ReadWorker::ReadAlignedSector(sector_t sector, size_t sz) { std::make_pair(sector, nullptr), SnapshotHandler::compare); bool not_found = (it == chunk_vec.end() || it->first != sector); - void* buffer = bufsink_.AcquireBuffer(BLOCK_SZ, size); + void* buffer = block_server_->GetResponseBuffer(BLOCK_SZ, size); if (!buffer) { SNAP_LOG(ERROR) << "AcquireBuffer failed in ReadAlignedSector"; return false; @@ -334,7 +311,8 @@ int ReadWorker::ReadUnalignedSector( int num_sectors_skip = sector - it->first; size_t skip_size = num_sectors_skip << SECTOR_SHIFT; size_t write_size = std::min(size, BLOCK_SZ - skip_size); - auto buffer = reinterpret_cast(bufsink_.AcquireBuffer(BLOCK_SZ, write_size)); + auto buffer = + reinterpret_cast(block_server_->GetResponseBuffer(BLOCK_SZ, write_size)); if (!buffer) { SNAP_LOG(ERROR) << "ProcessCowOp failed to allocate buffer"; return -1; @@ -462,7 +440,7 @@ bool ReadWorker::ReadUnalignedSector(sector_t sector, size_t size) { CHECK(diff_size <= BLOCK_SZ); size_t read_size = std::min(remaining_size, diff_size); - void* buffer = bufsink_.AcquireBuffer(BLOCK_SZ, read_size); + void* buffer = block_server_->GetResponseBuffer(BLOCK_SZ, read_size); if (!buffer) { SNAP_LOG(ERROR) << "AcquireBuffer failed in ReadUnalignedSector"; return false; @@ -488,88 +466,17 @@ bool ReadWorker::ReadUnalignedSector(sector_t sector, size_t size) { return true; } -void ReadWorker::RespondIOError() { - struct dm_user_header* header = bufsink_.GetHeaderPtr(); - header->type = DM_USER_RESP_ERROR; - // This is an issue with the dm-user interface. There - // is no way to propagate the I/O error back to dm-user - // if we have already communicated the header back. Header - // is responded once at the beginning; however I/O can - // be processed in chunks. If we encounter an I/O error - // somewhere in the middle of the processing, we can't communicate - // this back to dm-user. - // - // TODO: Fix the interface - CHECK(header_response_); - - WriteDmUserPayload(0); -} - -bool ReadWorker::DmuserReadRequest() { - struct dm_user_header* header = bufsink_.GetHeaderPtr(); - +bool ReadWorker::RequestSectors(uint64_t sector, uint64_t len) { // Unaligned I/O request - if (!IsBlockAligned(header->sector << SECTOR_SHIFT)) { - return ReadUnalignedSector(header->sector, header->len); + if (!IsBlockAligned(sector << SECTOR_SHIFT)) { + return ReadUnalignedSector(sector, len); } - return ReadAlignedSector(header->sector, header->len); + return ReadAlignedSector(sector, len); } bool ReadWorker::SendBufferedIo() { - return WriteDmUserPayload(bufsink_.GetPayloadBytesWritten()); -} - -bool ReadWorker::ProcessIORequest() { - // Read Header from dm-user misc device. This gives - // us the sector number for which IO is issued by dm-snapshot device - struct dm_user_header* header = bufsink_.GetHeaderPtr(); - if (!android::base::ReadFully(ctrl_fd_, header, sizeof(*header))) { - if (errno != ENOTBLK) { - SNAP_PLOG(ERROR) << "Control-read failed"; - } - - SNAP_PLOG(DEBUG) << "ReadDmUserHeader failed...."; - return false; - } - - SNAP_LOG(DEBUG) << "Daemon: msg->seq: " << std::dec << header->seq; - SNAP_LOG(DEBUG) << "Daemon: msg->len: " << std::dec << header->len; - SNAP_LOG(DEBUG) << "Daemon: msg->sector: " << std::dec << header->sector; - SNAP_LOG(DEBUG) << "Daemon: msg->type: " << std::dec << header->type; - SNAP_LOG(DEBUG) << "Daemon: msg->flags: " << std::dec << header->flags; - - // Use the same header buffer as the response header. - int request_type = header->type; - header->type = DM_USER_RESP_SUCCESS; - header_response_ = true; - - // Reset the output buffer. - bufsink_.ResetBufferOffset(); - - bool ok; - switch (request_type) { - case DM_USER_REQ_MAP_READ: - ok = DmuserReadRequest(); - break; - - case DM_USER_REQ_MAP_WRITE: - // TODO: We should not get any write request - // to dm-user as we mount all partitions - // as read-only. Need to verify how are TRIM commands - // handled during mount. - ok = false; - break; - - default: - ok = false; - break; - } - - if (!ok && header->type != DM_USER_RESP_ERROR) { - RespondIOError(); - } - return ok; + return block_server_->SendBufferedIo(); } } // namespace snapshot diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h index 8d6f66379359..a6a3eb8ca54d 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h @@ -17,28 +17,26 @@ #include #include +#include #include "worker.h" namespace android { namespace snapshot { -class ReadWorker : public Worker { +class ReadWorker : public Worker, public IBlockServer::Delegate { public: ReadWorker(const std::string& cow_device, const std::string& backing_device, - const std::string& control_device, const std::string& misc_name, - const std::string& base_path_merge, std::shared_ptr snapuserd); + const std::string& misc_name, const std::string& base_path_merge, + std::shared_ptr snapuserd, + std::shared_ptr opener); bool Run(); bool Init() override; void CloseFds() override; private: - // Functions interacting with dm-user - bool ProcessIORequest(); - bool WriteDmUserPayload(size_t size); - bool DmuserReadRequest(); + bool RequestSectors(uint64_t sector, uint64_t size) override; bool SendBufferedIo(); - void RespondIOError(); bool ProcessCowOp(const CowOperation* cow_op, void* buffer); bool ProcessXorOp(const CowOperation* cow_op, void* buffer); @@ -60,10 +58,9 @@ class ReadWorker : public Worker { std::string backing_store_device_; unique_fd backing_store_fd_; - std::string control_device_; - unique_fd ctrl_fd_; + std::shared_ptr block_server_opener_; + std::unique_ptr block_server_; - bool header_response_ = false; std::basic_string xor_buffer_; }; 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 6d09bc9b3d5b..6d3d5c7ad639 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "merge_worker.h" #include "read_worker.h" @@ -48,9 +49,10 @@ SnapshotHandler::SnapshotHandler(std::string misc_name, std::string cow_device, } bool SnapshotHandler::InitializeWorkers() { + auto opener = std::make_shared(misc_name_, control_device_); for (int i = 0; i < num_worker_threads_; i++) { - auto wt = std::make_unique(cow_device_, backing_store_device_, control_device_, - misc_name_, base_path_merge_, GetSharedPtr()); + auto wt = std::make_unique(cow_device_, backing_store_device_, misc_name_, + base_path_merge_, GetSharedPtr(), opener); if (!wt->Init()) { SNAP_LOG(ERROR) << "Thread initialization failed"; return false; From 7728c6c998abcec2461b80cd6aea56e38c568725 Mon Sep 17 00:00:00 2001 From: Snehal Date: Thu, 3 Aug 2023 16:51:20 +0000 Subject: [PATCH 0279/1487] Add mikemcternan@ to OWNERS Change-Id: Ia414e191eab2b2e3139b94fa8c94ea54f4fbf308 --- trusty/OWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/trusty/OWNERS b/trusty/OWNERS index 61b97c6410fd..bf1691275b67 100644 --- a/trusty/OWNERS +++ b/trusty/OWNERS @@ -3,6 +3,7 @@ arve@android.com danielangell@google.com gmar@google.com marcone@google.com +mikemcternan@google.com mmaurer@google.com ncbray@google.com swillden@google.com From 2cffe186ada6ddc3e474a0be97c9d74e12c4b880 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 7 Aug 2023 10:09:10 -0700 Subject: [PATCH 0280/1487] snapuserd: Remove ambiguous BufferSink in workers. BufferSink is not needed/used in all worker types, so move it explicitly to MergeWorker. This also moves the sizeof(dm_user_header) computation to BufferSink::Initialize. Bug: 288273605 Test: snapuserd_test Change-Id: I8fcea6f0e587ca6d8672df5ec58c4d4d14d4b72e --- fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp | 2 +- fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp | 4 ++-- .../snapuserd/user-space-merge/merge_worker.cpp | 2 ++ .../snapuserd/user-space-merge/merge_worker.h | 1 + .../libsnapshot/snapuserd/user-space-merge/worker.cpp | 11 ----------- .../libsnapshot/snapuserd/user-space-merge/worker.h | 3 --- 6 files changed, 6 insertions(+), 17 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp b/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp index ae62bc6ba077..b5fef4787f19 100644 --- a/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp +++ b/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp @@ -27,7 +27,7 @@ using android::base::unique_fd; DmUserBlockServer::DmUserBlockServer(const std::string& misc_name, unique_fd&& ctrl_fd, Delegate* delegate, size_t buffer_size) : misc_name_(misc_name), ctrl_fd_(std::move(ctrl_fd)), delegate_(delegate) { - buffer_.Initialize(sizeof(struct dm_user_header) + buffer_size); + buffer_.Initialize(buffer_size); } bool DmUserBlockServer::ProcessRequests() { diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp index 35065e61ef86..490c0e63a1bc 100644 --- a/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp +++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp @@ -23,9 +23,9 @@ namespace android { namespace snapshot { void BufferSink::Initialize(size_t size) { - buffer_size_ = size; + buffer_size_ = size + sizeof(struct dm_user_header); buffer_offset_ = 0; - buffer_ = std::make_unique(size); + buffer_ = std::make_unique(buffer_size_); } void* BufferSink::AcquireBuffer(size_t size, size_t to_write) { diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp index 2305a1c485a6..a83cab8d8b4c 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp @@ -556,6 +556,8 @@ bool MergeWorker::Run() { SNAP_LOG(INFO) << "Merge starting.."; + bufsink_.Initialize(PAYLOAD_BUFFER_SZ); + if (!Init()) { SNAP_LOG(ERROR) << "Merge thread initialization failed..."; snapuserd_->MergeFailed(); diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.h index f35147f2beb6..478d4c8a270c 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.h @@ -39,6 +39,7 @@ class MergeWorker : public Worker { void FinalizeIouring(); private: + BufferSink bufsink_; std::unique_ptr cowop_iter_; std::unique_ptr ring_; size_t ra_block_index_ = 0; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.cpp index aa156301fa3b..65208fb8bac9 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.cpp @@ -27,18 +27,7 @@ Worker::Worker(const std::string& cow_device, const std::string& misc_name, snapuserd_ = snapuserd; } -void Worker::InitializeBufsink() { - // Allocate the buffer which is used to communicate between - // daemon and dm-user. The buffer comprises of header and a fixed payload. - // If the dm-user requests a big IO, the IO will be broken into chunks - // of PAYLOAD_BUFFER_SZ. - size_t buf_size = sizeof(struct dm_user_header) + PAYLOAD_BUFFER_SZ; - bufsink_.Initialize(buf_size); -} - bool Worker::Init() { - InitializeBufsink(); - if (!InitializeFds()) { return false; } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h index 813b159eaee3..c89d1b4fd558 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h @@ -40,14 +40,11 @@ class Worker { virtual bool Init(); protected: - // Initialization - void InitializeBufsink(); bool InitializeFds(); bool InitReader(); virtual void CloseFds() { base_path_merge_fd_ = {}; } std::unique_ptr reader_; - BufferSink bufsink_; std::string misc_name_; // Needed for SNAP_LOG. From 384b22ce587766fb985dffaafee4c804b18c0109 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 28 Jun 2023 11:22:00 -0700 Subject: [PATCH 0281/1487] snapuserd: Add an IBlockServerFactory abstraction. To avoid SnapshotHandler hardcoding specifics about dm-user, this patch adds a factory interface, responsible for providing IBlockServerOpener objects. The test harness will use this to facilitate dm-user-less testing on host devices. Bug: 288273605 Test: snapuserd_test Change-Id: Ifd33c28ee7076f30a8a90f745353893188f97a08 --- fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp | 6 ++++++ .../snapuserd/include/snapuserd/block_server.h | 8 ++++++++ .../snapuserd/include/snapuserd/dm_user_block_server.h | 5 +++++ .../snapuserd/user-space-merge/handler_manager.cpp | 5 +++-- .../snapuserd/user-space-merge/handler_manager.h | 3 +++ .../snapuserd/user-space-merge/snapuserd_core.cpp | 10 +++++----- .../snapuserd/user-space-merge/snapuserd_core.h | 6 ++++-- .../snapuserd/user-space-merge/snapuserd_server.cpp | 7 ++++++- .../snapuserd/user-space-merge/snapuserd_server.h | 2 ++ .../snapuserd/user-space-merge/snapuserd_test.cpp | 7 +++++-- 10 files changed, 47 insertions(+), 12 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp b/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp index b5fef4787f19..e98833502554 100644 --- a/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp +++ b/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp @@ -142,5 +142,11 @@ std::unique_ptr DmUserBlockServerOpener::Open(IBlockServer::Delega return std::make_unique(misc_name_, std::move(fd), delegate, buffer_size); } +std::shared_ptr DmUserBlockServerFactory::CreateOpener( + const std::string& misc_name) { + auto dm_path = "/dev/dm-user/" + misc_name; + return std::make_shared(misc_name, dm_path); +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h index 72b73fc0b5f0..406bf11c34ca 100644 --- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h +++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h @@ -83,5 +83,13 @@ class IBlockServerOpener { size_t buffer_size) = 0; }; +class IBlockServerFactory { + public: + virtual ~IBlockServerFactory() {} + + // Return a new IBlockServerOpener given a unique device name. + virtual std::shared_ptr CreateOpener(const std::string& misc_name) = 0; +}; + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h index 6aecf500d4a2..f1f8da1430e2 100644 --- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h +++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h @@ -59,5 +59,10 @@ class DmUserBlockServerOpener : public IBlockServerOpener { std::string dm_user_path_; }; +class DmUserBlockServerFactory : public IBlockServerFactory { + public: + std::shared_ptr CreateOpener(const std::string& misc_name) override; +}; + } // namespace snapshot } // namespace android 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 041e5169918e..fd41cd419b3c 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp @@ -50,9 +50,10 @@ SnapshotHandlerManager::SnapshotHandlerManager() { std::shared_ptr SnapshotHandlerManager::AddHandler( const std::string& misc_name, const std::string& cow_device_path, const std::string& backing_device, const std::string& base_path_merge, - int num_worker_threads, bool use_iouring, bool perform_verification) { + std::shared_ptr opener, int num_worker_threads, bool use_iouring, + bool perform_verification) { auto snapuserd = std::make_shared(misc_name, cow_device_path, backing_device, - base_path_merge, num_worker_threads, + base_path_merge, opener, num_worker_threads, use_iouring, perform_verification); if (!snapuserd->InitCowDevice()) { LOG(ERROR) << "Failed to initialize Snapuserd"; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h index b7ddac19f28a..2a6da964e02c 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h @@ -21,6 +21,7 @@ #include #include +#include namespace android { namespace snapshot { @@ -55,6 +56,7 @@ class ISnapshotHandlerManager { const std::string& cow_device_path, const std::string& backing_device, const std::string& base_path_merge, + std::shared_ptr opener, int num_worker_threads, bool use_iouring, bool perform_verification) = 0; @@ -91,6 +93,7 @@ class SnapshotHandlerManager final : public ISnapshotHandlerManager { const std::string& cow_device_path, const std::string& backing_device, const std::string& base_path_merge, + std::shared_ptr opener, int num_worker_threads, bool use_iouring, bool perform_verification) override; bool StartHandler(const std::string& misc_name) override; 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 6d3d5c7ad639..5a82ca1f4d92 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -36,12 +36,12 @@ using android::base::unique_fd; SnapshotHandler::SnapshotHandler(std::string misc_name, std::string cow_device, std::string backing_device, std::string base_path_merge, - int num_worker_threads, bool use_iouring, - bool perform_verification) { + std::shared_ptr opener, int num_worker_threads, + bool use_iouring, bool perform_verification) { misc_name_ = std::move(misc_name); cow_device_ = std::move(cow_device); backing_store_device_ = std::move(backing_device); - control_device_ = "/dev/dm-user/" + misc_name_; + block_server_opener_ = std::move(opener); base_path_merge_ = std::move(base_path_merge); num_worker_threads_ = num_worker_threads; is_io_uring_enabled_ = use_iouring; @@ -49,10 +49,10 @@ SnapshotHandler::SnapshotHandler(std::string misc_name, std::string cow_device, } bool SnapshotHandler::InitializeWorkers() { - auto opener = std::make_shared(misc_name_, control_device_); for (int i = 0; i < num_worker_threads_; i++) { auto wt = std::make_unique(cow_device_, backing_store_device_, misc_name_, - base_path_merge_, GetSharedPtr(), opener); + base_path_merge_, GetSharedPtr(), + block_server_opener_); if (!wt->Init()) { SNAP_LOG(ERROR) << "Thread initialization failed"; return false; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index 5fe0a709af8e..a45e0bcc76e7 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -102,8 +103,8 @@ struct MergeGroupState { class SnapshotHandler : public std::enable_shared_from_this { public: SnapshotHandler(std::string misc_name, std::string cow_device, std::string backing_device, - std::string base_path_merge, int num_workers, bool use_iouring, - bool perform_verification); + std::string base_path_merge, std::shared_ptr opener, + int num_workers, bool use_iouring, bool perform_verification); bool InitCowDevice(); bool Start(); @@ -242,6 +243,7 @@ class SnapshotHandler : public std::enable_shared_from_this { std::unique_ptr ring_; std::unique_ptr update_verify_; + std::shared_ptr block_server_opener_; }; } // namespace snapshot 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 f2585eab1d81..13b9a00b8a4b 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "snapuserd_server.h" @@ -48,6 +49,7 @@ using android::base::unique_fd; UserSnapshotServer::UserSnapshotServer() { terminating_ = false; handlers_ = std::make_unique(); + block_server_factory_ = std::make_unique(); } UserSnapshotServer::~UserSnapshotServer() { @@ -363,8 +365,11 @@ std::shared_ptr UserSnapshotServer::AddHandler(const std::string& perform_verification = false; } + auto opener = block_server_factory_->CreateOpener(misc_name); + return handlers_->AddHandler(misc_name, cow_device_path, backing_device, base_path_merge, - num_worker_threads, io_uring_enabled_, perform_verification); + opener, num_worker_threads, io_uring_enabled_, + perform_verification); } bool UserSnapshotServer::WaitForSocket() { diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h index 988c01a99ba3..be285412f903 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h @@ -31,6 +31,7 @@ #include #include +#include #include "handler_manager.h" #include "snapuserd_core.h" @@ -50,6 +51,7 @@ class UserSnapshotServer { bool is_server_running_ = false; bool io_uring_enabled_ = false; std::unique_ptr handlers_; + std::unique_ptr block_server_factory_; std::mutex lock_; 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 16f9ed87f7ac..157925d63d59 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -37,8 +37,8 @@ #include #include #include +#include #include - #include "handler_manager.h" #include "snapuserd_core.h" #include "testing/temp_device.h" @@ -535,9 +535,12 @@ void SnapuserdTest::InitCowDevice() { use_iouring = false; } + DmUserBlockServerFactory factory; + + auto opener = factory.CreateOpener(system_device_ctrl_name_); auto handler = handlers_.AddHandler(system_device_ctrl_name_, cow_system_->path, base_loop_->device(), - base_loop_->device(), 1, use_iouring, false); + base_loop_->device(), opener, 1, use_iouring, false); ASSERT_NE(handler, nullptr); ASSERT_NE(handler->snapuserd(), nullptr); #ifdef __ANDROID__ From fe032d03914bf04e413927b89ba0b349bb5adb94 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 3 Aug 2023 16:44:27 -0700 Subject: [PATCH 0282/1487] snapuserd: Add a harness to run tests without dm-user specific code. This patch adds an abstraction layer around Tempdevice (which wraps device-mapper), and a layer to replace hardcoding of DmUserBlockServer. The only implementation of the new layer, currently, is for dm-user. However this will allow the harness to run with a backend chosen at runtime, making testing on the host or of ublk much easier. Bug: 288273605 Test: snapuserd_test Change-Id: I8735ef6c373f3e5c5cdf3df461668ddd8e551f63 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 1 + .../snapuserd/testing/dm_user_harness.cpp | 67 +++++++++++++++++++ .../snapuserd/testing/dm_user_harness.h | 54 +++++++++++++++ .../libsnapshot/snapuserd/testing/harness.h | 47 +++++++++++++ .../user-space-merge/snapuserd_test.cpp | 51 +++++++------- 5 files changed, 197 insertions(+), 23 deletions(-) create mode 100644 fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.cpp create mode 100644 fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.h create mode 100644 fs_mgr/libsnapshot/snapuserd/testing/harness.h diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 40dcc2a8e5b3..2368f8f360a0 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -219,6 +219,7 @@ cc_test { "libsnapshot_cow_defaults", ], srcs: [ + "testing/dm_user_harness.cpp", "user-space-merge/snapuserd_test.cpp", ], shared_libs: [ diff --git a/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.cpp b/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.cpp new file mode 100644 index 000000000000..7cadf250c267 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.cpp @@ -0,0 +1,67 @@ +// Copyright (C) 2023 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 "dm_user_harness.h" + +#include + +#include +#include +#include +#include + +namespace android { +namespace snapshot { + +using namespace std::chrono_literals; +using android::base::unique_fd; + +DmUserDevice::DmUserDevice(std::unique_ptr&& dev) : dev_(std::move(dev)) {} + +const std::string& DmUserDevice::GetPath() { + return dev_->path(); +} + +bool DmUserDevice::Destroy() { + return dev_->Destroy(); +} + +DmUserTestHarness::DmUserTestHarness() { + block_server_factory_ = std::make_unique(); +} + +std::unique_ptr DmUserTestHarness::CreateUserDevice(const std::string& dev_name, + const std::string& misc_name, + uint64_t num_sectors) { + android::dm::DmTable dmuser_table; + dmuser_table.Emplace(0, num_sectors, misc_name); + auto dev = std::make_unique(dev_name, dmuser_table); + if (!dev->valid()) { + return nullptr; + } + + auto misc_device = "/dev/dm-user/" + misc_name; + if (!android::fs_mgr::WaitForFile(misc_device, 10s)) { + return nullptr; + } + + return std::make_unique(std::move(dev)); +} + +IBlockServerFactory* DmUserTestHarness::GetBlockServerFactory() { + return block_server_factory_.get(); +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.h b/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.h new file mode 100644 index 000000000000..cf26bed037c1 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.h @@ -0,0 +1,54 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include + +#include "harness.h" +#include "temp_device.h" + +namespace android { +namespace snapshot { + +using android::base::unique_fd; + +class DmUserBlockServerFactory; + +class DmUserDevice final : public IUserDevice { + public: + explicit DmUserDevice(std::unique_ptr&& dev); + const std::string& GetPath() override; + bool Destroy() override; + + private: + std::unique_ptr dev_; +}; + +class DmUserTestHarness final : public ITestHarness { + public: + DmUserTestHarness(); + + std::unique_ptr CreateUserDevice(const std::string& dev_name, + const std::string& misc_name, + uint64_t num_sectors) override; + IBlockServerFactory* GetBlockServerFactory() override; + bool HasUserDevice() override { return true; } + + private: + std::unique_ptr block_server_factory_; +}; + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/testing/harness.h b/fs_mgr/libsnapshot/snapuserd/testing/harness.h new file mode 100644 index 000000000000..c0d528f8ba78 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/testing/harness.h @@ -0,0 +1,47 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include +#include + +#include + +#include +#include + +namespace android { +namespace snapshot { + +// Interface for a "block driver in userspace" device. +class IUserDevice { + public: + virtual ~IUserDevice() {} + virtual const std::string& GetPath() = 0; + virtual bool Destroy() = 0; +}; + +class ITestHarness { + public: + virtual ~ITestHarness() {} + virtual std::unique_ptr CreateUserDevice(const std::string& dev_name, + const std::string& misc_name, + uint64_t num_sectors) = 0; + virtual IBlockServerFactory* GetBlockServerFactory() = 0; + virtual bool HasUserDevice() = 0; +}; + +} // namespace snapshot +} // namespace android 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 157925d63d59..4ea1d5d08ead 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -41,6 +41,7 @@ #include #include "handler_manager.h" #include "snapuserd_core.h" +#include "testing/dm_user_harness.h" #include "testing/temp_device.h" DEFINE_string(force_config, "", "Force testing mode with iouring disabled"); @@ -75,10 +76,9 @@ class SnapuserdTest : public ::testing::Test { static const uint64_t kSectorSize = 512; protected: - void SetUp() override {} + void SetUp() override; void TearDown() override { Shutdown(); } - private: void SetupImpl(); void SimulateDaemonRestart(); @@ -94,10 +94,10 @@ class SnapuserdTest : public ::testing::Test { void InitCowDevice(); void SetDeviceControlName(); void InitDaemon(); - void CreateDmUserDevice(); + void CreateUserDevice(); unique_ptr base_loop_; - unique_ptr dmuser_dev_; + unique_ptr dmuser_dev_; std::string system_device_ctrl_name_; std::string system_device_name_; @@ -112,6 +112,7 @@ class SnapuserdTest : public ::testing::Test { size_t size_ = 100_MiB; int cow_num_sectors_; int total_base_size_; + std::unique_ptr harness_; }; static unique_fd CreateTempFile(const std::string& name, size_t size) { @@ -132,6 +133,10 @@ static unique_fd CreateTempFile(const std::string& name, size_t size) { return fd; } +void SnapuserdTest::SetUp() { + harness_ = std::make_unique(); +} + void SnapuserdTest::Shutdown() { ASSERT_TRUE(dmuser_dev_->Destroy()); @@ -173,7 +178,7 @@ bool SnapuserdTest::SetupCopyOverlap_2() { bool SnapuserdTest::SetupDaemon() { SetDeviceControlName(); - CreateDmUserDevice(); + CreateUserDevice(); InitCowDevice(); InitDaemon(); @@ -206,7 +211,7 @@ void SnapuserdTest::CreateBaseDevice() { } void SnapuserdTest::ReadSnapshotDeviceAndValidate() { - unique_fd fd(open(dmuser_dev_->path().c_str(), O_RDONLY)); + unique_fd fd(open(dmuser_dev_->GetPath().c_str(), O_RDONLY)); ASSERT_GE(fd, 0); std::unique_ptr snapuserd_buffer = std::make_unique(size_); @@ -535,9 +540,8 @@ void SnapuserdTest::InitCowDevice() { use_iouring = false; } - DmUserBlockServerFactory factory; - - auto opener = factory.CreateOpener(system_device_ctrl_name_); + auto factory = harness_->GetBlockServerFactory(); + auto opener = factory->CreateOpener(system_device_ctrl_name_); auto handler = handlers_.AddHandler(system_device_ctrl_name_, cow_system_->path, base_loop_->device(), base_loop_->device(), opener, 1, use_iouring, false); @@ -560,7 +564,7 @@ void SnapuserdTest::SetDeviceControlName() { system_device_ctrl_name_ = system_device_name_ + "-ctrl"; } -void SnapuserdTest::CreateDmUserDevice() { +void SnapuserdTest::CreateUserDevice() { unique_fd fd(TEMP_FAILURE_RETRY(open(base_loop_->device().c_str(), O_RDONLY | O_CLOEXEC))); ASSERT_TRUE(fd > 0); @@ -569,17 +573,9 @@ void SnapuserdTest::CreateDmUserDevice() { cow_num_sectors_ = dev_sz >> 9; - DmTable dmuser_table; - ASSERT_TRUE(dmuser_table.AddTarget( - std::make_unique(0, cow_num_sectors_, system_device_ctrl_name_))); - ASSERT_TRUE(dmuser_table.valid()); - - dmuser_dev_ = std::make_unique(system_device_name_, dmuser_table); - ASSERT_TRUE(dmuser_dev_->valid()); - ASSERT_FALSE(dmuser_dev_->path().empty()); - - auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_; - ASSERT_TRUE(android::fs_mgr::WaitForFile(misc_device, 10s)); + dmuser_dev_ = harness_->CreateUserDevice(system_device_name_, system_device_ctrl_name_, + cow_num_sectors_); + ASSERT_NE(dmuser_dev_, nullptr); } void SnapuserdTest::InitDaemon() { @@ -603,7 +599,7 @@ void SnapuserdTest::SetupImpl() { SetDeviceControlName(); - CreateDmUserDevice(); + CreateUserDevice(); InitCowDevice(); InitDaemon(); @@ -632,7 +628,7 @@ void SnapuserdTest::SimulateDaemonRestart() { Shutdown(); std::this_thread::sleep_for(500ms); SetDeviceControlName(); - CreateDmUserDevice(); + CreateUserDevice(); InitCowDevice(); InitDaemon(); } @@ -695,6 +691,9 @@ void SnapuserdTest::MergeInterrupt() { } TEST_F(SnapuserdTest, Snapshot_IO_TEST) { + if (!harness_->HasUserDevice()) { + GTEST_SKIP() << "Skipping snapshot read; not supported"; + } ASSERT_TRUE(SetupDefault()); // I/O before merge ReadSnapshotDeviceAndValidate(); @@ -707,6 +706,9 @@ TEST_F(SnapuserdTest, Snapshot_IO_TEST) { } TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST) { + if (!harness_->HasUserDevice()) { + GTEST_SKIP() << "Skipping snapshot read; not supported"; + } ASSERT_TRUE(SetupDefault()); // Issue I/O before merge begins std::async(std::launch::async, &SnapuserdTest::ReadSnapshotDeviceAndValidate, this); @@ -717,6 +719,9 @@ TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST) { } TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST_1) { + if (!harness_->HasUserDevice()) { + GTEST_SKIP() << "Skipping snapshot read; not supported"; + } ASSERT_TRUE(SetupDefault()); // Start the merge StartMerge(); From dba77ad7377d18eefeaa2cdb661660e39e02e595 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 3 Aug 2023 16:53:55 -0700 Subject: [PATCH 0283/1487] snapuserd: Factor setpriority/settid calls into a helper. This allows disabling the code in host builds, since settid() isn't available in the glibc prebuilt. Bug: 288273605 Test: snapuserd_test Change-Id: Ifddb5cb8b04484a1ab0a29794d65c9839759a919 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 1 + .../user-space-merge/merge_worker.cpp | 5 +-- .../user-space-merge/read_worker.cpp | 5 +-- .../user-space-merge/snapuserd_readahead.cpp | 5 +-- .../user-space-merge/snapuserd_test.cpp | 1 + fs_mgr/libsnapshot/snapuserd/utility.cpp | 36 +++++++++++++++++++ fs_mgr/libsnapshot/snapuserd/utility.h | 23 ++++++++++++ 7 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 fs_mgr/libsnapshot/snapuserd/utility.cpp create mode 100644 fs_mgr/libsnapshot/snapuserd/utility.h diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 2368f8f360a0..6251e5aeafb3 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -72,6 +72,7 @@ cc_library_static { "user-space-merge/snapuserd_transitions.cpp", "user-space-merge/snapuserd_verify.cpp", "user-space-merge/worker.cpp", + "utility.cpp", ], static_libs: [ "libbase", diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp index a83cab8d8b4c..2d6972171ea7 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp @@ -16,6 +16,7 @@ #include "merge_worker.h" #include "snapuserd_core.h" +#include "utility.h" namespace android { namespace snapshot { @@ -550,8 +551,8 @@ bool MergeWorker::Run() { return true; } - if (setpriority(PRIO_PROCESS, gettid(), kNiceValueForMergeThreads)) { - SNAP_PLOG(ERROR) << "Failed to set priority for TID: " << gettid(); + if (!SetThreadPriority(kNiceValueForMergeThreads)) { + SNAP_PLOG(ERROR) << "Failed to set thread priority"; } SNAP_LOG(INFO) << "Merge starting.."; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp index ce4be4348f8b..e2c292bd85bb 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp @@ -17,6 +17,7 @@ #include "read_worker.h" #include "snapuserd_core.h" +#include "utility.h" namespace android { namespace snapshot { @@ -208,8 +209,8 @@ bool ReadWorker::Init() { bool ReadWorker::Run() { SNAP_LOG(INFO) << "Processing snapshot I/O requests...."; - if (setpriority(PRIO_PROCESS, gettid(), kNiceValueForMergeThreads)) { - SNAP_PLOG(ERROR) << "Failed to set priority for TID: " << gettid(); + if (!SetThreadPriority(kNiceValueForMergeThreads)) { + SNAP_PLOG(ERROR) << "Failed to set thread priority"; } // Start serving IO diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp index 8755820e1ed2..8b799ea93a7c 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp @@ -17,6 +17,7 @@ #include "snapuserd_readahead.h" #include "snapuserd_core.h" +#include "utility.h" namespace android { namespace snapshot { @@ -765,8 +766,8 @@ bool ReadAhead::RunThread() { InitializeIouring(); - if (setpriority(PRIO_PROCESS, gettid(), kNiceValueForMergeThreads)) { - SNAP_PLOG(ERROR) << "Failed to set priority for TID: " << gettid(); + if (!SetThreadPriority(kNiceValueForMergeThreads)) { + SNAP_PLOG(ERROR) << "Failed to set thread priority"; } while (!RAIterDone()) { 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 4ea1d5d08ead..c40783499bb0 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -43,6 +43,7 @@ #include "snapuserd_core.h" #include "testing/dm_user_harness.h" #include "testing/temp_device.h" +#include "utility.h" DEFINE_string(force_config, "", "Force testing mode with iouring disabled"); diff --git a/fs_mgr/libsnapshot/snapuserd/utility.cpp b/fs_mgr/libsnapshot/snapuserd/utility.cpp new file mode 100644 index 000000000000..a84a7c14fc5e --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/utility.cpp @@ -0,0 +1,36 @@ +// Copyright (C) 2023 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 "utility.h" + +#include +#include + +#include + +namespace android { +namespace snapshot { + +using android::base::unique_fd; + +bool SetThreadPriority([[maybe_unused]] int priority) { +#ifdef __ANDROID__ + return setpriority(PRIO_PROCESS, gettid(), priority) != -1; +#else + return true; +#endif +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/utility.h b/fs_mgr/libsnapshot/snapuserd/utility.h new file mode 100644 index 000000000000..58ec3e63a3b3 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/utility.h @@ -0,0 +1,23 @@ +// Copyright (C) 2023 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. + +#pragma once + +namespace android { +namespace snapshot { + +bool SetThreadPriority(int priority); + +} // namespace snapshot +} // namespace android From 1cb36d300e3366d000086a0b2cac06c8187d34cb Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 8 Aug 2023 08:51:48 -0700 Subject: [PATCH 0284/1487] Adding struct to hold compresion parameters Since we're adding compression levels should consolidate this information into one structure. Adding in CowCompression struct to hold this information and refactoring code to work off this struct Test: ota Change-Id: I969a3ae19ec80fd964bcfb76b39f42f8dd31a56d --- .../include/libsnapshot/cow_format.h | 4 ++++ fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp | 3 ++- .../libsnapshot/libsnapshot_cow/writer_v2.cpp | 18 +++++++++--------- fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h | 2 +- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h index 3a81f6384e7d..c9a4dee3af41 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h @@ -161,6 +161,10 @@ enum CowCompressionAlgorithm : uint8_t { kCowCompressLz4 = 3, kCowCompressZstd = 4, }; +struct CowCompression { + CowCompressionAlgorithm algorithm = kCowCompressNone; + uint32_t compression_level = 0; +}; static constexpr uint8_t kCowReadAheadNotStarted = 0; static constexpr uint8_t kCowReadAheadInProgress = 1; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp index 31b9a5840934..ab275d4eba0f 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp @@ -472,9 +472,10 @@ TEST_P(CompressionTest, HorribleStream) { if (strcmp(GetParam(), "none") == 0) { GTEST_SKIP(); } - + CowCompression compression; auto algorithm = CompressionAlgorithmFromString(GetParam()); ASSERT_TRUE(algorithm.has_value()); + compression.algorithm = algorithm.value(); std::string expected = "The quick brown fox jumps over the lazy dog."; expected.resize(4096, '\0'); diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp index c5499697286d..cbd7569d210f 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp @@ -124,7 +124,7 @@ bool CowWriterV2::ParseOptions() { LOG(ERROR) << "unrecognized compression: " << options_.compression; return false; } - compression_ = *algorithm; + compression_.algorithm = *algorithm; if (options_.cluster_ops == 1) { LOG(ERROR) << "Clusters must contain at least two operations to function."; @@ -165,7 +165,7 @@ void CowWriterV2::InitWorkers() { return; } for (int i = 0; i < num_compress_threads_; i++) { - auto wt = std::make_unique(compression_, header_.block_size); + auto wt = std::make_unique(compression_.algorithm, header_.block_size); threads_.emplace_back(std::async(std::launch::async, &CompressWorker::RunThread, wt.get())); compress_threads_.push_back(std::move(wt)); } @@ -320,8 +320,8 @@ bool CowWriterV2::CompressBlocks(size_t num_blocks, const void* data) { const uint8_t* iter = reinterpret_cast(data); compressed_buf_.clear(); if (num_threads <= 1) { - return CompressWorker::CompressBlocks(compression_, options_.block_size, data, num_blocks, - &compressed_buf_); + return CompressWorker::CompressBlocks(compression_.algorithm, options_.block_size, data, + num_blocks, &compressed_buf_); } // Submit the blocks per thread. The retrieval of @@ -366,7 +366,7 @@ bool CowWriterV2::EmitBlocks(uint64_t new_block_start, const void* data, size_t while (num_blocks) { size_t pending_blocks = (std::min(kProcessingBlocks, num_blocks)); - if (compression_ && num_compress_threads_ > 1) { + if (compression_.algorithm && num_compress_threads_ > 1) { if (!CompressBlocks(pending_blocks, iter)) { return false; } @@ -386,19 +386,19 @@ bool CowWriterV2::EmitBlocks(uint64_t new_block_start, const void* data, size_t op.source = next_data_pos_; } - if (compression_) { + if (compression_.algorithm) { auto data = [&, this]() { if (num_compress_threads_ > 1) { auto data = std::move(*buf_iter_); buf_iter_++; return data; } else { - auto data = - CompressWorker::Compress(compression_, iter, header_.block_size); + auto data = CompressWorker::Compress(compression_.algorithm, iter, + header_.block_size); return data; } }(); - op.compression = compression_; + op.compression = compression_.algorithm; op.data_length = static_cast(data.size()); if (!WriteOperation(op, data.data(), data.size())) { diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h index 809ae5747935..1aa851872f42 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h @@ -63,7 +63,7 @@ class CowWriterV2 : public CowWriterBase { private: CowFooter footer_{}; - CowCompressionAlgorithm compression_ = kCowCompressNone; + CowCompression compression_; uint64_t current_op_pos_ = 0; uint64_t next_op_pos_ = 0; uint64_t next_data_pos_ = 0; From db70cbf78a874cbb679f92cdf8f395cbc7483c25 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 3 Aug 2023 16:57:12 -0700 Subject: [PATCH 0285/1487] snapuserd: Remove test dependence on LoopDevice. LoopDevice requires root, which is an obstacle to running this test in automation. The test also requires memfd which is not available in our included glibc. Create an IBackingDevice layer so we can use temporary files instead on host tests, while keeping the block-device code for on-device tests, which more closely matches how snapuserd runs. Bug: 288273605 Test: snapuserd_test Change-Id: I89b154921b6bbcf8fe213ef7f5c4da4d48322909 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 1 + .../libsnapshot/snapuserd/testing/harness.cpp | 116 ++++++++++++++++++ .../libsnapshot/snapuserd/testing/harness.h | 9 ++ .../user-space-merge/snapuserd_test.cpp | 47 ++----- 4 files changed, 138 insertions(+), 35 deletions(-) create mode 100644 fs_mgr/libsnapshot/snapuserd/testing/harness.cpp diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 6251e5aeafb3..fc260b6921c4 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -221,6 +221,7 @@ cc_test { ], srcs: [ "testing/dm_user_harness.cpp", + "testing/harness.cpp", "user-space-merge/snapuserd_test.cpp", ], shared_libs: [ diff --git a/fs_mgr/libsnapshot/snapuserd/testing/harness.cpp b/fs_mgr/libsnapshot/snapuserd/testing/harness.cpp new file mode 100644 index 000000000000..02ae549d1cc0 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/testing/harness.cpp @@ -0,0 +1,116 @@ +// Copyright (C) 2023 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 "harness.h" + +#ifdef __ANDROID__ +#include +#endif +#include +#include +#include + +#include +#include +#include +#include "snapuserd_logging.h" + +namespace android { +namespace snapshot { + +using namespace std::chrono_literals; +using android::base::unique_fd; +using android::dm::LoopDevice; + +#ifdef __ANDROID__ +// Prefer this on device since it is a real block device, which is more similar +// to how we use snapuserd. +class MemoryBackedDevice final : public IBackingDevice { + public: + bool Init(uint64_t size) { + memfd_.reset(memfd_create("snapuserd_test", MFD_ALLOW_SEALING)); + if (memfd_ < 0) { + PLOG(ERROR) << "memfd_create failed"; + return false; + } + if (ftruncate(memfd_.get(), size) < 0) { + PLOG(ERROR) << "ftruncate failed"; + return false; + } + if (fcntl(memfd_.get(), F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK) < 0) { + PLOG(ERROR) << "fcntl seal failed"; + return false; + } + dev_ = std::make_unique(memfd_, 10s); + return dev_->valid(); + } + const std::string& GetPath() override { return dev_->device(); } + uint64_t GetSize() override { + unique_fd fd(open(GetPath().c_str(), O_RDONLY | O_CLOEXEC)); + if (fd < 0) { + PLOG(ERROR) << "open failed: " << GetPath(); + return 0; + } + return get_block_device_size(fd.get()); + } + + private: + unique_fd memfd_; + std::unique_ptr dev_; +}; +#endif + +class FileBackedDevice final : public IBackingDevice { + public: + bool Init(uint64_t size) { + if (temp_.fd < 0) { + return false; + } + if (ftruncate(temp_.fd, size) < 0) { + PLOG(ERROR) << "ftruncate failed: " << temp_.path; + return false; + } + path_ = temp_.path; + return true; + } + + const std::string& GetPath() override { return path_; } + uint64_t GetSize() override { + off_t off = lseek(temp_.fd, 0, SEEK_END); + if (off < 0) { + PLOG(ERROR) << "lseek failed: " << temp_.path; + return 0; + } + return off; + } + + private: + TemporaryFile temp_; + std::string path_; +}; + +std::unique_ptr ITestHarness::CreateBackingDevice(uint64_t size) { +#ifdef __ANDROID__ + auto dev = std::make_unique(); +#else + auto dev = std::make_unique(); +#endif + if (!dev->Init(size)) { + return nullptr; + } + return dev; +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/testing/harness.h b/fs_mgr/libsnapshot/snapuserd/testing/harness.h index c0d528f8ba78..ffe9f7bc72e2 100644 --- a/fs_mgr/libsnapshot/snapuserd/testing/harness.h +++ b/fs_mgr/libsnapshot/snapuserd/testing/harness.h @@ -33,6 +33,14 @@ class IUserDevice { virtual bool Destroy() = 0; }; +// Interface for an fd/temp file that is a block device when possible. +class IBackingDevice { + public: + virtual ~IBackingDevice() {} + virtual const std::string& GetPath() = 0; + virtual uint64_t GetSize() = 0; +}; + class ITestHarness { public: virtual ~ITestHarness() {} @@ -41,6 +49,7 @@ class ITestHarness { uint64_t num_sectors) = 0; virtual IBlockServerFactory* GetBlockServerFactory() = 0; virtual bool HasUserDevice() = 0; + virtual std::unique_ptr CreateBackingDevice(uint64_t size); }; } // namespace snapshot 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 c40783499bb0..7e1b2c40f3f7 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -97,7 +96,7 @@ class SnapuserdTest : public ::testing::Test { void InitDaemon(); void CreateUserDevice(); - unique_ptr base_loop_; + unique_ptr base_dev_; unique_ptr dmuser_dev_; std::string system_device_ctrl_name_; @@ -116,24 +115,6 @@ class SnapuserdTest : public ::testing::Test { std::unique_ptr harness_; }; -static unique_fd CreateTempFile(const std::string& name, size_t size) { - unique_fd fd(syscall(__NR_memfd_create, name.c_str(), MFD_ALLOW_SEALING)); - if (fd < 0) { - return {}; - } - if (size) { - if (ftruncate(fd, size) < 0) { - perror("ftruncate"); - return {}; - } - if (fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK) < 0) { - perror("fcntl"); - return {}; - } - } - return fd; -} - void SnapuserdTest::SetUp() { harness_ = std::make_unique(); } @@ -189,14 +170,16 @@ bool SnapuserdTest::SetupDaemon() { } void SnapuserdTest::CreateBaseDevice() { - unique_fd rnd_fd; - total_base_size_ = (size_ * 5); - base_fd_ = CreateTempFile("base_device", total_base_size_); + + base_dev_ = harness_->CreateBackingDevice(total_base_size_); + ASSERT_NE(base_dev_, nullptr); + + base_fd_.reset(open(base_dev_->GetPath().c_str(), O_RDWR | O_CLOEXEC)); ASSERT_GE(base_fd_, 0); - rnd_fd.reset(open("/dev/random", O_RDONLY)); - ASSERT_TRUE(rnd_fd > 0); + unique_fd rnd_fd(open("/dev/random", O_RDONLY)); + ASSERT_GE(rnd_fd, 0); std::unique_ptr random_buffer = std::make_unique(1_MiB); @@ -206,9 +189,6 @@ void SnapuserdTest::CreateBaseDevice() { } ASSERT_EQ(lseek(base_fd_, 0, SEEK_SET), 0); - - base_loop_ = std::make_unique(base_fd_, 10s); - ASSERT_TRUE(base_loop_->valid()); } void SnapuserdTest::ReadSnapshotDeviceAndValidate() { @@ -544,8 +524,8 @@ void SnapuserdTest::InitCowDevice() { auto factory = harness_->GetBlockServerFactory(); auto opener = factory->CreateOpener(system_device_ctrl_name_); auto handler = - handlers_.AddHandler(system_device_ctrl_name_, cow_system_->path, base_loop_->device(), - base_loop_->device(), opener, 1, use_iouring, false); + handlers_.AddHandler(system_device_ctrl_name_, cow_system_->path, base_dev_->GetPath(), + base_dev_->GetPath(), opener, 1, use_iouring, false); ASSERT_NE(handler, nullptr); ASSERT_NE(handler->snapuserd(), nullptr); #ifdef __ANDROID__ @@ -566,11 +546,8 @@ void SnapuserdTest::SetDeviceControlName() { } void SnapuserdTest::CreateUserDevice() { - unique_fd fd(TEMP_FAILURE_RETRY(open(base_loop_->device().c_str(), O_RDONLY | O_CLOEXEC))); - ASSERT_TRUE(fd > 0); - - uint64_t dev_sz = get_block_device_size(fd.get()); - ASSERT_TRUE(dev_sz > 0); + auto dev_sz = base_dev_->GetSize(); + ASSERT_NE(dev_sz, 0); cow_num_sectors_ = dev_sz >> 9; From 02191dbfac2c7a555d9d154ec9b2aa23a8313ebc Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 5 Jul 2023 16:54:42 -0700 Subject: [PATCH 0286/1487] snapuserd: Fix race condition in HandleManager shutdown. When HandlerManager shuts down, the monitor thread is left detached. The monitor thread does not hold a shared_ptr reference to the HandlerManager, so the pointer can be left dangling. Fix this by not detaching the monitor merge thread. This patch also changes the test harness to destroy SnapshotHandlerManager on "shutdown", to avoid state leaking into the next instance of snapuserd. Bug: 288273605 Test: snapuserd_test Change-Id: Iaaf96a37657c85cff4d2a8b15ccfde4aa03d3220 --- .../user-space-merge/handler_manager.cpp | 13 ++++++++----- .../user-space-merge/handler_manager.h | 2 +- .../user-space-merge/snapuserd_test.cpp | 19 +++++++++++-------- 3 files changed, 20 insertions(+), 14 deletions(-) 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 fd41cd419b3c..50b9d4331482 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp @@ -201,9 +201,8 @@ bool SnapshotHandlerManager::StartMerge(std::lock_guard* proof_of_lo handler->snapuserd()->MonitorMerge(); - if (!is_merge_monitor_started_) { - std::thread(&SnapshotHandlerManager::MonitorMerge, this).detach(); - is_merge_monitor_started_ = true; + if (!merge_monitor_.joinable()) { + merge_monitor_ = std::thread(&SnapshotHandlerManager::MonitorMerge, this); } merge_handlers_.push(handler); @@ -357,8 +356,12 @@ void SnapshotHandlerManager::JoinAllThreads() { if (th.joinable()) th.join(); } - stop_monitor_merge_thread_ = true; - WakeupMonitorMergeThread(); + if (merge_monitor_.joinable()) { + stop_monitor_merge_thread_ = true; + WakeupMonitorMergeThread(); + + merge_monitor_.join(); + } } auto SnapshotHandlerManager::FindHandler(std::lock_guard* proof_of_lock, diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h index 2a6da964e02c..b1605f0989fe 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h @@ -122,9 +122,9 @@ class SnapshotHandlerManager final : public ISnapshotHandlerManager { std::mutex lock_; HandlerList dm_users_; - bool is_merge_monitor_started_ = false; bool stop_monitor_merge_thread_ = false; int active_merge_threads_ = 0; + std::thread merge_monitor_; int num_partitions_merge_complete_ = 0; std::queue> merge_handlers_; android::base::unique_fd monitor_merge_event_fd_; 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 7e1b2c40f3f7..0e02f0b853cf 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -106,7 +106,7 @@ class SnapuserdTest : public ::testing::Test { std::unique_ptr cow_system_; std::unique_ptr orig_buffer_; std::unique_ptr merged_buffer_; - SnapshotHandlerManager handlers_; + std::unique_ptr handlers_; bool setup_ok_ = false; bool merge_ok_ = false; size_t size_ = 100_MiB; @@ -117,15 +117,18 @@ class SnapuserdTest : public ::testing::Test { void SnapuserdTest::SetUp() { harness_ = std::make_unique(); + handlers_ = std::make_unique(); } void SnapuserdTest::Shutdown() { ASSERT_TRUE(dmuser_dev_->Destroy()); auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_; - ASSERT_TRUE(handlers_.DeleteHandler(system_device_ctrl_name_)); + ASSERT_TRUE(handlers_->DeleteHandler(system_device_ctrl_name_)); ASSERT_TRUE(android::fs_mgr::WaitForFileDeleted(misc_device, 10s)); - handlers_.TerminateMergeThreads(); + handlers_->TerminateMergeThreads(); + handlers_->JoinAllThreads(); + handlers_ = std::make_unique(); } bool SnapuserdTest::SetupDefault() { @@ -524,8 +527,8 @@ void SnapuserdTest::InitCowDevice() { auto factory = harness_->GetBlockServerFactory(); auto opener = factory->CreateOpener(system_device_ctrl_name_); auto handler = - handlers_.AddHandler(system_device_ctrl_name_, cow_system_->path, base_dev_->GetPath(), - base_dev_->GetPath(), opener, 1, use_iouring, false); + handlers_->AddHandler(system_device_ctrl_name_, cow_system_->path, base_dev_->GetPath(), + base_dev_->GetPath(), opener, 1, use_iouring, false); ASSERT_NE(handler, nullptr); ASSERT_NE(handler->snapuserd(), nullptr); #ifdef __ANDROID__ @@ -557,12 +560,12 @@ void SnapuserdTest::CreateUserDevice() { } void SnapuserdTest::InitDaemon() { - ASSERT_TRUE(handlers_.StartHandler(system_device_ctrl_name_)); + ASSERT_TRUE(handlers_->StartHandler(system_device_ctrl_name_)); } void SnapuserdTest::CheckMergeCompletion() { while (true) { - double percentage = handlers_.GetMergePercentage(); + double percentage = handlers_->GetMergePercentage(); if ((int)percentage == 100) { break; } @@ -592,7 +595,7 @@ bool SnapuserdTest::Merge() { } void SnapuserdTest::StartMerge() { - ASSERT_TRUE(handlers_.InitiateMerge(system_device_ctrl_name_)); + ASSERT_TRUE(handlers_->InitiateMerge(system_device_ctrl_name_)); } void SnapuserdTest::ValidateMerge() { From 9aa421824686f102276a5578db2e9366bc4d2060 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 5 Jul 2023 16:57:28 -0700 Subject: [PATCH 0287/1487] snapuserd: Add diagnostics for debugging races. Adds calls to pthread_setname_np for each thread. Clarify error messages from io_uring calls that return -errno. Add log messages for some failure paths that didn't have any. Add an ostream overload for MERGE_IO_TRANSITION, and add an INVALID state for initialization. Bug: 288273605 Test: builds Change-Id: Ic0681cbf0017af67bcf52b98db184a9b48752faf --- .../user-space-merge/handler_manager.cpp | 4 ++++ .../user-space-merge/merge_worker.cpp | 8 ++++++- .../user-space-merge/read_worker.cpp | 4 ++++ .../user-space-merge/snapuserd_core.cpp | 2 -- .../user-space-merge/snapuserd_core.h | 8 +++++-- .../user-space-merge/snapuserd_readahead.cpp | 12 ++++++++-- .../snapuserd_transitions.cpp | 24 +++++++++++++++++++ 7 files changed, 55 insertions(+), 7 deletions(-) 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 50b9d4331482..d979e20c0c0a 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp @@ -14,6 +14,7 @@ #include "handler_manager.h" +#include #include #include @@ -132,6 +133,8 @@ bool SnapshotHandlerManager::DeleteHandler(const std::string& misc_name) { void SnapshotHandlerManager::RunThread(std::shared_ptr handler) { LOG(INFO) << "Entering thread for handler: " << handler->misc_name(); + pthread_setname_np(pthread_self(), "Handler"); + if (!handler->snapuserd()->Start()) { LOG(ERROR) << " Failed to launch all worker threads"; } @@ -219,6 +222,7 @@ void SnapshotHandlerManager::WakeupMonitorMergeThread() { } void SnapshotHandlerManager::MonitorMerge() { + pthread_setname_np(pthread_self(), "Merge Monitor"); while (!stop_monitor_merge_thread_) { uint64_t testVal; ssize_t ret = diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp index 2d6972171ea7..11b8d7c92f0e 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp @@ -15,6 +15,8 @@ */ #include "merge_worker.h" +#include + #include "snapuserd_core.h" #include "utility.h" @@ -198,6 +200,7 @@ bool MergeWorker::MergeOrderedOpsAsync() { // Wait for RA thread to notify that the merge window // is ready for merging. if (!snapuserd_->WaitForMergeBegin()) { + SNAP_LOG(ERROR) << "Failed waiting for merge to begin"; return false; } @@ -303,7 +306,7 @@ bool MergeWorker::MergeOrderedOpsAsync() { // will fallback to synchronous I/O. ret = io_uring_wait_cqe(ring_.get(), &cqe); if (ret) { - SNAP_LOG(ERROR) << "Merge: io_uring_wait_cqe failed: " << ret; + SNAP_LOG(ERROR) << "Merge: io_uring_wait_cqe failed: " << strerror(-ret); status = false; break; } @@ -546,6 +549,9 @@ void MergeWorker::FinalizeIouring() { bool MergeWorker::Run() { SNAP_LOG(DEBUG) << "Waiting for merge begin..."; + + pthread_setname_np(pthread_self(), "MergeWorker"); + if (!snapuserd_->WaitForMergeBegin()) { SNAP_LOG(ERROR) << "Merge terminated early..."; return true; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp index e2c292bd85bb..b9ecfa5b3235 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp @@ -16,6 +16,8 @@ #include "read_worker.h" +#include + #include "snapuserd_core.h" #include "utility.h" @@ -209,6 +211,8 @@ bool ReadWorker::Init() { bool ReadWorker::Run() { SNAP_LOG(INFO) << "Processing snapshot I/O requests...."; + pthread_setname_np(pthread_self(), "ReadWorker"); + if (!SetThreadPriority(kNiceValueForMergeThreads)) { SNAP_PLOG(ERROR) << "Failed to set thread priority"; } 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 5a82ca1f4d92..c2958512d1c1 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -295,8 +295,6 @@ bool SnapshotHandler::Start() { if (ra_thread_) { ra_thread_status = std::async(std::launch::async, &ReadAhead::RunThread, read_ahead_thread_.get()); - - SNAP_LOG(INFO) << "Read-ahead thread started"; } // Launch worker threads diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index a45e0bcc76e7..622fc5028dbe 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -68,12 +69,13 @@ static constexpr int kNiceValueForMergeThreads = -5; #define SNAP_PLOG(level) PLOG(level) << misc_name_ << ": " enum class MERGE_IO_TRANSITION { + INVALID, MERGE_READY, MERGE_BEGIN, MERGE_FAILED, MERGE_COMPLETE, IO_TERMINATED, - READ_AHEAD_FAILURE, + READ_AHEAD_FAILURE }; class MergeWorker; @@ -220,7 +222,7 @@ class SnapshotHandler : public std::enable_shared_from_this { bool populate_data_from_cow_ = false; bool ra_thread_ = false; int total_ra_blocks_merged_ = 0; - MERGE_IO_TRANSITION io_state_; + MERGE_IO_TRANSITION io_state_ = MERGE_IO_TRANSITION::INVALID; std::unique_ptr read_ahead_thread_; std::unordered_map read_ahead_buffer_map_; @@ -246,5 +248,7 @@ class SnapshotHandler : public std::enable_shared_from_this { std::shared_ptr block_server_opener_; }; +std::ostream& operator<<(std::ostream& os, MERGE_IO_TRANSITION value); + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp index 8b799ea93a7c..d2128c5d02fa 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp @@ -16,6 +16,8 @@ #include "snapuserd_readahead.h" +#include + #include "snapuserd_core.h" #include "utility.h" @@ -428,7 +430,7 @@ bool ReadAhead::ReapIoCompletions(int pending_ios_to_complete) { // will fallback to synchronous I/O. int ret = io_uring_wait_cqe(ring_.get(), &cqe); if (ret) { - SNAP_LOG(ERROR) << "Read-ahead - io_uring_wait_cqe failed: " << ret; + SNAP_LOG(ERROR) << "Read-ahead - io_uring_wait_cqe failed: " << strerror(-ret); status = false; break; } @@ -691,6 +693,7 @@ bool ReadAhead::ReadAheadIOStart() { // window. If there is a crash during this time frame, merge should resume // based on the contents of the scratch space. if (!snapuserd_->WaitForMergeReady()) { + SNAP_LOG(ERROR) << "ReadAhead failed to wait for merge ready"; return false; } @@ -752,6 +755,10 @@ void ReadAhead::FinalizeIouring() { } bool ReadAhead::RunThread() { + SNAP_LOG(INFO) << "ReadAhead thread started."; + + pthread_setname_np(pthread_self(), "ReadAhead"); + if (!InitializeFds()) { return false; } @@ -770,6 +777,7 @@ bool ReadAhead::RunThread() { SNAP_PLOG(ERROR) << "Failed to set thread priority"; } + SNAP_LOG(INFO) << "ReadAhead processing."; while (!RAIterDone()) { if (!ReadAheadIOStart()) { break; @@ -780,7 +788,7 @@ bool ReadAhead::RunThread() { CloseFds(); reader_->CloseCowFd(); - SNAP_LOG(INFO) << " ReadAhead thread terminating...."; + SNAP_LOG(INFO) << " ReadAhead thread terminating."; return true; } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp index 28c9f688a8cc..52e4f89cd124 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp @@ -199,6 +199,7 @@ bool SnapshotHandler::WaitForMergeBegin() { if (io_state_ == MERGE_IO_TRANSITION::READ_AHEAD_FAILURE || io_state_ == MERGE_IO_TRANSITION::IO_TERMINATED) { + SNAP_LOG(ERROR) << "WaitForMergeBegin failed with state: " << io_state_; return false; } } @@ -211,6 +212,7 @@ bool SnapshotHandler::WaitForMergeBegin() { if (io_state_ == MERGE_IO_TRANSITION::READ_AHEAD_FAILURE || io_state_ == MERGE_IO_TRANSITION::IO_TERMINATED) { + SNAP_LOG(ERROR) << "WaitForMergeBegin failed with state: " << io_state_; return false; } @@ -277,6 +279,7 @@ bool SnapshotHandler::WaitForMergeReady() { if (io_state_ == MERGE_IO_TRANSITION::MERGE_FAILED || io_state_ == MERGE_IO_TRANSITION::MERGE_COMPLETE || io_state_ == MERGE_IO_TRANSITION::IO_TERMINATED) { + SNAP_LOG(ERROR) << "Wait for merge ready failed: " << io_state_; return false; } return true; @@ -668,5 +671,26 @@ MERGE_GROUP_STATE SnapshotHandler::ProcessMergingBlock(uint64_t new_block, void* } } +std::ostream& operator<<(std::ostream& os, MERGE_IO_TRANSITION value) { + switch (value) { + case MERGE_IO_TRANSITION::INVALID: + return os << "INVALID"; + case MERGE_IO_TRANSITION::MERGE_READY: + return os << "MERGE_READY"; + case MERGE_IO_TRANSITION::MERGE_BEGIN: + return os << "MERGE_BEGIN"; + case MERGE_IO_TRANSITION::MERGE_FAILED: + return os << "MERGE_FAILED"; + case MERGE_IO_TRANSITION::MERGE_COMPLETE: + return os << "MERGE_COMPLETE"; + case MERGE_IO_TRANSITION::IO_TERMINATED: + return os << "IO_TERMINATED"; + case MERGE_IO_TRANSITION::READ_AHEAD_FAILURE: + return os << "READ_AHEAD_FAILURE"; + default: + return os << "unknown"; + } +} + } // namespace snapshot } // namespace android From 4e0d58c9e57e0838fa2a902291700eb54848b976 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 7 Aug 2023 14:59:07 -0700 Subject: [PATCH 0288/1487] snapuserd: Don't specify a path to TemporaryFile. Placing temporary files in the executable dir creates unexpected files in the build dir when running on the host, which linger if snapuserd crashes. Bug: 288273605 Test: snapuserd_test Change-Id: Ia1ea4ba70b645a9d2f49419b91003bc62fb03cb2 --- .../libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 9f7a91dae277..0f1374cd1038 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -108,8 +108,7 @@ void SnapuserdTestBase::CreateBaseDevice() { } std::unique_ptr SnapuserdTestBase::CreateCowDeviceInternal() { - std::string path = android::base::GetExecutableDirectory(); - cow_system_ = std::make_unique(path); + cow_system_ = std::make_unique(); CowOptions options; options.compression = "gz"; From 27add511522e09350fb64ac744c970c11285b21f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 3 Aug 2023 20:42:38 -0700 Subject: [PATCH 0289/1487] snapuserd: Add an ITestHarness implementation for hosts. This adds an implementation of ITestHarness suitable for running tests on the host. IUserDevice and ProcessRequests are implemented just enough for shutdown of ReadWorker to work. Most snapuserd tests are focused on merging, and do not need a ReadWorker accepting requests. Bug: 288273605 Test: snapuserd_test Change-Id: I00cf6ec941fb6423290f7a299e5321adea7d8919 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 1 + .../snapuserd/testing/host_harness.cpp | 107 ++++++++++++++++++ .../snapuserd/testing/host_harness.h | 104 +++++++++++++++++ 3 files changed, 212 insertions(+) create mode 100644 fs_mgr/libsnapshot/snapuserd/testing/host_harness.cpp create mode 100644 fs_mgr/libsnapshot/snapuserd/testing/host_harness.h diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index fc260b6921c4..f5b87e04fd3b 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -222,6 +222,7 @@ cc_test { srcs: [ "testing/dm_user_harness.cpp", "testing/harness.cpp", + "testing/host_harness.cpp", "user-space-merge/snapuserd_test.cpp", ], shared_libs: [ diff --git a/fs_mgr/libsnapshot/snapuserd/testing/host_harness.cpp b/fs_mgr/libsnapshot/snapuserd/testing/host_harness.cpp new file mode 100644 index 000000000000..bb90e6d29cc6 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/testing/host_harness.cpp @@ -0,0 +1,107 @@ +// Copyright (C) 2023 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 "host_harness.h" + +#include "snapuserd_logging.h" + +namespace android { +namespace snapshot { + +void TestBlockServerQueue::WaitForShutdown() { + std::unique_lock lock(m_); + if (shutdown_) { + return; + } + cv_.wait(lock, [this]() -> bool { return shutdown_; }); +} + +void TestBlockServerQueue::Shutdown() { + std::unique_lock lock(m_); + shutdown_ = true; + cv_.notify_all(); +} + +TestBlockServer::TestBlockServer(std::shared_ptr queue, + const std::string& misc_name) + : queue_(queue), misc_name_(misc_name) {} + +bool TestBlockServer::ProcessRequests() { + queue_->WaitForShutdown(); + return false; +} + +void* TestBlockServer::GetResponseBuffer(size_t size, size_t to_write) { + std::string buffer(size, '\0'); + buffered_.emplace_back(std::move(buffer), to_write); + return buffered_.back().first.data(); +} + +bool TestBlockServer::SendBufferedIo() { + for (const auto& [data, to_write] : buffered_) { + sent_io_ += data.substr(0, to_write); + } + buffered_.clear(); + return true; +} + +TestBlockServerOpener::TestBlockServerOpener(std::shared_ptr queue, + const std::string& misc_name) + : queue_(queue), misc_name_(misc_name) {} + +std::unique_ptr TestBlockServerOpener::Open(IBlockServer::Delegate*, size_t) { + return std::make_unique(queue_, misc_name_); +} + +std::shared_ptr TestBlockServerFactory::CreateOpener( + const std::string& misc_name) { + if (queues_.count(misc_name)) { + LOG(ERROR) << "Cannot create opener for " << misc_name << ", already exists"; + return nullptr; + } + auto queue = std::make_shared(); + queues_.emplace(misc_name, queue); + return std::make_shared(queue, misc_name); +} + +bool TestBlockServerFactory::DeleteQueue(const std::string& misc_name) { + auto iter = queues_.find(misc_name); + if (iter == queues_.end()) { + LOG(ERROR) << "Cannot delete queue " << misc_name << ", not found"; + return false; + } + iter->second->Shutdown(); + queues_.erase(iter); + return true; +} + +HostUserDevice::HostUserDevice(TestBlockServerFactory* factory, const std::string& misc_name) + : factory_(factory), misc_name_(misc_name) {} + +bool HostUserDevice::Destroy() { + return factory_->DeleteQueue(misc_name_); +} + +std::unique_ptr HostTestHarness::CreateUserDevice(const std::string&, + const std::string& misc_name, + uint64_t) { + return std::make_unique(&factory_, misc_name); +} + +IBlockServerFactory* HostTestHarness::GetBlockServerFactory() { + return &factory_; +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/testing/host_harness.h b/fs_mgr/libsnapshot/snapuserd/testing/host_harness.h new file mode 100644 index 000000000000..e5c698514e7a --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/testing/host_harness.h @@ -0,0 +1,104 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "harness.h" + +namespace android { +namespace snapshot { + +class TestBlockServerQueue final { + public: + void WaitForShutdown(); + void Shutdown(); + + private: + std::mutex m_; + std::condition_variable cv_; + bool shutdown_ = false; +}; + +class TestBlockServer final : public IBlockServer { + public: + TestBlockServer(std::shared_ptr queue, const std::string& misc_name); + bool ProcessRequests() override; + void* GetResponseBuffer(size_t size, size_t to_write) override; + bool SendBufferedIo() override; + + std::string&& sent_io() { return std::move(sent_io_); } + + private: + std::shared_ptr queue_; + std::string misc_name_; + std::string sent_io_; + std::vector> buffered_; +}; + +class TestBlockServerOpener final : public IBlockServerOpener { + public: + TestBlockServerOpener(std::shared_ptr queue, + const std::string& misc_name); + std::unique_ptr Open(IBlockServer::Delegate* delegate, + size_t buffer_size) override; + + private: + std::shared_ptr queue_; + std::string misc_name_; +}; + +class TestBlockServerFactory final : public IBlockServerFactory { + public: + std::shared_ptr CreateOpener(const std::string& misc_name) override; + bool DeleteQueue(const std::string& misc_name); + + private: + std::unordered_map> queues_; +}; + +class TestBlockServerFactory; + +class HostUserDevice final : public IUserDevice { + public: + HostUserDevice(TestBlockServerFactory* factory, const std::string& misc_name); + const std::string& GetPath() override { return empty_path_; } + bool Destroy(); + + private: + TestBlockServerFactory* factory_; + std::string misc_name_; + std::string empty_path_; +}; + +class HostTestHarness final : public ITestHarness { + public: + std::unique_ptr CreateUserDevice(const std::string& dev_name, + const std::string& misc_name, + uint64_t num_sectors) override; + IBlockServerFactory* GetBlockServerFactory() override; + bool HasUserDevice() override { return false; } + + private: + TestBlockServerFactory factory_; +}; + +} // namespace snapshot +} // namespace android From 0ec9b0eb9226828a2fa7a67b3e9d7400015acbef Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 7 Aug 2023 15:25:07 -0700 Subject: [PATCH 0290/1487] snapuesrd: Build snapuserd_test on host. Bug: 288273605 Test: snapuserd_test Change-Id: I10e099feff30f09b8c9f0b9dcca64336cb0861b9 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 2 ++ .../snapuserd/include/snapuserd/snapuserd_kernel.h | 6 ++++-- .../snapuserd/user-space-merge/snapuserd_test.cpp | 9 ++++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index f5b87e04fd3b..fe7f99c675d7 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -90,6 +90,7 @@ cc_library_static { ramdisk_available: true, vendor_ramdisk_available: true, recovery_available: true, + host_supported: true, } cc_defaults { @@ -256,4 +257,5 @@ cc_test { }, auto_gen_config: true, require_root: false, + host_supported: true, } diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h index 0d83f4789625..7ab75dc7966c 100644 --- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h +++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h @@ -14,6 +14,8 @@ #pragma once +#include + namespace android { namespace snapshot { @@ -70,7 +72,7 @@ struct disk_header { /* In sectors */ uint32_t chunk_size; -} __packed; +} __attribute__((packed)); // A disk exception is a mapping of old_chunk to new_chunk // old_chunk is the chunk ID of a dm-snapshot device. @@ -78,7 +80,7 @@ struct disk_header { struct disk_exception { uint64_t old_chunk; uint64_t new_chunk; -} __packed; +} __attribute__((packed)); // Control structures to communicate with dm-user // It comprises of header and a payload 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 0f1374cd1038..9c923847daed 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -41,6 +41,7 @@ #include "handler_manager.h" #include "snapuserd_core.h" #include "testing/dm_user_harness.h" +#include "testing/host_harness.h" #include "testing/temp_device.h" #include "utility.h" @@ -80,7 +81,11 @@ class SnapuserdTestBase : public ::testing::Test { }; void SnapuserdTestBase::SetUp() { +#if __ANDROID__ harness_ = std::make_unique(); +#else + harness_ = std::make_unique(); +#endif } void SnapuserdTestBase::TearDown() {} @@ -269,7 +274,9 @@ void SnapuserdTest::TearDown() { } void SnapuserdTest::Shutdown() { - ASSERT_TRUE(dmuser_dev_->Destroy()); + if (dmuser_dev_) { + ASSERT_TRUE(dmuser_dev_->Destroy()); + } auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_; ASSERT_TRUE(handlers_->DeleteHandler(system_device_ctrl_name_)); From 9fb4fc307c5e950a8eeb8c03d9b884eff137b8f0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 7 Aug 2023 14:18:46 -0700 Subject: [PATCH 0291/1487] snapuserd: Add error propagation to tests. snapuserd_test in general doesn't propagate errors, which means the first failure will cascade into many failures. This can make it harder to figure out what's going on. Unfortunately error propagation is difficult with gtest, since bool returns don't work with ASSERT_EQ and Android doesn't use exceptions. Use ASSERT_NO_FATAL_FAILURE for now, since that is the least invasive change. Bug: 288273605 Test: snapuserd_test Change-Id: I6550682fd63602bc15649f705def2915f6329357 --- .../user-space-merge/snapuserd_test.cpp | 187 ++++++++---------- 1 file changed, 84 insertions(+), 103 deletions(-) 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 0e02f0b853cf..ae921fd35bfe 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -58,11 +58,11 @@ using namespace std; class SnapuserdTest : public ::testing::Test { public: - bool SetupDefault(); - bool SetupOrderedOps(); - bool SetupOrderedOpsInverted(); - bool SetupCopyOverlap_1(); - bool SetupCopyOverlap_2(); + void SetupDefault(); + void SetupOrderedOps(); + void SetupOrderedOpsInverted(); + void SetupCopyOverlap_1(); + void SetupCopyOverlap_2(); bool Merge(); void ValidateMerge(); void ReadSnapshotDeviceAndValidate(); @@ -70,7 +70,7 @@ class SnapuserdTest : public ::testing::Test { void MergeInterrupt(); void MergeInterruptFixed(int duration); void MergeInterruptRandomly(int max_duration); - void StartMerge(); + bool StartMerge(); void CheckMergeCompletion(); static const uint64_t kSectorSize = 512; @@ -89,7 +89,7 @@ class SnapuserdTest : public ::testing::Test { void CreateCowDeviceOrderedOpsInverted(); void CreateCowDeviceWithCopyOverlap_1(); void CreateCowDeviceWithCopyOverlap_2(); - bool SetupDaemon(); + void SetupDaemon(); void CreateBaseDevice(); void InitCowDevice(); void SetDeviceControlName(); @@ -107,8 +107,6 @@ class SnapuserdTest : public ::testing::Test { std::unique_ptr orig_buffer_; std::unique_ptr merged_buffer_; std::unique_ptr handlers_; - bool setup_ok_ = false; - bool merge_ok_ = false; size_t size_ = 100_MiB; int cow_num_sectors_; int total_base_size_; @@ -131,45 +129,40 @@ void SnapuserdTest::Shutdown() { handlers_ = std::make_unique(); } -bool SnapuserdTest::SetupDefault() { - SetupImpl(); - return setup_ok_; +void SnapuserdTest::SetupDefault() { + ASSERT_NO_FATAL_FAILURE(SetupImpl()); } -bool SnapuserdTest::SetupOrderedOps() { - CreateBaseDevice(); - CreateCowDeviceOrderedOps(); - return SetupDaemon(); +void SnapuserdTest::SetupOrderedOps() { + ASSERT_NO_FATAL_FAILURE(CreateBaseDevice()); + ASSERT_NO_FATAL_FAILURE(CreateCowDeviceOrderedOps()); + ASSERT_NO_FATAL_FAILURE(SetupDaemon()); } -bool SnapuserdTest::SetupOrderedOpsInverted() { - CreateBaseDevice(); - CreateCowDeviceOrderedOpsInverted(); - return SetupDaemon(); +void SnapuserdTest::SetupOrderedOpsInverted() { + ASSERT_NO_FATAL_FAILURE(CreateBaseDevice()); + ASSERT_NO_FATAL_FAILURE(CreateCowDeviceOrderedOpsInverted()); + ASSERT_NO_FATAL_FAILURE(SetupDaemon()); } -bool SnapuserdTest::SetupCopyOverlap_1() { - CreateBaseDevice(); - CreateCowDeviceWithCopyOverlap_1(); - return SetupDaemon(); +void SnapuserdTest::SetupCopyOverlap_1() { + ASSERT_NO_FATAL_FAILURE(CreateBaseDevice()); + ASSERT_NO_FATAL_FAILURE(CreateCowDeviceWithCopyOverlap_1()); + ASSERT_NO_FATAL_FAILURE(SetupDaemon()); } -bool SnapuserdTest::SetupCopyOverlap_2() { - CreateBaseDevice(); - CreateCowDeviceWithCopyOverlap_2(); - return SetupDaemon(); +void SnapuserdTest::SetupCopyOverlap_2() { + ASSERT_NO_FATAL_FAILURE(CreateBaseDevice()); + ASSERT_NO_FATAL_FAILURE(CreateCowDeviceWithCopyOverlap_2()); + ASSERT_NO_FATAL_FAILURE(SetupDaemon()); } -bool SnapuserdTest::SetupDaemon() { +void SnapuserdTest::SetupDaemon() { SetDeviceControlName(); - CreateUserDevice(); - InitCowDevice(); - InitDaemon(); - - setup_ok_ = true; - - return setup_ok_; + ASSERT_NO_FATAL_FAILURE(CreateUserDevice()); + ASSERT_NO_FATAL_FAILURE(InitCowDevice()); + ASSERT_NO_FATAL_FAILURE(InitDaemon()); } void SnapuserdTest::CreateBaseDevice() { @@ -575,27 +568,26 @@ void SnapuserdTest::CheckMergeCompletion() { } void SnapuserdTest::SetupImpl() { - CreateBaseDevice(); - CreateCowDevice(); + ASSERT_NO_FATAL_FAILURE(CreateBaseDevice()); + ASSERT_NO_FATAL_FAILURE(CreateCowDevice()); SetDeviceControlName(); - CreateUserDevice(); - InitCowDevice(); - InitDaemon(); - - setup_ok_ = true; + ASSERT_NO_FATAL_FAILURE(CreateUserDevice()); + ASSERT_NO_FATAL_FAILURE(InitCowDevice()); + ASSERT_NO_FATAL_FAILURE(InitDaemon()); } bool SnapuserdTest::Merge() { - StartMerge(); + if (!StartMerge()) { + return false; + } CheckMergeCompletion(); - merge_ok_ = true; - return merge_ok_; + return true; } -void SnapuserdTest::StartMerge() { - ASSERT_TRUE(handlers_->InitiateMerge(system_device_ctrl_name_)); +bool SnapuserdTest::StartMerge() { + return handlers_->InitiateMerge(system_device_ctrl_name_); } void SnapuserdTest::ValidateMerge() { @@ -606,67 +598,67 @@ void SnapuserdTest::ValidateMerge() { } void SnapuserdTest::SimulateDaemonRestart() { - Shutdown(); + ASSERT_NO_FATAL_FAILURE(Shutdown()); std::this_thread::sleep_for(500ms); SetDeviceControlName(); - CreateUserDevice(); - InitCowDevice(); - InitDaemon(); + ASSERT_NO_FATAL_FAILURE(CreateUserDevice()); + ASSERT_NO_FATAL_FAILURE(InitCowDevice()); + ASSERT_NO_FATAL_FAILURE(InitDaemon()); } void SnapuserdTest::MergeInterruptRandomly(int max_duration) { std::srand(std::time(nullptr)); - StartMerge(); + ASSERT_TRUE(StartMerge()); for (int i = 0; i < 20; i++) { int duration = std::rand() % max_duration; std::this_thread::sleep_for(std::chrono::milliseconds(duration)); - SimulateDaemonRestart(); - StartMerge(); + ASSERT_NO_FATAL_FAILURE(SimulateDaemonRestart()); + ASSERT_TRUE(StartMerge()); } - SimulateDaemonRestart(); + ASSERT_NO_FATAL_FAILURE(SimulateDaemonRestart()); ASSERT_TRUE(Merge()); } void SnapuserdTest::MergeInterruptFixed(int duration) { - StartMerge(); + ASSERT_TRUE(StartMerge()); for (int i = 0; i < 25; i++) { std::this_thread::sleep_for(std::chrono::milliseconds(duration)); - SimulateDaemonRestart(); - StartMerge(); + ASSERT_NO_FATAL_FAILURE(SimulateDaemonRestart()); + ASSERT_TRUE(StartMerge()); } - SimulateDaemonRestart(); + ASSERT_NO_FATAL_FAILURE(SimulateDaemonRestart()); ASSERT_TRUE(Merge()); } void SnapuserdTest::MergeInterrupt() { // Interrupt merge at various intervals - StartMerge(); + ASSERT_TRUE(StartMerge()); std::this_thread::sleep_for(250ms); - SimulateDaemonRestart(); + ASSERT_NO_FATAL_FAILURE(SimulateDaemonRestart()); - StartMerge(); + ASSERT_TRUE(StartMerge()); std::this_thread::sleep_for(250ms); - SimulateDaemonRestart(); + ASSERT_NO_FATAL_FAILURE(SimulateDaemonRestart()); - StartMerge(); + ASSERT_TRUE(StartMerge()); std::this_thread::sleep_for(150ms); - SimulateDaemonRestart(); + ASSERT_NO_FATAL_FAILURE(SimulateDaemonRestart()); - StartMerge(); + ASSERT_TRUE(StartMerge()); std::this_thread::sleep_for(100ms); - SimulateDaemonRestart(); + ASSERT_NO_FATAL_FAILURE(SimulateDaemonRestart()); - StartMerge(); + ASSERT_TRUE(StartMerge()); std::this_thread::sleep_for(800ms); - SimulateDaemonRestart(); + ASSERT_NO_FATAL_FAILURE(SimulateDaemonRestart()); - StartMerge(); + ASSERT_TRUE(StartMerge()); std::this_thread::sleep_for(600ms); - SimulateDaemonRestart(); + ASSERT_NO_FATAL_FAILURE(SimulateDaemonRestart()); ASSERT_TRUE(Merge()); } @@ -675,98 +667,87 @@ TEST_F(SnapuserdTest, Snapshot_IO_TEST) { if (!harness_->HasUserDevice()) { GTEST_SKIP() << "Skipping snapshot read; not supported"; } - ASSERT_TRUE(SetupDefault()); + ASSERT_NO_FATAL_FAILURE(SetupDefault()); // I/O before merge - ReadSnapshotDeviceAndValidate(); + ASSERT_NO_FATAL_FAILURE(ReadSnapshotDeviceAndValidate()); ASSERT_TRUE(Merge()); ValidateMerge(); // I/O after merge - daemon should read directly // from base device - ReadSnapshotDeviceAndValidate(); - Shutdown(); + ASSERT_NO_FATAL_FAILURE(ReadSnapshotDeviceAndValidate()); } TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST) { if (!harness_->HasUserDevice()) { GTEST_SKIP() << "Skipping snapshot read; not supported"; } - ASSERT_TRUE(SetupDefault()); + ASSERT_NO_FATAL_FAILURE(SetupDefault()); // Issue I/O before merge begins std::async(std::launch::async, &SnapuserdTest::ReadSnapshotDeviceAndValidate, this); // Start the merge ASSERT_TRUE(Merge()); ValidateMerge(); - Shutdown(); } TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST_1) { if (!harness_->HasUserDevice()) { GTEST_SKIP() << "Skipping snapshot read; not supported"; } - ASSERT_TRUE(SetupDefault()); + ASSERT_NO_FATAL_FAILURE(SetupDefault()); // Start the merge - StartMerge(); + ASSERT_TRUE(StartMerge()); // Issue I/O in parallel when merge is in-progress std::async(std::launch::async, &SnapuserdTest::ReadSnapshotDeviceAndValidate, this); CheckMergeCompletion(); ValidateMerge(); - Shutdown(); } TEST_F(SnapuserdTest, Snapshot_Merge_Resume) { - ASSERT_TRUE(SetupDefault()); - MergeInterrupt(); + ASSERT_NO_FATAL_FAILURE(SetupDefault()); + ASSERT_NO_FATAL_FAILURE(MergeInterrupt()); ValidateMerge(); - Shutdown(); } TEST_F(SnapuserdTest, Snapshot_COPY_Overlap_TEST_1) { - ASSERT_TRUE(SetupCopyOverlap_1()); + ASSERT_NO_FATAL_FAILURE(SetupCopyOverlap_1()); ASSERT_TRUE(Merge()); ValidateMerge(); - Shutdown(); } TEST_F(SnapuserdTest, Snapshot_COPY_Overlap_TEST_2) { - ASSERT_TRUE(SetupCopyOverlap_2()); + ASSERT_NO_FATAL_FAILURE(SetupCopyOverlap_2()); ASSERT_TRUE(Merge()); ValidateMerge(); - Shutdown(); } TEST_F(SnapuserdTest, Snapshot_COPY_Overlap_Merge_Resume_TEST) { - ASSERT_TRUE(SetupCopyOverlap_1()); - MergeInterrupt(); + ASSERT_NO_FATAL_FAILURE(SetupCopyOverlap_1()); + ASSERT_NO_FATAL_FAILURE(MergeInterrupt()); ValidateMerge(); - Shutdown(); } TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Fixed_Ordered) { - ASSERT_TRUE(SetupOrderedOps()); - MergeInterruptFixed(300); + ASSERT_NO_FATAL_FAILURE(SetupOrderedOps()); + ASSERT_NO_FATAL_FAILURE(MergeInterruptFixed(300)); ValidateMerge(); - Shutdown(); } TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Random_Ordered) { - ASSERT_TRUE(SetupOrderedOps()); - MergeInterruptRandomly(500); + ASSERT_NO_FATAL_FAILURE(SetupOrderedOps()); + ASSERT_NO_FATAL_FAILURE(MergeInterruptRandomly(500)); ValidateMerge(); - Shutdown(); } TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Fixed_Inverted) { - ASSERT_TRUE(SetupOrderedOpsInverted()); - MergeInterruptFixed(50); + ASSERT_NO_FATAL_FAILURE(SetupOrderedOpsInverted()); + ASSERT_NO_FATAL_FAILURE(MergeInterruptFixed(50)); ValidateMerge(); - Shutdown(); } TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Random_Inverted) { - ASSERT_TRUE(SetupOrderedOpsInverted()); - MergeInterruptRandomly(50); + ASSERT_NO_FATAL_FAILURE(SetupOrderedOpsInverted()); + ASSERT_NO_FATAL_FAILURE(MergeInterruptRandomly(50)); ValidateMerge(); - Shutdown(); } } // namespace snapshot From 6aec095d6872b93d8c18076a7b0b45c494b95a1c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 7 Aug 2023 19:46:20 -0700 Subject: [PATCH 0292/1487] snapuserd: Add unit tests for ReadWorker::ReadAlignedSector. These tests are for real bugs that were previously not testable. Bug: 288273605 Test: snapuserd_test Change-Id: I9e9af999e4f5f988f4538750eba109f6b2fe448c --- .../snapuserd/testing/host_harness.cpp | 7 +- .../snapuserd/testing/host_harness.h | 1 + .../snapuserd/user-space-merge/read_worker.h | 4 +- .../user-space-merge/snapuserd_test.cpp | 109 ++++++++++++++++++ 4 files changed, 119 insertions(+), 2 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/testing/host_harness.cpp b/fs_mgr/libsnapshot/snapuserd/testing/host_harness.cpp index bb90e6d29cc6..0d230ad84726 100644 --- a/fs_mgr/libsnapshot/snapuserd/testing/host_harness.cpp +++ b/fs_mgr/libsnapshot/snapuserd/testing/host_harness.cpp @@ -64,7 +64,7 @@ std::unique_ptr TestBlockServerOpener::Open(IBlockServer::Delegate return std::make_unique(queue_, misc_name_); } -std::shared_ptr TestBlockServerFactory::CreateOpener( +std::shared_ptr TestBlockServerFactory::CreateTestOpener( const std::string& misc_name) { if (queues_.count(misc_name)) { LOG(ERROR) << "Cannot create opener for " << misc_name << ", already exists"; @@ -75,6 +75,11 @@ std::shared_ptr TestBlockServerFactory::CreateOpener( return std::make_shared(queue, misc_name); } +std::shared_ptr TestBlockServerFactory::CreateOpener( + const std::string& misc_name) { + return CreateTestOpener(misc_name); +} + bool TestBlockServerFactory::DeleteQueue(const std::string& misc_name) { auto iter = queues_.find(misc_name); if (iter == queues_.end()) { diff --git a/fs_mgr/libsnapshot/snapuserd/testing/host_harness.h b/fs_mgr/libsnapshot/snapuserd/testing/host_harness.h index e5c698514e7a..ec0bd29ad474 100644 --- a/fs_mgr/libsnapshot/snapuserd/testing/host_harness.h +++ b/fs_mgr/libsnapshot/snapuserd/testing/host_harness.h @@ -68,6 +68,7 @@ class TestBlockServerOpener final : public IBlockServerOpener { class TestBlockServerFactory final : public IBlockServerFactory { public: std::shared_ptr CreateOpener(const std::string& misc_name) override; + std::shared_ptr CreateTestOpener(const std::string& misc_name); bool DeleteQueue(const std::string& misc_name); private: diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h index a6a3eb8ca54d..6dbae812f812 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h @@ -33,9 +33,11 @@ class ReadWorker : public Worker, public IBlockServer::Delegate { bool Run(); bool Init() override; void CloseFds() override; + bool RequestSectors(uint64_t sector, uint64_t size) override; + + IBlockServer* block_server() const { return block_server_.get(); } private: - bool RequestSectors(uint64_t sector, uint64_t size) override; bool SendBufferedIo(); bool ProcessCowOp(const CowOperation* cow_op, void* buffer); 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 9c923847daed..c5ccb0d22f16 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -39,6 +39,8 @@ #include #include #include "handler_manager.h" +#include "merge_worker.h" +#include "read_worker.h" #include "snapuserd_core.h" #include "testing/dm_user_harness.h" #include "testing/host_harness.h" @@ -56,6 +58,9 @@ using LoopDevice = android::dm::LoopDevice; using namespace std::chrono_literals; using namespace android::dm; using namespace std; +using testing::AssertionFailure; +using testing::AssertionResult; +using testing::AssertionSuccess; class SnapuserdTestBase : public ::testing::Test { protected: @@ -776,6 +781,110 @@ TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Random_Inverted) { ValidateMerge(); } +class HandlerTest : public SnapuserdTestBase { + protected: + void SetUp() override; + void TearDown() override; + + AssertionResult ReadSectors(sector_t sector, uint64_t size, void* buffer); + + TestBlockServerFactory factory_; + std::shared_ptr opener_; + std::shared_ptr handler_; + std::unique_ptr read_worker_; + TestBlockServer* block_server_; + std::future handler_thread_; +}; + +void HandlerTest::SetUp() { + ASSERT_NO_FATAL_FAILURE(SnapuserdTestBase::SetUp()); + ASSERT_NO_FATAL_FAILURE(CreateBaseDevice()); + ASSERT_NO_FATAL_FAILURE(CreateCowDevice()); + ASSERT_NO_FATAL_FAILURE(SetDeviceControlName()); + + opener_ = factory_.CreateTestOpener(system_device_ctrl_name_); + ASSERT_NE(opener_, nullptr); + + handler_ = std::make_shared(system_device_ctrl_name_, cow_system_->path, + base_dev_->GetPath(), base_dev_->GetPath(), + opener_, 1, false, false); + ASSERT_TRUE(handler_->InitCowDevice()); + ASSERT_TRUE(handler_->InitializeWorkers()); + + read_worker_ = std::make_unique(cow_system_->path, base_dev_->GetPath(), + system_device_ctrl_name_, base_dev_->GetPath(), + handler_->GetSharedPtr(), opener_); + ASSERT_TRUE(read_worker_->Init()); + block_server_ = static_cast(read_worker_->block_server()); + + handler_thread_ = std::async(std::launch::async, &SnapshotHandler::Start, handler_.get()); +} + +void HandlerTest::TearDown() { + ASSERT_TRUE(factory_.DeleteQueue(system_device_ctrl_name_)); + ASSERT_TRUE(handler_thread_.get()); + SnapuserdTestBase::TearDown(); +} + +AssertionResult HandlerTest::ReadSectors(sector_t sector, uint64_t size, void* buffer) { + if (!read_worker_->RequestSectors(sector, size)) { + return AssertionFailure() << "request sectors failed"; + } + + std::string result = std::move(block_server_->sent_io()); + if (result.size() != size) { + return AssertionFailure() << "size mismatch in result, got " << result.size() + << ", expected " << size; + } + + memcpy(buffer, result.data(), size); + return AssertionSuccess(); +} + +// This test mirrors ReadSnapshotDeviceAndValidate. +TEST_F(HandlerTest, Read) { + std::unique_ptr snapuserd_buffer = std::make_unique(size_); + + // COPY + loff_t offset = 0; + ASSERT_TRUE(ReadSectors(offset / SECTOR_SIZE, size_, snapuserd_buffer.get())); + ASSERT_EQ(memcmp(snapuserd_buffer.get(), orig_buffer_.get(), size_), 0); + + // REPLACE + offset += size_; + ASSERT_TRUE(ReadSectors(offset / SECTOR_SIZE, size_, snapuserd_buffer.get())); + ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + size_, size_), 0); + + // ZERO + offset += size_; + ASSERT_TRUE(ReadSectors(offset / SECTOR_SIZE, size_, snapuserd_buffer.get())); + ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 2), size_), 0); + + // REPLACE + offset += size_; + ASSERT_TRUE(ReadSectors(offset / SECTOR_SIZE, size_, snapuserd_buffer.get())); + ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 3), size_), 0); + + // XOR + offset += size_; + ASSERT_TRUE(ReadSectors(offset / SECTOR_SIZE, size_, snapuserd_buffer.get())); + ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 4), size_), 0); +} + +TEST_F(HandlerTest, ReadUnalignedSector) { + std::unique_ptr snapuserd_buffer = std::make_unique(BLOCK_SZ); + + ASSERT_TRUE(ReadSectors(1, BLOCK_SZ, snapuserd_buffer.get())); + ASSERT_EQ(memcmp(snapuserd_buffer.get(), orig_buffer_.get() + SECTOR_SIZE, BLOCK_SZ), 0); +} + +TEST_F(HandlerTest, ReadUnalignedSize) { + std::unique_ptr snapuserd_buffer = std::make_unique(SECTOR_SIZE); + + ASSERT_TRUE(ReadSectors(0, SECTOR_SIZE, snapuserd_buffer.get())); + ASSERT_EQ(memcmp(snapuserd_buffer.get(), orig_buffer_.get(), SECTOR_SIZE), 0); +} + } // namespace snapshot } // namespace android From dbda1300aee31850ea89c4f76573dda225fed220 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 7 Aug 2023 14:54:38 -0700 Subject: [PATCH 0293/1487] snapuserd: Factor a base class out of tests. This factors a lighter weight class out of SnapuserdTest, so we can construct tests without needing a HandlerManager/daemon. Bug: 288273605 Test: snapuserd_test Change-Id: Ib33dc593a5b3d3df86853e73f245918ef36fd9fa --- .../user-space-merge/snapuserd_test.cpp | 316 ++++++++++-------- 1 file changed, 168 insertions(+), 148 deletions(-) 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 ae921fd35bfe..9f7a91dae277 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -56,7 +56,167 @@ using namespace std::chrono_literals; using namespace android::dm; using namespace std; -class SnapuserdTest : public ::testing::Test { +class SnapuserdTestBase : public ::testing::Test { + protected: + void SetUp() override; + void TearDown() override; + void CreateBaseDevice(); + void CreateCowDevice(); + void SetDeviceControlName(); + std::unique_ptr CreateCowDeviceInternal(); + + std::unique_ptr harness_; + size_t size_ = 100_MiB; + int total_base_size_ = 0; + std::string system_device_ctrl_name_; + std::string system_device_name_; + + unique_ptr base_dev_; + unique_fd base_fd_; + + std::unique_ptr cow_system_; + + std::unique_ptr orig_buffer_; +}; + +void SnapuserdTestBase::SetUp() { + harness_ = std::make_unique(); +} + +void SnapuserdTestBase::TearDown() {} + +void SnapuserdTestBase::CreateBaseDevice() { + total_base_size_ = (size_ * 5); + + base_dev_ = harness_->CreateBackingDevice(total_base_size_); + ASSERT_NE(base_dev_, nullptr); + + base_fd_.reset(open(base_dev_->GetPath().c_str(), O_RDWR | O_CLOEXEC)); + ASSERT_GE(base_fd_, 0); + + unique_fd rnd_fd(open("/dev/random", O_RDONLY)); + ASSERT_GE(rnd_fd, 0); + + std::unique_ptr random_buffer = std::make_unique(1_MiB); + + for (size_t j = 0; j < ((total_base_size_) / 1_MiB); j++) { + ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), 1_MiB, 0), true); + ASSERT_EQ(android::base::WriteFully(base_fd_, random_buffer.get(), 1_MiB), true); + } + + ASSERT_EQ(lseek(base_fd_, 0, SEEK_SET), 0); +} + +std::unique_ptr SnapuserdTestBase::CreateCowDeviceInternal() { + std::string path = android::base::GetExecutableDirectory(); + cow_system_ = std::make_unique(path); + + CowOptions options; + options.compression = "gz"; + + unique_fd fd(cow_system_->fd); + cow_system_->fd = -1; + + return CreateCowWriter(kDefaultCowVersion, options, std::move(fd)); +} + +void SnapuserdTestBase::CreateCowDevice() { + unique_fd rnd_fd; + loff_t offset = 0; + + auto writer = CreateCowDeviceInternal(); + ASSERT_NE(writer, nullptr); + + rnd_fd.reset(open("/dev/random", O_RDONLY)); + ASSERT_TRUE(rnd_fd > 0); + + std::unique_ptr random_buffer_1_ = std::make_unique(size_); + + // Fill random data + for (size_t j = 0; j < (size_ / 1_MiB); j++) { + ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0), + true); + + offset += 1_MiB; + } + + size_t num_blocks = size_ / writer->GetBlockSize(); + size_t blk_end_copy = num_blocks * 2; + size_t source_blk = num_blocks - 1; + size_t blk_src_copy = blk_end_copy - 1; + + uint32_t sequence[num_blocks * 2]; + // Sequence for Copy ops + for (int i = 0; i < num_blocks; i++) { + sequence[i] = num_blocks - 1 - i; + } + // Sequence for Xor ops + for (int i = 0; i < num_blocks; i++) { + sequence[num_blocks + i] = 5 * num_blocks - 1 - i; + } + ASSERT_TRUE(writer->AddSequenceData(2 * num_blocks, sequence)); + + size_t x = num_blocks; + while (1) { + ASSERT_TRUE(writer->AddCopy(source_blk, blk_src_copy)); + x -= 1; + if (x == 0) { + break; + } + source_blk -= 1; + blk_src_copy -= 1; + } + + source_blk = num_blocks; + blk_src_copy = blk_end_copy; + + ASSERT_TRUE(writer->AddRawBlocks(source_blk, random_buffer_1_.get(), size_)); + + size_t blk_zero_copy_start = source_blk + num_blocks; + size_t blk_zero_copy_end = blk_zero_copy_start + num_blocks; + + ASSERT_TRUE(writer->AddZeroBlocks(blk_zero_copy_start, num_blocks)); + + size_t blk_random2_replace_start = blk_zero_copy_end; + + ASSERT_TRUE(writer->AddRawBlocks(blk_random2_replace_start, random_buffer_1_.get(), size_)); + + size_t blk_xor_start = blk_random2_replace_start + num_blocks; + size_t xor_offset = BLOCK_SZ / 2; + ASSERT_TRUE(writer->AddXorBlocks(blk_xor_start, random_buffer_1_.get(), size_, num_blocks, + xor_offset)); + + // Flush operations + ASSERT_TRUE(writer->Finalize()); + // Construct the buffer required for validation + orig_buffer_ = std::make_unique(total_base_size_); + std::string zero_buffer(size_, 0); + ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), size_, size_), true); + memcpy((char*)orig_buffer_.get() + size_, random_buffer_1_.get(), size_); + memcpy((char*)orig_buffer_.get() + (size_ * 2), (void*)zero_buffer.c_str(), size_); + memcpy((char*)orig_buffer_.get() + (size_ * 3), random_buffer_1_.get(), size_); + ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, &orig_buffer_.get()[size_ * 4], size_, + size_ + xor_offset), + true); + for (int i = 0; i < size_; i++) { + orig_buffer_.get()[(size_ * 4) + i] = + (uint8_t)(orig_buffer_.get()[(size_ * 4) + i] ^ random_buffer_1_.get()[i]); + } +} + +void SnapuserdTestBase::SetDeviceControlName() { + system_device_name_.clear(); + system_device_ctrl_name_.clear(); + + std::string str(cow_system_->path); + std::size_t found = str.find_last_of("/\\"); + ASSERT_NE(found, std::string::npos); + system_device_name_ = str.substr(found + 1); + + system_device_ctrl_name_ = system_device_name_ + "-ctrl"; +} + +class SnapuserdTest : public SnapuserdTestBase { public: void SetupDefault(); void SetupOrderedOps(); @@ -77,47 +237,38 @@ class SnapuserdTest : public ::testing::Test { protected: void SetUp() override; - void TearDown() override { Shutdown(); } + void TearDown() override; void SetupImpl(); void SimulateDaemonRestart(); - std::unique_ptr CreateCowDeviceInternal(); - void CreateCowDevice(); void CreateCowDeviceOrderedOps(); void CreateCowDeviceOrderedOpsInverted(); void CreateCowDeviceWithCopyOverlap_1(); void CreateCowDeviceWithCopyOverlap_2(); void SetupDaemon(); - void CreateBaseDevice(); void InitCowDevice(); - void SetDeviceControlName(); void InitDaemon(); void CreateUserDevice(); - unique_ptr base_dev_; unique_ptr dmuser_dev_; - std::string system_device_ctrl_name_; - std::string system_device_name_; - - unique_fd base_fd_; - std::unique_ptr cow_system_; - std::unique_ptr orig_buffer_; std::unique_ptr merged_buffer_; std::unique_ptr handlers_; - size_t size_ = 100_MiB; int cow_num_sectors_; - int total_base_size_; - std::unique_ptr harness_; }; void SnapuserdTest::SetUp() { - harness_ = std::make_unique(); + ASSERT_NO_FATAL_FAILURE(SnapuserdTestBase::SetUp()); handlers_ = std::make_unique(); } +void SnapuserdTest::TearDown() { + SnapuserdTestBase::TearDown(); + Shutdown(); +} + void SnapuserdTest::Shutdown() { ASSERT_TRUE(dmuser_dev_->Destroy()); @@ -165,28 +316,6 @@ void SnapuserdTest::SetupDaemon() { ASSERT_NO_FATAL_FAILURE(InitDaemon()); } -void SnapuserdTest::CreateBaseDevice() { - total_base_size_ = (size_ * 5); - - base_dev_ = harness_->CreateBackingDevice(total_base_size_); - ASSERT_NE(base_dev_, nullptr); - - base_fd_.reset(open(base_dev_->GetPath().c_str(), O_RDWR | O_CLOEXEC)); - ASSERT_GE(base_fd_, 0); - - unique_fd rnd_fd(open("/dev/random", O_RDONLY)); - ASSERT_GE(rnd_fd, 0); - - std::unique_ptr random_buffer = std::make_unique(1_MiB); - - for (size_t j = 0; j < ((total_base_size_) / 1_MiB); j++) { - ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), 1_MiB, 0), true); - ASSERT_EQ(android::base::WriteFully(base_fd_, random_buffer.get(), 1_MiB), true); - } - - ASSERT_EQ(lseek(base_fd_, 0, SEEK_SET), 0); -} - void SnapuserdTest::ReadSnapshotDeviceAndValidate() { unique_fd fd(open(dmuser_dev_->GetPath().c_str(), O_RDONLY)); ASSERT_GE(fd, 0); @@ -218,19 +347,6 @@ void SnapuserdTest::ReadSnapshotDeviceAndValidate() { ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 4), size_), 0); } -std::unique_ptr SnapuserdTest::CreateCowDeviceInternal() { - std::string path = android::base::GetExecutableDirectory(); - cow_system_ = std::make_unique(path); - - CowOptions options; - options.compression = "gz"; - - unique_fd fd(cow_system_->fd); - cow_system_->fd = -1; - - return CreateCowWriter(kDefaultCowVersion, options, std::move(fd)); -} - void SnapuserdTest::CreateCowDeviceWithCopyOverlap_2() { auto writer = CreateCowDeviceInternal(); ASSERT_NE(writer, nullptr); @@ -427,90 +543,6 @@ void SnapuserdTest::CreateCowDeviceOrderedOps() { } } -void SnapuserdTest::CreateCowDevice() { - unique_fd rnd_fd; - loff_t offset = 0; - - auto writer = CreateCowDeviceInternal(); - ASSERT_NE(writer, nullptr); - - rnd_fd.reset(open("/dev/random", O_RDONLY)); - ASSERT_TRUE(rnd_fd > 0); - - std::unique_ptr random_buffer_1_ = std::make_unique(size_); - - // Fill random data - for (size_t j = 0; j < (size_ / 1_MiB); j++) { - ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0), - true); - - offset += 1_MiB; - } - - size_t num_blocks = size_ / writer->GetBlockSize(); - size_t blk_end_copy = num_blocks * 2; - size_t source_blk = num_blocks - 1; - size_t blk_src_copy = blk_end_copy - 1; - - uint32_t sequence[num_blocks * 2]; - // Sequence for Copy ops - for (int i = 0; i < num_blocks; i++) { - sequence[i] = num_blocks - 1 - i; - } - // Sequence for Xor ops - for (int i = 0; i < num_blocks; i++) { - sequence[num_blocks + i] = 5 * num_blocks - 1 - i; - } - ASSERT_TRUE(writer->AddSequenceData(2 * num_blocks, sequence)); - - size_t x = num_blocks; - while (1) { - ASSERT_TRUE(writer->AddCopy(source_blk, blk_src_copy)); - x -= 1; - if (x == 0) { - break; - } - source_blk -= 1; - blk_src_copy -= 1; - } - - source_blk = num_blocks; - blk_src_copy = blk_end_copy; - - ASSERT_TRUE(writer->AddRawBlocks(source_blk, random_buffer_1_.get(), size_)); - - size_t blk_zero_copy_start = source_blk + num_blocks; - size_t blk_zero_copy_end = blk_zero_copy_start + num_blocks; - - ASSERT_TRUE(writer->AddZeroBlocks(blk_zero_copy_start, num_blocks)); - - size_t blk_random2_replace_start = blk_zero_copy_end; - - ASSERT_TRUE(writer->AddRawBlocks(blk_random2_replace_start, random_buffer_1_.get(), size_)); - - size_t blk_xor_start = blk_random2_replace_start + num_blocks; - size_t xor_offset = BLOCK_SZ / 2; - ASSERT_TRUE(writer->AddXorBlocks(blk_xor_start, random_buffer_1_.get(), size_, num_blocks, - xor_offset)); - - // Flush operations - ASSERT_TRUE(writer->Finalize()); - // Construct the buffer required for validation - orig_buffer_ = std::make_unique(total_base_size_); - std::string zero_buffer(size_, 0); - ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), size_, size_), true); - memcpy((char*)orig_buffer_.get() + size_, random_buffer_1_.get(), size_); - memcpy((char*)orig_buffer_.get() + (size_ * 2), (void*)zero_buffer.c_str(), size_); - memcpy((char*)orig_buffer_.get() + (size_ * 3), random_buffer_1_.get(), size_); - ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, &orig_buffer_.get()[size_ * 4], size_, - size_ + xor_offset), - true); - for (int i = 0; i < size_; i++) { - orig_buffer_.get()[(size_ * 4) + i] = - (uint8_t)(orig_buffer_.get()[(size_ * 4) + i] ^ random_buffer_1_.get()[i]); - } -} - void SnapuserdTest::InitCowDevice() { bool use_iouring = true; if (FLAGS_force_config == "iouring_disabled") { @@ -529,18 +561,6 @@ void SnapuserdTest::InitCowDevice() { #endif } -void SnapuserdTest::SetDeviceControlName() { - system_device_name_.clear(); - system_device_ctrl_name_.clear(); - - std::string str(cow_system_->path); - std::size_t found = str.find_last_of("/\\"); - ASSERT_NE(found, std::string::npos); - system_device_name_ = str.substr(found + 1); - - system_device_ctrl_name_ = system_device_name_ + "-ctrl"; -} - void SnapuserdTest::CreateUserDevice() { auto dev_sz = base_dev_->GetSize(); ASSERT_NE(dev_sz, 0); From 1333d87bfe60623b8db8eb6b38b94957cf165e79 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 7 Aug 2023 19:58:55 -0700 Subject: [PATCH 0294/1487] snapuserd: Reduce size of COWs in tests. This greatly reduces the runtime of snapuserd_test, from 4 minutes to about 1.5 minutes. Bug: 269361087 Test: snapuserd_test Change-Id: Ic18443d4e4318f6ef6adadeabd47ccceeeb19b6f --- .../libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c5ccb0d22f16..01fe06fe79bf 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -72,7 +72,7 @@ class SnapuserdTestBase : public ::testing::Test { std::unique_ptr CreateCowDeviceInternal(); std::unique_ptr harness_; - size_t size_ = 100_MiB; + size_t size_ = 10_MiB; int total_base_size_ = 0; std::string system_device_ctrl_name_; std::string system_device_name_; From 50460fa3acde3b8e663e51a56b3d27561c09878e Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Thu, 3 Aug 2023 16:39:36 -0700 Subject: [PATCH 0295/1487] libsnapshot: take in compression_level Changing libsnapshot to have configurable compression_level Test: ota_from_target_files Change-Id: I4c050a2c83cc0fa9079f94dd2d9009f291358740 --- .../include/libsnapshot/cow_writer.h | 14 +++--- .../libsnapshot_cow/cow_compress.cpp | 49 ++++++++++++++----- .../libsnapshot/libsnapshot_cow/test_v2.cpp | 14 +++++- .../libsnapshot/libsnapshot_cow/writer_v2.cpp | 35 ++++++++++--- 4 files changed, 83 insertions(+), 29 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h index d6194eb9396f..755050fa1d4f 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h @@ -110,16 +110,17 @@ class ICowWriter { class CompressWorker { public: - CompressWorker(CowCompressionAlgorithm compression, uint32_t block_size); + CompressWorker(CowCompression compression, uint32_t block_size); bool RunThread(); void EnqueueCompressBlocks(const void* buffer, size_t num_blocks); bool GetCompressedBuffers(std::vector>* compressed_buf); void Finalize(); - static std::basic_string Compress(CowCompressionAlgorithm compression, - const void* data, size_t length); + static uint32_t GetDefaultCompressionLevel(CowCompressionAlgorithm compression); + static std::basic_string Compress(CowCompression compression, const void* data, + size_t length); - static bool CompressBlocks(CowCompressionAlgorithm compression, size_t block_size, - const void* buffer, size_t num_blocks, + static bool CompressBlocks(CowCompression compression, size_t block_size, const void* buffer, + size_t num_blocks, std::vector>* compressed_data); private: @@ -130,7 +131,7 @@ class CompressWorker { std::vector> compressed_data; }; - CowCompressionAlgorithm compression_; + CowCompression compression_; uint32_t block_size_; std::queue work_queue_; @@ -139,7 +140,6 @@ class CompressWorker { std::condition_variable cv_; bool stopped_ = false; - std::basic_string Compress(const void* data, size_t length); bool CompressBlocks(const void* buffer, size_t num_blocks, std::vector>* compressed_data); }; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp index a4a0ad661823..96d60161218d 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp @@ -46,24 +46,47 @@ std::optional CompressionAlgorithmFromString(std::strin } else if (name == "none" || name.empty()) { return {kCowCompressNone}; } else { + LOG(ERROR) << "unable to determine default compression algorithm for: " << name; return {}; } } -std::basic_string CompressWorker::Compress(const void* data, size_t length) { - return Compress(compression_, data, length); +// 1. Default compression level is determined by compression algorithm +// 2. There might be compatibility issues if a value is changed here, as some older versions of +// Android will assume a different compression level, causing cow_size estimation differences that +// will lead to OTA failure. Ensure that the device and OTA package use the same compression level +// for OTA to succeed. +uint32_t CompressWorker::GetDefaultCompressionLevel(CowCompressionAlgorithm compression) { + switch (compression) { + case kCowCompressGz: { + return Z_BEST_COMPRESSION; + } + case kCowCompressBrotli: { + return BROTLI_DEFAULT_QUALITY; + } + case kCowCompressLz4: { + break; + } + case kCowCompressZstd: { + return ZSTD_defaultCLevel(); + } + case kCowCompressNone: { + break; + } + } + return 0; } -std::basic_string CompressWorker::Compress(CowCompressionAlgorithm compression, - const void* data, size_t length) { - switch (compression) { +std::basic_string CompressWorker::Compress(CowCompression compression, const void* data, + size_t length) { + switch (compression.algorithm) { case kCowCompressGz: { const auto bound = compressBound(length); std::basic_string buffer(bound, '\0'); uLongf dest_len = bound; auto rv = compress2(buffer.data(), &dest_len, reinterpret_cast(data), - length, Z_BEST_COMPRESSION); + length, compression.compression_level); if (rv != Z_OK) { LOG(ERROR) << "compress2 returned: " << rv; return {}; @@ -81,8 +104,8 @@ std::basic_string CompressWorker::Compress(CowCompressionAlgorithm comp size_t encoded_size = bound; auto rv = BrotliEncoderCompress( - BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, length, - reinterpret_cast(data), &encoded_size, buffer.data()); + compression.compression_level, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, + length, reinterpret_cast(data), &encoded_size, buffer.data()); if (!rv) { LOG(ERROR) << "BrotliEncoderCompress failed"; return {}; @@ -117,8 +140,8 @@ std::basic_string CompressWorker::Compress(CowCompressionAlgorithm comp } case kCowCompressZstd: { std::basic_string buffer(ZSTD_compressBound(length), '\0'); - const auto compressed_size = - ZSTD_compress(buffer.data(), buffer.size(), data, length, 0); + const auto compressed_size = ZSTD_compress(buffer.data(), buffer.size(), data, length, + compression.compression_level); if (compressed_size <= 0) { LOG(ERROR) << "ZSTD compression failed " << compressed_size; return {}; @@ -133,7 +156,7 @@ std::basic_string CompressWorker::Compress(CowCompressionAlgorithm comp return buffer; } default: - LOG(ERROR) << "unhandled compression type: " << compression; + LOG(ERROR) << "unhandled compression type: " << compression.algorithm; break; } return {}; @@ -143,7 +166,7 @@ bool CompressWorker::CompressBlocks(const void* buffer, size_t num_blocks, return CompressBlocks(compression_, block_size_, buffer, num_blocks, compressed_data); } -bool CompressWorker::CompressBlocks(CowCompressionAlgorithm compression, size_t block_size, +bool CompressWorker::CompressBlocks(CowCompression compression, size_t block_size, const void* buffer, size_t num_blocks, std::vector>* compressed_data) { const uint8_t* iter = reinterpret_cast(buffer); @@ -255,7 +278,7 @@ void CompressWorker::Finalize() { cv_.notify_all(); } -CompressWorker::CompressWorker(CowCompressionAlgorithm compression, uint32_t block_size) +CompressWorker::CompressWorker(CowCompression compression, uint32_t block_size) : compression_(compression), block_size_(block_size) {} } // namespace snapshot diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp index ab275d4eba0f..2258d9fb75cb 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp @@ -480,7 +480,7 @@ TEST_P(CompressionTest, HorribleStream) { std::string expected = "The quick brown fox jumps over the lazy dog."; expected.resize(4096, '\0'); - auto result = CompressWorker::Compress(*algorithm, expected.data(), expected.size()); + auto result = CompressWorker::Compress(compression, expected.data(), expected.size()); ASSERT_FALSE(result.empty()); HorribleStream stream(result); @@ -1409,6 +1409,18 @@ TEST_F(CowTest, RevMergeOpItrTest) { ASSERT_TRUE(iter->AtEnd()); } +TEST_F(CowTest, ParseOptionsTest) { + CowOptions options; + std::vector> testcases = { + {"gz,4", true}, {"gz,4,4", false}, {"lz4,4", true}, {"brotli,4", true}, + {"zstd,4", true}, {"zstd,x", false}, {"zs,4", false}, {"zstd.4", false}}; + for (size_t i = 0; i < testcases.size(); i++) { + options.compression = testcases[i].first; + CowWriterV2 writer(options, GetCowFd()); + ASSERT_EQ(writer.Initialize(), testcases[i].second); + } +} + TEST_F(CowTest, LegacyRevMergeOpItrTest) { CowOptions options; options.cluster_ops = 5; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp index cbd7569d210f..4ab5713b476a 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp @@ -39,6 +39,8 @@ #include #include +#include "android-base/parseint.h" +#include "android-base/strings.h" #include "parser_v2.h" // The info messages here are spammy, but as useful for update_engine. Disable @@ -119,11 +121,28 @@ void CowWriterV2::SetupHeaders() { } bool CowWriterV2::ParseOptions() { - auto algorithm = CompressionAlgorithmFromString(options_.compression); + auto parts = android::base::Split(options_.compression, ","); + + if (parts.size() > 2) { + LOG(ERROR) << "failed to parse compression parameters: invalid argument count: " + << parts.size() << " " << options_.compression; + return false; + } + auto algorithm = CompressionAlgorithmFromString(parts[0]); if (!algorithm) { LOG(ERROR) << "unrecognized compression: " << options_.compression; return false; } + if (parts.size() > 1) { + if (!android::base::ParseUint(parts[1], &compression_.compression_level)) { + LOG(ERROR) << "failed to parse compression level invalid type: " << parts[1]; + return false; + } + } else { + compression_.compression_level = + CompressWorker::GetDefaultCompressionLevel(algorithm.value()); + } + compression_.algorithm = *algorithm; if (options_.cluster_ops == 1) { @@ -165,7 +184,7 @@ void CowWriterV2::InitWorkers() { return; } for (int i = 0; i < num_compress_threads_; i++) { - auto wt = std::make_unique(compression_.algorithm, header_.block_size); + auto wt = std::make_unique(compression_, header_.block_size); threads_.emplace_back(std::async(std::launch::async, &CompressWorker::RunThread, wt.get())); compress_threads_.push_back(std::move(wt)); } @@ -320,8 +339,8 @@ bool CowWriterV2::CompressBlocks(size_t num_blocks, const void* data) { const uint8_t* iter = reinterpret_cast(data); compressed_buf_.clear(); if (num_threads <= 1) { - return CompressWorker::CompressBlocks(compression_.algorithm, options_.block_size, data, - num_blocks, &compressed_buf_); + return CompressWorker::CompressBlocks(compression_, options_.block_size, data, num_blocks, + &compressed_buf_); } // Submit the blocks per thread. The retrieval of @@ -393,8 +412,8 @@ bool CowWriterV2::EmitBlocks(uint64_t new_block_start, const void* data, size_t buf_iter_++; return data; } else { - auto data = CompressWorker::Compress(compression_.algorithm, iter, - header_.block_size); + auto data = + CompressWorker::Compress(compression_, iter, header_.block_size); return data; } }(); @@ -507,8 +526,8 @@ bool CowWriterV2::Finalize() { } } - // Footer should be at the end of a file, so if there is data after the current block, end it - // and start a new cluster. + // Footer should be at the end of a file, so if there is data after the current block, end + // it and start a new cluster. if (cluster_size_ && current_data_size_ > 0) { EmitCluster(); extra_cluster = true; From fe6c1d55f72da9429fcae161cd582125e59b027c Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 8 Aug 2023 08:46:43 -0700 Subject: [PATCH 0296/1487] Moving includes Removing unused includes + moving includes to file that uses them Test: m libsnapshot Change-Id: Iacb1d1d0d17cf9059583443e9a17fdc1007bc399 --- fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h | 3 --- fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp | 2 +- fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h | 1 + 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h index 755050fa1d4f..74b8bb845533 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h @@ -18,14 +18,11 @@ #include #include -#include #include #include #include #include #include -#include -#include #include #include diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp index 4ab5713b476a..6d04c6a0c380 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp @@ -20,8 +20,8 @@ #include #include +#include #include -#include #include #include diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h index 1aa851872f42..3f357e024cf0 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h @@ -14,6 +14,7 @@ #pragma once +#include #include "writer_base.h" namespace android { From 0ff0eeed775142048c4f22021310d6a7b3084e53 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 12 May 2023 10:09:23 -0700 Subject: [PATCH 0297/1487] libfs_avb: Allow overriding the slot suffix. There is no easy way to override fs_mgr_get_slot_suffix for testing or for simulating slot switches. It relies on global properties, and since fstab is usually a static library, linked multiple times, we can't just stick a global variable in fs_mgr_slotselect. libfs_avb already takes slot suffix arguments in various places. This CL extends that by adding arguments to AvbHandle and FsManagerAvbOps. Bug: N/A Test: snapshotctl Change-Id: Ide7f052b38249d6bc79a6a2c124baf8ca08bcc3b --- fs_mgr/libfs_avb/avb_ops.cpp | 13 ++++++++---- fs_mgr/libfs_avb/avb_ops.h | 3 ++- fs_mgr/libfs_avb/fs_avb.cpp | 25 ++++++++++++++++++------ fs_mgr/libfs_avb/include/fs_avb/fs_avb.h | 8 +++++--- fs_mgr/libfstab/include/fstab/fstab.h | 3 +++ fs_mgr/libfstab/slotselect.cpp | 10 ++++++++++ 6 files changed, 48 insertions(+), 14 deletions(-) diff --git a/fs_mgr/libfs_avb/avb_ops.cpp b/fs_mgr/libfs_avb/avb_ops.cpp index a119bfcde274..cc197761984d 100644 --- a/fs_mgr/libfs_avb/avb_ops.cpp +++ b/fs_mgr/libfs_avb/avb_ops.cpp @@ -108,8 +108,8 @@ static AvbIOResult get_size_of_partition(AvbOps* ops ATTRIBUTE_UNUSED, // Converts a partition name (with ab_suffix) to the corresponding mount point. // e.g., "system_a" => "/system", // e.g., "vendor_a" => "/vendor", -static std::string DeriveMountPoint(const std::string& partition_name) { - const std::string ab_suffix = fs_mgr_get_slot_suffix(); +static std::string DeriveMountPoint(const std::string& partition_name, + const std::string& ab_suffix) { std::string mount_point(partition_name); auto found = partition_name.rfind(ab_suffix); if (found != std::string::npos) { @@ -119,7 +119,7 @@ static std::string DeriveMountPoint(const std::string& partition_name) { return "/" + mount_point; } -FsManagerAvbOps::FsManagerAvbOps() { +FsManagerAvbOps::FsManagerAvbOps(const std::string& slot_suffix) { // We only need to provide the implementation of read_from_partition() // operation since that's all what is being used by the avb_slot_verify(). // Other I/O operations are only required in bootloader but not in @@ -135,6 +135,11 @@ FsManagerAvbOps::FsManagerAvbOps() { // Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps. avb_ops_.user_data = this; + + slot_suffix_ = slot_suffix; + if (slot_suffix_.empty()) { + slot_suffix_ = fs_mgr_get_slot_suffix(); + } } // Given a partition name (with ab_suffix), e.g., system_a, returns the corresponding @@ -149,7 +154,7 @@ std::string FsManagerAvbOps::GetLogicalPath(const std::string& partition_name) { return ""; } - const auto mount_point = DeriveMountPoint(partition_name); + const auto mount_point = DeriveMountPoint(partition_name, slot_suffix_); if (mount_point.empty()) return ""; auto fstab_entry = GetEntryForMountPoint(&fstab_, mount_point); diff --git a/fs_mgr/libfs_avb/avb_ops.h b/fs_mgr/libfs_avb/avb_ops.h index 12686a61df5b..709091e3832e 100644 --- a/fs_mgr/libfs_avb/avb_ops.h +++ b/fs_mgr/libfs_avb/avb_ops.h @@ -48,7 +48,7 @@ namespace fs_mgr { // class FsManagerAvbOps { public: - FsManagerAvbOps(); + explicit FsManagerAvbOps(const std::string& slot_suffix = {}); static FsManagerAvbOps* GetInstanceFromAvbOps(AvbOps* ops) { return reinterpret_cast(ops->user_data); @@ -66,6 +66,7 @@ class FsManagerAvbOps { std::string GetPartitionPath(const char* partition_name); AvbOps avb_ops_; Fstab fstab_; + std::string slot_suffix_; }; } // namespace fs_mgr diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp index a28887627673..fb224230fe4c 100644 --- a/fs_mgr/libfs_avb/fs_avb.cpp +++ b/fs_mgr/libfs_avb/fs_avb.cpp @@ -182,6 +182,11 @@ bool AvbVerifier::VerifyVbmetaImages(const std::vector& vbmeta_image // class AvbHandle // --------------- +AvbHandle::AvbHandle() : status_(AvbHandleStatus::kUninitialized) { + slot_suffix_ = fs_mgr_get_slot_suffix(); + other_slot_suffix_ = fs_mgr_get_other_slot_suffix(); +} + AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta( const std::string& partition_name, const std::string& ab_suffix, const std::string& ab_other_suffix, const std::string& expected_public_key_path, @@ -194,6 +199,9 @@ AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta( return nullptr; } + avb_handle->slot_suffix_ = ab_suffix; + avb_handle->other_slot_suffix_ = ab_other_suffix; + std::string expected_key_blob; if (!expected_public_key_path.empty()) { if (access(expected_public_key_path.c_str(), F_OK) != 0) { @@ -373,9 +381,14 @@ AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const FstabEntry& fstab_entry, return avb_handle; } -AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta() { +AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const std::string& slot_suffix) { // Loads inline vbmeta images, starting from /vbmeta. - return LoadAndVerifyVbmeta("vbmeta", fs_mgr_get_slot_suffix(), fs_mgr_get_other_slot_suffix(), + auto suffix = slot_suffix; + if (suffix.empty()) { + suffix = fs_mgr_get_slot_suffix(); + } + auto other_suffix = android::fs_mgr::OtherSlotSuffix(suffix); + return LoadAndVerifyVbmeta("vbmeta", suffix, other_suffix, {} /* expected_public_key, already checked by bootloader */, HashAlgorithm::kSHA256, IsAvbPermissive(), /* allow_verification_error */ @@ -399,7 +412,7 @@ AvbUniquePtr AvbHandle::Open() { ? AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR : AVB_SLOT_VERIFY_FLAGS_NONE; AvbSlotVerifyResult verify_result = - avb_ops.AvbSlotVerify(fs_mgr_get_slot_suffix(), flags, &avb_handle->vbmeta_images_); + avb_ops.AvbSlotVerify(avb_handle->slot_suffix_, flags, &avb_handle->vbmeta_images_); // Only allow the following verify results: // - AVB_SLOT_VERIFY_RESULT_OK. @@ -492,7 +505,7 @@ AvbHashtreeResult AvbHandle::SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait } if (!LoadAvbHashtreeToEnableVerity(fstab_entry, wait_for_verity_dev, vbmeta_images_, - fs_mgr_get_slot_suffix(), fs_mgr_get_other_slot_suffix())) { + slot_suffix_, other_slot_suffix_)) { return AvbHashtreeResult::kFail; } @@ -526,8 +539,8 @@ std::string AvbHandle::GetSecurityPatchLevel(const FstabEntry& fstab_entry) cons if (vbmeta_images_.size() < 1) { return ""; } - std::string avb_partition_name = DeriveAvbPartitionName(fstab_entry, fs_mgr_get_slot_suffix(), - fs_mgr_get_other_slot_suffix()); + std::string avb_partition_name = + DeriveAvbPartitionName(fstab_entry, slot_suffix_, other_slot_suffix_); auto avb_prop_name = "com.android.build." + avb_partition_name + ".security_patch"; return GetAvbPropertyDescriptor(avb_prop_name, vbmeta_images_); } diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h index 4702e6807914..924ab247384f 100644 --- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h +++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h @@ -83,8 +83,8 @@ class AvbHandle { // is verified and can be trusted. // // TODO(bowgotsai): remove Open() and switch to LoadAndVerifyVbmeta(). - static AvbUniquePtr Open(); // loads inline vbmeta, via libavb. - static AvbUniquePtr LoadAndVerifyVbmeta(); // loads inline vbmeta. + static AvbUniquePtr Open(); // loads inline vbmeta, via libavb. + static AvbUniquePtr LoadAndVerifyVbmeta(const std::string& slot_suffix = {}); // The caller can specify optional preload_avb_key_blobs for public key matching. // This is mostly for init to preload AVB keys before chroot into /system. @@ -137,12 +137,14 @@ class AvbHandle { AvbHandle& operator=(AvbHandle&&) noexcept = delete; // no move assignment private: - AvbHandle() : status_(AvbHandleStatus::kUninitialized) {} + AvbHandle(); std::vector vbmeta_images_; VBMetaInfo vbmeta_info_; // A summary info for vbmeta_images_. AvbHandleStatus status_; std::string avb_version_; + std::string slot_suffix_; + std::string other_slot_suffix_; }; } // namespace fs_mgr diff --git a/fs_mgr/libfstab/include/fstab/fstab.h b/fs_mgr/libfstab/include/fstab/fstab.h index 150a47da350c..09471f087f6c 100644 --- a/fs_mgr/libfstab/include/fstab/fstab.h +++ b/fs_mgr/libfstab/include/fstab/fstab.h @@ -145,5 +145,8 @@ void ImportKernelCmdline(const std::function& fn // Otherwise returns false and |*out| is not modified. bool GetKernelCmdline(const std::string& key, std::string* out); +// Return the "other" slot for the given slot suffix. +std::string OtherSlotSuffix(const std::string& suffix); + } // namespace fs_mgr } // namespace android diff --git a/fs_mgr/libfstab/slotselect.cpp b/fs_mgr/libfstab/slotselect.cpp index 97b2ba1f575f..db3f8da64254 100644 --- a/fs_mgr/libfstab/slotselect.cpp +++ b/fs_mgr/libfstab/slotselect.cpp @@ -74,3 +74,13 @@ bool fs_mgr_update_for_slotselect(Fstab* fstab) { } return true; } + +namespace android { +namespace fs_mgr { + +std::string OtherSlotSuffix(const std::string& suffix) { + return other_suffix(suffix); +} + +} // namespace fs_mgr +} // namespace android From ad5df3256061b2afeddc05c30200fe3f9df2543f Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 8 Aug 2023 13:49:27 -0700 Subject: [PATCH 0298/1487] decompressor maintenence cleaning up a bit of code for consistency + adding in zstd to FromString() function Test: m libsnapshot Change-Id: Ic8b7243c5a5ee25326a46e944c13578136f27078 --- .../libsnapshot_cow/cow_decompress.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp index da90cc048169..3692c1a8aa9c 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -62,6 +63,8 @@ std::unique_ptr IDecompressor::FromString(std::string_view compre return IDecompressor::Brotli(); } else if (compressor == "gz") { return IDecompressor::Gz(); + } else if (compressor == "zstd") { + return IDecompressor::Zstd(); } else { return nullptr; } @@ -211,10 +214,6 @@ bool GzDecompressor::PartialDecompress(const uint8_t* data, size_t length) { return true; } -std::unique_ptr IDecompressor::Gz() { - return std::unique_ptr(new GzDecompressor()); -} - class BrotliDecompressor final : public StreamDecompressor { public: ~BrotliDecompressor(); @@ -275,10 +274,6 @@ bool BrotliDecompressor::PartialDecompress(const uint8_t* data, size_t length) { return true; } -std::unique_ptr IDecompressor::Brotli() { - return std::unique_ptr(new BrotliDecompressor()); -} - class Lz4Decompressor final : public IDecompressor { public: ~Lz4Decompressor() override = default; @@ -382,6 +377,14 @@ class ZstdDecompressor final : public IDecompressor { } }; +std::unique_ptr IDecompressor::Brotli() { + return std::make_unique(); +} + +std::unique_ptr IDecompressor::Gz() { + return std::make_unique(); +} + std::unique_ptr IDecompressor::Lz4() { return std::make_unique(); } From 1b13b14758257350cb76381b52c906685ed58c74 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 8 Aug 2023 16:00:30 -0700 Subject: [PATCH 0299/1487] crasher: add pac and bti crashes. Also add the missing `.size` directives to all the assembler functions for slightly improved backtraces. Test: crasher64 pac; crasher64 bti Change-Id: I8e0c127cbff56c33637e6ca8f1d927b971951807 --- debuggerd/crasher/arm/crashglue.S | 8 ++-- debuggerd/crasher/arm64/crashglue.S | 45 +++++++++++++++++++-- debuggerd/crasher/crasher.cpp | 56 ++++++++++++++++++++++----- debuggerd/crasher/riscv64/crashglue.S | 6 ++- debuggerd/crasher/x86/crashglue.S | 6 ++- debuggerd/crasher/x86_64/crashglue.S | 6 ++- 6 files changed, 105 insertions(+), 22 deletions(-) diff --git a/debuggerd/crasher/arm/crashglue.S b/debuggerd/crasher/arm/crashglue.S index e4adf403cd85..0def8aee3f7b 100644 --- a/debuggerd/crasher/arm/crashglue.S +++ b/debuggerd/crasher/arm/crashglue.S @@ -23,10 +23,11 @@ crash1: ldr lr, [lr] b . .cfi_endproc + .size crash1, .-crash1 -.globl crashnostack -.type crashnostack, %function -crashnostack: +.globl crash_no_stack +.type crash_no_stack, %function +crash_no_stack: .cfi_startproc mov r1, sp .cfi_def_cfa_register r1 @@ -35,3 +36,4 @@ crashnostack: ldr r0, [r0] b . .cfi_endproc + .size crash_no_stack, .-crash_no_stack diff --git a/debuggerd/crasher/arm64/crashglue.S b/debuggerd/crasher/arm64/crashglue.S index 97c824efb2d2..c56e19a388c7 100644 --- a/debuggerd/crasher/arm64/crashglue.S +++ b/debuggerd/crasher/arm64/crashglue.S @@ -41,11 +41,12 @@ crash1: ldr x30, [x30] b . .cfi_endproc + .size crash1, .-crash1 -.globl crashnostack -.type crashnostack, %function -crashnostack: +.globl crash_no_stack +.type crash_no_stack, %function +crash_no_stack: .cfi_startproc mov x1, sp .cfi_def_cfa_register x1 @@ -54,3 +55,41 @@ crashnostack: ldr x0, [x0] b . .cfi_endproc + .size crash_no_stack, .-crash_no_stack + + +.globl crash_bti +.type crash_bti, %function +crash_bti: + .cfi_startproc + adr x16, 1f + br x16 +1: // Deliberatly not a bti instruction so we crash here. + b . + .cfi_endproc + .size crash_bti, .-crash_bti + + +.globl crash_pac +.type crash_pac, %function +crash_pac: + .cfi_startproc + paciasp + // Since sp is a pac input, this ensures a mismatch. + sub sp, sp, #16 + autiasp + b . + .cfi_endproc + .size crash_pac, .-crash_pac + +// Set the PAC and BTI bits for this object file. +.section .note.gnu.property, "a" +.balign 8 +.long 4 +.long 0x10 +.long 0x5 +.asciz "GNU" +.long 0xc0000000 +.long 4 +.long 0x3 +.long 0 diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp index 12ba502ecf8b..3b52776d7b32 100644 --- a/debuggerd/crasher/crasher.cpp +++ b/debuggerd/crasher/crasher.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,9 @@ #include #include +#include +#include + // We test both kinds of logging. #include #include @@ -59,8 +63,10 @@ typedef int (__kuser_cmpxchg64_t)(const int64_t*, const int64_t*, volatile int64 // Avoid name mangling so that stacks are more readable. extern "C" { -void crash1(void); -void crashnostack(void); +void crash1(); +void crash_no_stack(); +void crash_bti(); +void crash_pac(); int do_action(const char* arg); @@ -196,13 +202,6 @@ static int usage() { fprintf(stderr, " fdsan_file close a file descriptor that's owned by a FILE*\n"); fprintf(stderr, " fdsan_dir close a file descriptor that's owned by a DIR*\n"); fprintf(stderr, " seccomp fail a seccomp check\n"); -#if defined(__arm__) - fprintf(stderr, " kuser_helper_version call kuser_helper_version\n"); - fprintf(stderr, " kuser_get_tls call kuser_get_tls\n"); - fprintf(stderr, " kuser_cmpxchg call kuser_cmpxchg\n"); - fprintf(stderr, " kuser_memory_barrier call kuser_memory_barrier\n"); - fprintf(stderr, " kuser_cmpxchg64 call kuser_cmpxchg64\n"); -#endif fprintf(stderr, " xom read execute-only memory\n"); fprintf(stderr, "\n"); fprintf(stderr, " LOG_ALWAYS_FATAL call liblog LOG_ALWAYS_FATAL\n"); @@ -223,6 +222,20 @@ static int usage() { fprintf(stderr, "\n"); fprintf(stderr, " no_new_privs set PR_SET_NO_NEW_PRIVS and then abort\n"); fprintf(stderr, "\n"); +#if defined(__arm__) + fprintf(stderr, "Also, since this is an arm32 binary:\n"); + fprintf(stderr, " kuser_helper_version call kuser_helper_version\n"); + fprintf(stderr, " kuser_get_tls call kuser_get_tls\n"); + fprintf(stderr, " kuser_cmpxchg call kuser_cmpxchg\n"); + fprintf(stderr, " kuser_memory_barrier call kuser_memory_barrier\n"); + fprintf(stderr, " kuser_cmpxchg64 call kuser_cmpxchg64\n"); +#endif +#if defined(__aarch64__) + fprintf(stderr, "Also, since this is an arm64 binary:\n"); + fprintf(stderr, " bti fail a branch target identification (BTI) check\n"); + fprintf(stderr, " pac fail a pointer authentication (PAC) check\n"); +#endif + fprintf(stderr, "\n"); fprintf(stderr, "prefix any of the above with 'thread-' to run on a new thread\n"); fprintf(stderr, "prefix any of the above with 'exhaustfd-' to exhaust\n"); fprintf(stderr, "all available file descriptors before crashing.\n"); @@ -231,6 +244,21 @@ static int usage() { return EXIT_FAILURE; } +[[maybe_unused]] static void CheckCpuFeature(const std::string& name) { + std::string cpuinfo; + if (!android::base::ReadFileToString("/proc/cpuinfo", &cpuinfo)) { + error(1, errno, "couldn't read /proc/cpuinfo"); + } + std::vector lines = android::base::Split(cpuinfo, "\n"); + for (std::string_view line : lines) { + if (!android::base::ConsumePrefix(&line, "Features\t:")) continue; + std::vector features = android::base::Split(std::string(line), " "); + if (std::find(features.begin(), features.end(), name) == features.end()) { + error(1, 0, "/proc/cpuinfo does not report feature '%s'", name.c_str()); + } + } +} + noinline int do_action(const char* arg) { // Prefixes. if (!strncmp(arg, "wait-", strlen("wait-"))) { @@ -256,7 +284,7 @@ noinline int do_action(const char* arg) { } else if (!strcasecmp(arg, "stack-overflow")) { overflow_stack(nullptr); } else if (!strcasecmp(arg, "nostack")) { - crashnostack(); + crash_no_stack(); } else if (!strcasecmp(arg, "exit")) { exit(1); } else if (!strcasecmp(arg, "call-null")) { @@ -349,6 +377,14 @@ noinline int do_action(const char* arg) { __kuser_dmb(); } else if (!strcasecmp(arg, "kuser_cmpxchg64")) { return __kuser_cmpxchg64(0, 0, 0); +#endif +#if defined(__aarch64__) + } else if (!strcasecmp(arg, "bti")) { + CheckCpuFeature("bti"); + crash_bti(); + } else if (!strcasecmp(arg, "pac")) { + CheckCpuFeature("paca"); + crash_pac(); #endif } else if (!strcasecmp(arg, "no_new_privs")) { if (prctl(PR_SET_NO_NEW_PRIVS, 1) != 0) { diff --git a/debuggerd/crasher/riscv64/crashglue.S b/debuggerd/crasher/riscv64/crashglue.S index 42f59b345723..f179e336810f 100644 --- a/debuggerd/crasher/riscv64/crashglue.S +++ b/debuggerd/crasher/riscv64/crashglue.S @@ -43,10 +43,11 @@ crash1: ld t2, 0(zero) j . .cfi_endproc + .size crash1, .-crash1 -.globl crashnostack -crashnostack: +.globl crash_no_stack +crash_no_stack: .cfi_startproc mv t1, sp .cfi_def_cfa_register t1 @@ -54,3 +55,4 @@ crashnostack: ld t2, 0(zero) j . .cfi_endproc + .size crash_no_stack, .-crash_no_stack diff --git a/debuggerd/crasher/x86/crashglue.S b/debuggerd/crasher/x86/crashglue.S index e8eb3a7cab5c..453035bf81ab 100644 --- a/debuggerd/crasher/x86/crashglue.S +++ b/debuggerd/crasher/x86/crashglue.S @@ -6,13 +6,15 @@ crash1: movl $0, %edx jmp *%edx + .size crash1, .-crash1 -.globl crashnostack -crashnostack: +.globl crash_no_stack +crash_no_stack: .cfi_startproc movl %esp, %eax .cfi_def_cfa_register %eax movl $0, %esp movl (%esp), %ebx .cfi_endproc + .size crash_no_stack, .-crash_no_stack diff --git a/debuggerd/crasher/x86_64/crashglue.S b/debuggerd/crasher/x86_64/crashglue.S index 8f6721478a0b..c3d39c483f3c 100644 --- a/debuggerd/crasher/x86_64/crashglue.S +++ b/debuggerd/crasher/x86_64/crashglue.S @@ -6,13 +6,15 @@ crash1: movl $0, %edx jmp *%rdx + .size crash1, .-crash1 -.globl crashnostack -crashnostack: +.globl crash_no_stack +crash_no_stack: .cfi_startproc movq %rsp, %rax .cfi_def_cfa_register %rax movq $0, %rsp movq (%rsp), %rbx .cfi_endproc + .size crash_no_stack, .-crash_no_stack From 8665b5f9df3141db35c6b3ddc36286ab1c69a611 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 8 Aug 2023 16:34:19 -0700 Subject: [PATCH 0300/1487] snapuserd: Remove host_supported from snapuserd_test until it passes. Bug: 295074841 Test: snapuserd_test Change-Id: Ie51263ec6971f9806bcfa2b522e5ed24da5d65cf --- fs_mgr/libsnapshot/snapuserd/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index fe7f99c675d7..6548cc8a75b0 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -257,5 +257,4 @@ cc_test { }, auto_gen_config: true, require_root: false, - host_supported: true, } From 566c65239f1cf3fcb0d8745715e5ef1083d4bd3a Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Wed, 9 Aug 2023 07:05:31 +0000 Subject: [PATCH 0301/1487] Use /bootstrap-apex for bootstrap APEXes This new directory is bind-mounted to /apex in the bootstrap mount namespace so that apexd-bootstrap mounts bootstrap APEXes there via /apex. The directory is shared between two mount namespaces, hence visible in the default mount namespace. Bug: 290148078 Test: VendorApexHostTestCases Change-Id: I841480e41be8def5a4c6a4aa874c4e21465a71d3 --- init/init.cpp | 6 ++++++ init/mount_namespace.cpp | 35 ++++++++++++++++++++++++++--------- init/mount_namespace.h | 3 +++ init/selinux.cpp | 2 +- rootdir/Android.mk | 2 +- 5 files changed, 37 insertions(+), 11 deletions(-) diff --git a/init/init.cpp b/init/init.cpp index da63fdc3bda5..4bb8eecb981a 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -832,6 +832,12 @@ static void MountExtraFilesystems() { CHECKCALL(mount("tmpfs", "/apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0")); + if (NeedsTwoMountNamespaces()) { + // /bootstrap-apex is used to mount "bootstrap" APEXes. + CHECKCALL(mount("tmpfs", "/bootstrap-apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, + "mode=0755,uid=0,gid=0")); + } + // /linkerconfig is used to keep generated linker configuration CHECKCALL(mount("tmpfs", "/linkerconfig", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0")); diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp index 5b53d5092227..7918f23e9e82 100644 --- a/init/mount_namespace.cpp +++ b/init/mount_namespace.cpp @@ -66,15 +66,6 @@ static std::string GetMountNamespaceId() { return ret; } -// In case we have two sets of APEXes (non-updatable, updatable), we need two separate mount -// namespaces. -static bool NeedsTwoMountNamespaces() { - if (IsRecoveryMode()) return false; - // In microdroid, there's only one set of APEXes in built-in directories include block devices. - if (IsMicrodroid()) return false; - return true; -} - static android::base::unique_fd bootstrap_ns_fd; static android::base::unique_fd default_ns_fd; @@ -83,6 +74,15 @@ static std::string default_ns_id; } // namespace +// In case we have two sets of APEXes (non-updatable, updatable), we need two separate mount +// namespaces. +bool NeedsTwoMountNamespaces() { + if (IsRecoveryMode()) return false; + // In microdroid, there's only one set of APEXes in built-in directories include block devices. + if (IsMicrodroid()) return false; + return true; +} + bool SetupMountNamespaces() { // Set the propagation type of / as shared so that any mounting event (e.g. // /data) is by default visible to all processes. When private mounting is @@ -163,6 +163,23 @@ bool SetupMountNamespaces() { PLOG(ERROR) << "Cannot switch back to bootstrap mount namespace"; return false; } + + // Some components (e.g. servicemanager) need to access bootstrap + // APEXes from the default mount namespace. To achieve that, we bind-mount + // /apex to /bootstrap-apex in the bootstrap mount namespace. Since /bootstrap-apex + // is "shared", the mounts are visible in the default mount namespace as well. + // + // The end result will look like: + // in the bootstrap mount namespace: + // /apex (== /bootstrap-apex) + // {bootstrap APEXes from the read-only partition} + // + // in the default mount namespace: + // /bootstrap-apex + // {bootstrap APEXes from the read-only partition} + // /apex + // {APEXes, can be from /data partition} + if (!(BindMount("/bootstrap-apex", "/apex"))) return false; } else { // Otherwise, default == bootstrap default_ns_fd.reset(OpenMountNamespace()); diff --git a/init/mount_namespace.h b/init/mount_namespace.h index 5e3dab241290..43c5476a6ab8 100644 --- a/init/mount_namespace.h +++ b/init/mount_namespace.h @@ -24,9 +24,12 @@ namespace init { enum MountNamespace { NS_BOOTSTRAP, NS_DEFAULT }; bool SetupMountNamespaces(); + base::Result SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespace); base::Result GetCurrentMountNamespace(); +bool NeedsTwoMountNamespaces(); + } // namespace init } // namespace android diff --git a/init/selinux.cpp b/init/selinux.cpp index f34474f85093..ebdcaa62db38 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -757,7 +757,7 @@ void SelinuxRestoreContext() { selinux_android_restorecon("/dev/device-mapper", 0); selinux_android_restorecon("/apex", 0); - + selinux_android_restorecon("/bootstrap-apex", 0); selinux_android_restorecon("/linkerconfig", 0); // adb remount, snapshot-based updates, and DSUs all create files during diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 3362872c070d..52187536f3fe 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -91,7 +91,7 @@ endif # # create some directories (some are mount points) and symlinks LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \ - dev proc sys system data data_mirror odm oem acct config storage mnt apex debug_ramdisk \ + dev proc sys system data data_mirror odm oem acct config storage mnt apex bootstrap-apex debug_ramdisk \ linkerconfig second_stage_resources postinstall $(BOARD_ROOT_EXTRA_FOLDERS)); \ ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \ ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \ From cedcb4cd92d0d677d62ec97998ef8b1d467caac5 Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Wed, 9 Aug 2023 11:32:48 +0100 Subject: [PATCH 0302/1487] KeyMint HAL: process destroyAttestationIds Bugs: 283049310 Test: VtsAidlKeyMintTargetTest using disabled test Change-Id: I545511a7a701faf8e82dff9c169c3738f2c30e6d --- trusty/keymaster/TrustyKeymaster.cpp | 5 +++++ trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h | 2 ++ trusty/keymaster/keymint/TrustyKeyMintDevice.cpp | 6 +++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/trusty/keymaster/TrustyKeymaster.cpp b/trusty/keymaster/TrustyKeymaster.cpp index ac986951da56..b118a2001ca2 100644 --- a/trusty/keymaster/TrustyKeymaster.cpp +++ b/trusty/keymaster/TrustyKeymaster.cpp @@ -218,6 +218,11 @@ void TrustyKeymaster::DeleteAllKeys(const DeleteAllKeysRequest& request, ForwardCommand(KM_DELETE_ALL_KEYS, request, response); } +void TrustyKeymaster::DestroyAttestationIds(const DestroyAttestationIdsRequest& request, + DestroyAttestationIdsResponse* response) { + ForwardCommand(KM_DESTROY_ATTESTATION_IDS, request, response); +} + void TrustyKeymaster::BeginOperation(const BeginOperationRequest& request, BeginOperationResponse* response) { ForwardCommand(KM_BEGIN_OPERATION, request, response); diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h index 60d3f87ae6e5..c50178bcfa2e 100644 --- a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h +++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h @@ -55,6 +55,8 @@ class TrustyKeymaster { void UpgradeKey(const UpgradeKeyRequest& request, UpgradeKeyResponse* response); void DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response); void DeleteAllKeys(const DeleteAllKeysRequest& request, DeleteAllKeysResponse* response); + void DestroyAttestationIds(const DestroyAttestationIdsRequest& request, + DestroyAttestationIdsResponse* response); void BeginOperation(const BeginOperationRequest& request, BeginOperationResponse* response); void UpdateOperation(const UpdateOperationRequest& request, UpdateOperationResponse* response); void FinishOperation(const FinishOperationRequest& request, FinishOperationResponse* response); diff --git a/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp index b696ff9316be..fec4c60fe19d 100644 --- a/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp +++ b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp @@ -258,7 +258,11 @@ ScopedAStatus TrustyKeyMintDevice::deleteAllKeys() { } ScopedAStatus TrustyKeyMintDevice::destroyAttestationIds() { - return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED); + keymaster::DestroyAttestationIdsRequest request(impl_->message_version()); + keymaster::DestroyAttestationIdsResponse response(impl_->message_version()); + impl_->DestroyAttestationIds(request, &response); + + return kmError2ScopedAStatus(response.error); } ScopedAStatus TrustyKeyMintDevice::begin(KeyPurpose purpose, const vector& keyBlob, From 376b70423d3e0ffdb3d032231a7e41d51b0ff746 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Wed, 9 Aug 2023 10:52:38 -0700 Subject: [PATCH 0303/1487] Adding force_flash functionality aosp/2452605 might've accidentally omitted force flash functionality from fastboot. Some users need to flash dynamic partitions from bootloader, so we are readding this feature back into fastboot Test: adb reboot bootloader, fastboot flash system --force Change-Id: I37a51ebbe38b27ed428c38068d30c0febd7db09c --- fastboot/task.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastboot/task.cpp b/fastboot/task.cpp index bf64f0e1e42c..146064cc5b3f 100644 --- a/fastboot/task.cpp +++ b/fastboot/task.cpp @@ -32,7 +32,7 @@ FlashTask::FlashTask(const std::string& slot, const std::string& pname, const st void FlashTask::Run() { auto flash = [&](const std::string& partition) { - if (should_flash_in_userspace(partition) && !is_userspace_fastboot()) { + if (should_flash_in_userspace(partition) && !is_userspace_fastboot() && !fp_->force_flash) { die("The partition you are trying to flash is dynamic, and " "should be flashed via fastbootd. Please run:\n" "\n" From 24a7df5d38c638489cc4e1b3a8034a3b1ad2cf36 Mon Sep 17 00:00:00 2001 From: Tomislav Novak Date: Wed, 9 Aug 2023 15:19:51 -0700 Subject: [PATCH 0304/1487] debuggerd: fix passing of fdsan_table to crash_dump Commit aosp/1259140 moved fdsan_table into debugger_process_info, which is populated conditionally. This introduced a bug where the process that receives BIONIC_SIGNAL_DEBUGGER (35) does not propagate the fdsan_table pointer to crash_dump: $ adb shell kill -SIG35 $ adb logcat -s DEBUG E DEBUG : failed to read fdsan table entry 0: I/O error Fdsan in warn-only mode uses BIONIC_SIGNAL_DEBUGGER[1], so the generated tombstones don't have any fd ownership info. Fix it by calling get_process_info() irrespective of the signal being handled, taking care to preserve the previous behavior of not showing abort messages set by applications in non-fatal dumps. Test: debuggerd_test Test: send SIG35 to arbitrary process and inspect the log and tombstone Test: crasher fdsan_file [1] https://android.googlesource.com/platform/bionic/+/20ad9129e7115417fcd1da922693947580b7f0a6/libc/bionic/fdsan.cpp#166 Change-Id: I76931ca4825e846fc99f26fa590c045130abb850 --- debuggerd/handler/debuggerd_handler.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp index 1e5365d3cd53..01365f22fc10 100644 --- a/debuggerd/handler/debuggerd_handler.cpp +++ b/debuggerd/handler/debuggerd_handler.cpp @@ -552,8 +552,14 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c } debugger_process_info process_info = {}; + if (g_callbacks.get_process_info) { + process_info = g_callbacks.get_process_info(); + } uintptr_t si_val = reinterpret_cast(info->si_ptr); if (signal_number == BIONIC_SIGNAL_DEBUGGER) { + // Applications can set abort messages via android_set_abort_message without + // actually aborting; ignore those messages in non-fatal dumps. + process_info.abort_msg = nullptr; if (info->si_code == SI_QUEUE && info->si_pid == __getpid()) { // Allow for the abort message to be explicitly specified via the sigqueue value. // Keep the bottom bit intact for representing whether we want a backtrace or a tombstone. @@ -562,8 +568,6 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c info->si_ptr = reinterpret_cast(si_val & 1); } } - } else if (g_callbacks.get_process_info) { - process_info = g_callbacks.get_process_info(); } gwp_asan_callbacks_t gwp_asan_callbacks = {}; From 3a0833c9cdf3b8c09a41bf5cadd9ffe8dd135c84 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Fri, 28 Jul 2023 13:07:53 -0700 Subject: [PATCH 0305/1487] Fix potential miscellaneous debuggerd issues. Check for the log opening failing. Add the ability to put error messages in the log and tombstone so that it's clear if the log reading failed in some way. Adjust test so that if there is a log or if no log exists, the test will still pass. Print an if the command line is unreadable instead of nothing. Test: Ran unit tests. Test: Induced error and verified error message is save in tombstone. Change-Id: I2fce8078573b40b9fed3cd453235f3824cadb5e3 --- debuggerd/debuggerd_test.cpp | 10 ++++-- debuggerd/libdebuggerd/tombstone_proto.cpp | 35 +++++++++++++++---- .../libdebuggerd/tombstone_proto_to_text.cpp | 2 ++ 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index 52c1c255458d..19ff7ebf0b44 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -2264,10 +2264,14 @@ TEST_F(CrasherTest, fault_address_after_last_map) { ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)"); - // Assumes that the open files section comes after the map section. - // If that assumption changes, the regex below needs to change. + // Verifies that the fault address error message is at the end of the + // maps section. To do this, the check below looks for the start of the + // open files section or the start of the log file section. It's possible + // for either of these sections to be present after the maps section right + // now. + // If the sections move around, this check might need to be modified. match_str = android::base::StringPrintf( - R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)", + R"(\n--->Fault address falls at %s after any mapped regions\n(---------|\nopen files:))", format_pointer(crash_uptr).c_str()); ASSERT_MATCH(result, match_str); } diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp index 7b2e0689e440..744bfabf5afb 100644 --- a/debuggerd/libdebuggerd/tombstone_proto.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto.cpp @@ -493,27 +493,48 @@ static void dump_mappings(Tombstone* tombstone, unwindstack::Maps* maps, } } +// This creates a fake log message that indicates an error occurred when +// reading the log. +static void add_error_log_msg(Tombstone* tombstone, const std::string&& error_msg) { + LogBuffer buffer; + buffer.set_name("ERROR"); + + LogMessage* log_msg = buffer.add_logs(); + log_msg->set_timestamp("00-00 00:00:00.000"); + log_msg->set_pid(0); + log_msg->set_tid(0); + log_msg->set_priority(ANDROID_LOG_ERROR); + log_msg->set_tag(""); + log_msg->set_message(error_msg); + + *tombstone->add_log_buffers() = std::move(buffer); + + async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "%s", error_msg.c_str()); +} + static void dump_log_file(Tombstone* tombstone, const char* logger, pid_t pid) { logger_list* logger_list = android_logger_list_open(android_name_to_log_id(logger), ANDROID_LOG_NONBLOCK, kMaxLogMessages, pid); + if (logger_list == nullptr) { + add_error_log_msg(tombstone, android::base::StringPrintf("Cannot open log file %s", logger)); + return; + } LogBuffer buffer; - while (true) { log_msg log_entry; ssize_t actual = android_logger_list_read(logger_list, &log_entry); - if (actual < 0) { if (actual == -EINTR) { // interrupted by signal, retry continue; } - if (actual == -EAGAIN) { - // non-blocking EOF; we're done - break; - } else { - break; + // Don't consider EAGAIN an error since this is a non-blocking call. + if (actual != -EAGAIN) { + add_error_log_msg(tombstone, android::base::StringPrintf("reading log %s failed (%s)", + logger, strerror(-actual))); } + break; } else if (actual == 0) { break; } diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp index 8e6abdfa117e..eed81fc1533a 100644 --- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp @@ -81,6 +81,8 @@ static void print_thread_header(CallbackType callback, const Tombstone& tombston if (!tombstone.command_line().empty()) { process_name = tombstone.command_line()[0].c_str(); CB(should_log, "Cmdline: %s", android::base::Join(tombstone.command_line(), " ").c_str()); + } else { + CB(should_log, "Cmdline: "); } CB(should_log, "pid: %d, tid: %d, name: %s >>> %s <<<", tombstone.pid(), thread.id(), thread.name().c_str(), process_name); From 5c4217cf6eb0686fcab73cd55d216859549b6250 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Thu, 10 Aug 2023 13:12:53 +0900 Subject: [PATCH 0306/1487] Read .rc files from bootstrap apexes To start an early_hal service from a bootstrap vendor apex, init now reads .rc files from bootstrap apexes as well. In this change, perform_apex_config command is re-purposed to support bootstrap mode. Now we have some similarity between two apexd calls: - for bootstrap apexes (in the bootstrap mount namespace): exec_start apexd-bootstrap perform_apex_config --bootstrap - for normal apexes (in the default mount namespace): restart apexd ... wait_for_prop apexd.status activated perform_apex_config Note that some tasks in perform_apex_config are not needed in the bootstrap. For example, we don't need to create apexdata directories for bootstrap apexes. Bug: 290148081 Test: VendorApexHostTestCases Change-Id: I8f683a4dcd7cd9a2466a4b1b417d84c025c37761 --- init/README.md | 3 ++- init/builtins.cpp | 25 +++++++++++++++++++------ rootdir/init.rc | 4 +--- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/init/README.md b/init/README.md index 5fced19b076f..11c4e1cf3770 100644 --- a/init/README.md +++ b/init/README.md @@ -674,11 +674,12 @@ provides the `aidl_lazy_test_1` interface. _options_ include "barrier=1", "noauto\_da\_alloc", "discard", ... as a comma separated string, e.g. barrier=1,noauto\_da\_alloc -`perform_apex_config` +`perform_apex_config [--bootstrap]` > Performs tasks after APEXes are mounted. For example, creates data directories for the mounted APEXes, parses config file(s) from them, and updates linker configurations. Intended to be used only once when apexd notifies the mount event by setting `apexd.status` to ready. + Use --bootstrap when invoking in the bootstrap mount namespace. `restart [--only-if-running] ` > Stops and restarts a running service, does nothing if the service is currently diff --git a/init/builtins.cpp b/init/builtins.cpp index fa5e36d52220..e40b831d1427 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -1292,10 +1292,21 @@ static Result create_apex_data_dirs() { } static Result do_perform_apex_config(const BuiltinArguments& args) { - auto create_dirs = create_apex_data_dirs(); - if (!create_dirs.ok()) { - return create_dirs.error(); + bool bootstrap = false; + if (args.size() == 2) { + if (args[1] != "--bootstrap") { + return Error() << "Unexpected argument: " << args[1]; + } + bootstrap = true; } + + if (!bootstrap) { + auto create_dirs = create_apex_data_dirs(); + if (!create_dirs.ok()) { + return create_dirs.error(); + } + } + auto parse_configs = ParseApexConfigs(/*apex_name=*/""); if (!parse_configs.ok()) { return parse_configs.error(); @@ -1306,8 +1317,10 @@ static Result do_perform_apex_config(const BuiltinArguments& args) { return update_linker_config.error(); } - // Now start delayed services - ServiceList::GetInstance().MarkServicesUpdate(); + if (!bootstrap) { + // Now start delayed services + ServiceList::GetInstance().MarkServicesUpdate(); + } return {}; } @@ -1362,7 +1375,7 @@ const BuiltinFunctionMap& GetBuiltinFunctionMap() { // mount and umount are run in the same context as mount_all for symmetry. {"mount_all", {0, kMax, {false, do_mount_all}}}, {"mount", {3, kMax, {false, do_mount}}}, - {"perform_apex_config", {0, 0, {false, do_perform_apex_config}}}, + {"perform_apex_config", {0, 1, {false, do_perform_apex_config}}}, {"umount", {1, 1, {false, do_umount}}}, {"umount_all", {0, 1, {false, do_umount_all}}}, {"update_linker_config", {0, 0, {false, do_update_linker_config}}}, diff --git a/rootdir/init.rc b/rootdir/init.rc index 8f01d932b851..0d31cdce788b 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -74,9 +74,7 @@ on early-init # become available. Note that this is executed as exec_start to ensure that # the libraries are available to the processes started after this statement. exec_start apexd-bootstrap - - # Generate linker config based on apex mounted in bootstrap namespace - update_linker_config + perform_apex_config --bootstrap # These must already exist by the time boringssl_self_test32 / boringssl_self_test64 run. mkdir /dev/boringssl 0755 root root From 6fe9367f7bb636d63a856d29944b4f229c3d01e2 Mon Sep 17 00:00:00 2001 From: Po-yao Chang Date: Thu, 10 Aug 2023 17:03:34 +0800 Subject: [PATCH 0307/1487] Run boringssl tests according to ro.zygote If ro.zygote is zygote64, don't bother running 32-bit test. Otherwise abilist{32,64} decides what tests to run. Bug: 291874369 Test: make gsi_arm64-user; Check /system/etc/init/hw Change-Id: Id10b2242606d6400acc29c3174f713581d6cce2e --- rootdir/Android.bp | 18 ++++++++++++++++++ rootdir/init.boringssl.zygote64.rc | 4 ++++ rootdir/init.boringssl.zygote64_32.rc | 8 ++++++++ rootdir/init.rc | 9 +-------- 4 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 rootdir/init.boringssl.zygote64.rc create mode 100644 rootdir/init.boringssl.zygote64_32.rc diff --git a/rootdir/Android.bp b/rootdir/Android.bp index e98733ada721..c8a3cd61cf28 100644 --- a/rootdir/Android.bp +++ b/rootdir/Android.bp @@ -16,6 +16,22 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } +prebuilt_etc { + name: "init.boringssl.zygote64_32.rc", + src: "init.boringssl.zygote64_32.rc", + sub_dir: "init/hw", + symlinks: [ + "init.boringssl.zygote32.rc", + "init.boringssl.no_zygote.rc", + ], +} + +prebuilt_etc { + name: "init.boringssl.zygote64.rc", + src: "init.boringssl.zygote64.rc", + sub_dir: "init/hw", +} + prebuilt_etc { name: "init.rc", src: "init.rc", @@ -23,6 +39,8 @@ prebuilt_etc { required: [ "fsverity_init", "platform-bootclasspath", + "init.boringssl.zygote64.rc", + "init.boringssl.zygote64_32.rc", ], } diff --git a/rootdir/init.boringssl.zygote64.rc b/rootdir/init.boringssl.zygote64.rc new file mode 100644 index 000000000000..3f49fea8b01c --- /dev/null +++ b/rootdir/init.boringssl.zygote64.rc @@ -0,0 +1,4 @@ +on init && property:ro.product.cpu.abilist64=* + exec_start boringssl_self_test64 +on property:apexd.status=ready && property:ro.product.cpu.abilist64=* + exec_start boringssl_self_test_apex64 diff --git a/rootdir/init.boringssl.zygote64_32.rc b/rootdir/init.boringssl.zygote64_32.rc new file mode 100644 index 000000000000..c0be42dbb098 --- /dev/null +++ b/rootdir/init.boringssl.zygote64_32.rc @@ -0,0 +1,8 @@ +on init && property:ro.product.cpu.abilist32=* + exec_start boringssl_self_test32 +on init && property:ro.product.cpu.abilist64=* + exec_start boringssl_self_test64 +on property:apexd.status=ready && property:ro.product.cpu.abilist32=* + exec_start boringssl_self_test_apex32 +on property:apexd.status=ready && property:ro.product.cpu.abilist64=* + exec_start boringssl_self_test_apex64 diff --git a/rootdir/init.rc b/rootdir/init.rc index 8f01d932b851..56bcedfbe530 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -461,14 +461,7 @@ on init start vndservicemanager # Run boringssl self test for each ABI. Any failures trigger reboot to firmware. -on init && property:ro.product.cpu.abilist32=* - exec_start boringssl_self_test32 -on init && property:ro.product.cpu.abilist64=* - exec_start boringssl_self_test64 -on property:apexd.status=ready && property:ro.product.cpu.abilist32=* - exec_start boringssl_self_test_apex32 -on property:apexd.status=ready && property:ro.product.cpu.abilist64=* - exec_start boringssl_self_test_apex64 +import /system/etc/init/hw/init.boringssl.${ro.zygote}.rc service boringssl_self_test32 /system/bin/boringssl_self_test32 reboot_on_failure reboot,boringssl-self-check-failed From d3550e33148c48c4accdccb7f822701e5bea025d Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Thu, 10 Aug 2023 06:28:58 +0000 Subject: [PATCH 0308/1487] Remove cutils threads.h header completely. Bug: 289414897 Test: it builds Change-Id: Ifcde5849923f19f1c898a6a95811eea55be0d276 --- libcutils/include/cutils/threads.h | 15 --------------- libcutils/include_outside_system/cutils/threads.h | 1 - 2 files changed, 16 deletions(-) delete mode 100644 libcutils/include/cutils/threads.h delete mode 120000 libcutils/include_outside_system/cutils/threads.h diff --git a/libcutils/include/cutils/threads.h b/libcutils/include/cutils/threads.h deleted file mode 100644 index 9bc3429bec29..000000000000 --- a/libcutils/include/cutils/threads.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ diff --git a/libcutils/include_outside_system/cutils/threads.h b/libcutils/include_outside_system/cutils/threads.h deleted file mode 120000 index 99330ffadfe3..000000000000 --- a/libcutils/include_outside_system/cutils/threads.h +++ /dev/null @@ -1 +0,0 @@ -../../include/cutils/threads.h \ No newline at end of file From 3983f9aa6ec3961a7581f95f817f189a8ca5c492 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Wed, 9 Aug 2023 23:08:21 -0700 Subject: [PATCH 0309/1487] libsnapshot: Check for valid snapshots based on current slot We may have snapshot files in /metadata/ota/snapshot/ which ends with .tmp such as system_a.tmp - This happens if the device reboots just before `rename` in `WriteStringToFileAtomic`. This can lead to spurious merge failures. Log the error and skip these snapshot files. It is ok to skip as we will still have original snapshot status files since we are already in the merge path. Additionally, try to remove these files when snapshot is deleted. Bug: 292198189 Test: OTA Change-Id: I5db3dbd5a919b263ae577185de3e7f79a5e9b89a Signed-off-by: Akilesh Kailash --- fs_mgr/libsnapshot/snapshot.cpp | 18 +++++++++++++----- fs_mgr/libsnapshot/snapshot_test.cpp | 23 ++++++++++++++++++++++- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index 86ff5f710da7..51389a0dbf27 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -729,6 +729,14 @@ bool SnapshotManager::DeleteSnapshot(LockedFile* lock, const std::string& name) LOG(ERROR) << "Failed to remove status file " << file_path << ": " << error; return false; } + + // This path may never exist. If it is present, then it's a stale + // snapshot status file. Just remove the file and log the message. + const std::string tmp_path = file_path + ".tmp"; + if (!android::base::RemoveFileIfExists(tmp_path, &error)) { + LOG(ERROR) << "Failed to remove stale snapshot file " << tmp_path; + } + return true; } @@ -754,10 +762,10 @@ bool SnapshotManager::InitiateMerge() { return false; } - auto other_suffix = device_->GetOtherSlotSuffix(); + auto current_slot_suffix = device_->GetSlotSuffix(); for (const auto& snapshot : snapshots) { - if (android::base::EndsWith(snapshot, other_suffix)) { + if (!android::base::EndsWith(snapshot, current_slot_suffix)) { // Allow the merge to continue, but log this unexpected case. LOG(ERROR) << "Unexpected snapshot found during merge: " << snapshot; continue; @@ -1123,7 +1131,7 @@ auto SnapshotManager::CheckMergeState(LockedFile* lock, const std::functionGetOtherSlotSuffix(); + auto current_slot_suffix = device_->GetSlotSuffix(); bool cancelled = false; bool merging = false; @@ -1131,9 +1139,9 @@ auto SnapshotManager::CheckMergeState(LockedFile* lock, const std::functionInitiateMerge()); + // Create stale files in snapshot directory. Merge should skip these files + // as the suffix doesn't match the current slot. + auto tmp_path = test_device->GetMetadataDir() + "/snapshots/test_partition_b.tmp"; + auto other_slot = test_device->GetMetadataDir() + "/snapshots/test_partition_a"; + + unique_fd fd(open(tmp_path.c_str(), O_RDWR | O_CLOEXEC | O_CREAT, 0644)); + ASSERT_GE(fd, 0); + + fd.reset(open(other_slot.c_str(), O_RDWR | O_CLOEXEC | O_CREAT, 0644)); + ASSERT_GE(fd, 0); + // The device should have been switched to a snapshot-merge target. DeviceMapper::TargetInfo target; ASSERT_TRUE(sm->IsSnapshotDevice("test_partition_b", &target)); @@ -700,13 +711,23 @@ TEST_F(SnapshotTest, Merge) { ASSERT_EQ(sm->ProcessUpdateState(), UpdateState::MergeCompleted); ASSERT_EQ(sm->GetUpdateState(), UpdateState::None); + // Make sure that snapshot states are cleared and all stale files + // are deleted + { + ASSERT_TRUE(AcquireLock()); + auto local_lock = std::move(lock_); + std::vector snapshots; + ASSERT_TRUE(sm->ListSnapshots(local_lock.get(), &snapshots)); + ASSERT_TRUE(snapshots.empty()); + } + // The device should no longer be a snapshot or snapshot-merge. ASSERT_FALSE(sm->IsSnapshotDevice("test_partition_b")); // Test that we can read back the string we wrote to the snapshot. Note // that the base device is gone now. |snap_device| contains the correct // partition. - unique_fd fd(open("/dev/block/mapper/test_partition_b", O_RDONLY | O_CLOEXEC)); + fd.reset(open("/dev/block/mapper/test_partition_b", O_RDONLY | O_CLOEXEC)); ASSERT_GE(fd, 0); std::string buffer(test_string.size(), '\0'); From 55ef3d6104032dcaa773e486405cb9f8978fd5ce Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Thu, 10 Aug 2023 18:27:22 +0900 Subject: [PATCH 0310/1487] Skip bootstrap APEX RC files for the second round Reading .rc files from bootstrap APEXes causes "double loading". This works for services because init just ignores duplicates. But it emits error logs, which can mislead even though there's no actual errors. Besides, for actions, duplicates can cause a problem when commands are not idempotent. So, when loading RC files from APEXes for the second time, we'd better skip those bootstrap APEXes. Bug: 290148081 Test: VendorApexHostTestCases Change-Id: Ia630dbd14046064b5e5c612c01ebacf57091c8d4 --- init/apex_init_util.cpp | 91 ++++++++++++++++++++++++++++++++--------- init/apex_init_util.h | 8 ++-- init/builtins.cpp | 6 +-- init/init.cpp | 2 +- 4 files changed, 81 insertions(+), 26 deletions(-) diff --git a/init/apex_init_util.cpp b/init/apex_init_util.cpp index c818f8fe9e3a..d88da390eff6 100644 --- a/init/apex_init_util.cpp +++ b/init/apex_init_util.cpp @@ -16,13 +16,15 @@ #include "apex_init_util.h" +#include #include +#include #include #include -#include #include +#include #include #include "action_manager.h" @@ -34,10 +36,13 @@ namespace android { namespace init { -static Result> CollectApexConfigs(const std::string& apex_name) { +static Result> CollectRcScriptsFromApex( + const std::string& apex_name, const std::set& skip_apexes) { glob_t glob_result; - std::string glob_pattern = apex_name.empty() ? - "/apex/*/etc/*rc" : "/apex/" + apex_name + "/etc/*rc"; + // Pattern uses "*rc" instead of ".rc" because APEXes can have versioned RC files + // like foo.34rc. + std::string glob_pattern = + apex_name.empty() ? "/apex/*/etc/*rc" : "/apex/" + apex_name + "/etc/*rc"; const int ret = glob(glob_pattern.c_str(), GLOB_MARK, nullptr, &glob_result); if (ret != 0 && ret != GLOB_NOMATCH) { @@ -47,15 +52,28 @@ static Result> CollectApexConfigs(const std::string& ap std::vector configs; for (size_t i = 0; i < glob_result.gl_pathc; i++) { std::string path = glob_result.gl_pathv[i]; - // Filter-out /apex/@ paths. The paths are bind-mounted to + + // Filter out directories + if (path.back() == '/') { + continue; + } + + // Get apex name from path. + std::vector paths = android::base::Split(path, "/"); + if (paths.size() < 3) { + continue; + } + const std::string& apex_name = paths[2]; + + // Filter out /apex/@ paths. The paths are bind-mounted to // /apex/ paths, so unless we filter them out, we will parse the // same file twice. - std::vector paths = android::base::Split(path, "/"); - if (paths.size() >= 3 && paths[2].find('@') != std::string::npos) { + if (apex_name.find('@') != std::string::npos) { continue; } - // Filter directories - if (path.back() == '/') { + + // Filter out skip_set apexes + if (skip_apexes.count(apex_name) > 0) { continue; } configs.push_back(path); @@ -64,11 +82,41 @@ static Result> CollectApexConfigs(const std::string& ap return configs; } -static Result ParseConfigs(const std::vector& configs) { +static std::set GetApexListFrom(const std::string& apex_dir) { + std::set apex_list; + auto dirp = std::unique_ptr(opendir(apex_dir.c_str()), closedir); + if (!dirp) { + return apex_list; + } + struct dirent* entry; + while ((entry = readdir(dirp.get())) != nullptr) { + if (entry->d_type != DT_DIR) continue; + + const char* name = entry->d_name; + if (name[0] == '.') continue; + if (strchr(name, '@') != nullptr) continue; + if (strcmp(name, "sharedlibs") == 0) continue; + apex_list.insert(name); + } + return apex_list; +} + +static Result ParseRcScripts(const std::vector& files) { + if (files.empty()) { + return {}; + } + // APEXes can have versioned RC files. These should be filtered based on + // SDK version. + auto filtered = FilterVersionedConfigs( + files, android::base::GetIntProperty("ro.build.version.sdk", INT_MAX)); + if (filtered.empty()) { + return {}; + } + Parser parser = CreateApexConfigParser(ActionManager::GetInstance(), ServiceList::GetInstance()); std::vector errors; - for (const auto& c : configs) { + for (const auto& c : filtered) { auto result = parser.ParseConfigFile(c); // We should handle other config files even when there's an error. if (!result.ok()) { @@ -81,16 +129,21 @@ static Result ParseConfigs(const std::vector& configs) { return {}; } -Result ParseApexConfigs(const std::string& apex_name) { - auto configs = OR_RETURN(CollectApexConfigs(apex_name)); +Result ParseRcScriptsFromApex(const std::string& apex_name) { + auto configs = OR_RETURN(CollectRcScriptsFromApex(apex_name, /*skip_apexes=*/{})); + return ParseRcScripts(configs); +} - if (configs.empty()) { - return {}; +Result ParseRcScriptsFromAllApexes(bool bootstrap) { + std::set skip_apexes; + if (!bootstrap) { + // In case we already loaded config files from bootstrap APEXes, we need to avoid loading + // them again. We can get the list of bootstrap APEXes by scanning /bootstrap-apex and + // skip them in CollectRcScriptsFromApex. + skip_apexes = GetApexListFrom("/bootstrap-apex"); } - - auto filtered_configs = FilterVersionedConfigs(configs, - android::base::GetIntProperty("ro.build.version.sdk", INT_MAX)); - return ParseConfigs(filtered_configs); + auto configs = OR_RETURN(CollectRcScriptsFromApex(/*apex_name=*/"", skip_apexes)); + return ParseRcScripts(configs); } } // namespace init diff --git a/init/apex_init_util.h b/init/apex_init_util.h index 43f8ad5eb64d..e55b3c0c9976 100644 --- a/init/apex_init_util.h +++ b/init/apex_init_util.h @@ -24,9 +24,11 @@ namespace android { namespace init { -// Parse all config files for a given apex. -// If apex name is empty(""), config files for all apexes will be parsed. -Result ParseApexConfigs(const std::string& apex_name); +// Parse all RC scripts for a given apex. +Result ParseRcScriptsFromApex(const std::string& apex_name); + +// Parse all RC scripts for all apexes under /apex. +Result ParseRcScriptsFromAllApexes(bool bootstrap); } // namespace init } // namespace android diff --git a/init/builtins.cpp b/init/builtins.cpp index e40b831d1427..2ced66d113f2 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -1307,9 +1307,9 @@ static Result do_perform_apex_config(const BuiltinArguments& args) { } } - auto parse_configs = ParseApexConfigs(/*apex_name=*/""); - if (!parse_configs.ok()) { - return parse_configs.error(); + auto parse_result = ParseRcScriptsFromAllApexes(bootstrap); + if (!parse_result.ok()) { + return parse_result.error(); } auto update_linker_config = do_update_linker_config(args); diff --git a/init/init.cpp b/init/init.cpp index 4bb8eecb981a..40e21696fbdf 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -487,7 +487,7 @@ static Result UpdateApexLinkerConfig(const std::string& apex_name) { } static Result DoLoadApex(const std::string& apex_name) { - if (auto result = ParseApexConfigs(apex_name); !result.ok()) { + if (auto result = ParseRcScriptsFromApex(apex_name); !result.ok()) { return result.error(); } From d8a270698d3f12c659b9f8e3ec7fec631bf2058a Mon Sep 17 00:00:00 2001 From: Wei Li Date: Thu, 10 Aug 2023 18:18:36 -0700 Subject: [PATCH 0311/1487] Track root directory symlinks created by LOCAL_POST_INSTALL_CMD in ALL_ROOTDIR_SYMLINKS and add them to ALL_DEFAULT_INSTALLED_MODULES, so they can be included in product SBOMs properly. Bug: 272358980 Test: CIs and build/soong/tests/sbom_test.sh Change-Id: I73dfb34156d681786c013912e59a0d0c0c48ecc7 --- rootdir/Android.mk | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 3362872c070d..ebed44ea15a2 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -98,20 +98,31 @@ LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \ ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \ ln -sfn /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \ ln -sf /storage/self/primary $(TARGET_ROOT_OUT)/sdcard + +ALL_ROOTDIR_SYMLINKS := \ + $(TARGET_ROOT_OUT)/bin \ + $(TARGET_ROOT_OUT)/etc \ + $(TARGET_ROOT_OUT)/bugreports \ + $(TARGET_ROOT_OUT)/d \ + $(TARGET_ROOT_OUT)/sdcard + ifdef BOARD_USES_VENDORIMAGE LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/vendor else LOCAL_POST_INSTALL_CMD += ; ln -sf /system/vendor $(TARGET_ROOT_OUT)/vendor + ALL_ROOTDIR_SYMLINKS += $(TARGET_ROOT_OUT)/vendor endif ifdef BOARD_USES_PRODUCTIMAGE LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/product else LOCAL_POST_INSTALL_CMD += ; ln -sf /system/product $(TARGET_ROOT_OUT)/product + ALL_ROOTDIR_SYMLINKS += $(TARGET_ROOT_OUT)/product endif ifdef BOARD_USES_SYSTEM_EXTIMAGE LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/system_ext else LOCAL_POST_INSTALL_CMD += ; ln -sf /system/system_ext $(TARGET_ROOT_OUT)/system_ext + ALL_ROOTDIR_SYMLINKS += $(TARGET_ROOT_OUT)/system_ext endif ifdef BOARD_USES_METADATA_PARTITION LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/metadata @@ -134,6 +145,18 @@ LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/overlay $(TARGET_ROOT_OUT)/odm/ov LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/priv-app $(TARGET_ROOT_OUT)/odm/priv-app LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/usr $(TARGET_ROOT_OUT)/odm/usr +ALL_ROOTDIR_SYMLINKS += \ + $(TARGET_ROOT_OUT)/odm/app \ + $(TARGET_ROOT_OUT)/odm/bin \ + $(TARGET_ROOT_OUT)/odm/etc \ + $(TARGET_ROOT_OUT)/odm/firmware \ + $(TARGET_ROOT_OUT)/odm/framework \ + $(TARGET_ROOT_OUT)/odm/lib \ + $(TARGET_ROOT_OUT)/odm/lib64 \ + $(TARGET_ROOT_OUT)/odm/overlay \ + $(TARGET_ROOT_OUT)/odm/priv-app \ + $(TARGET_ROOT_OUT)/odm/usr + # For /vendor_dlkm partition. LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/vendor_dlkm @@ -144,6 +167,7 @@ LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/vendor_dlkm # Note that /vendor_dlkm/lib is omitted because vendor DLKMs should be accessed # via /vendor/lib/modules directly. LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/vendor_dlkm/etc $(TARGET_ROOT_OUT)/vendor_dlkm/etc +ALL_ROOTDIR_SYMLINKS += $(TARGET_ROOT_OUT)/vendor_dlkm/etc # For /odm_dlkm partition. LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/odm_dlkm @@ -154,6 +178,7 @@ LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/odm_dlkm # Note that /odm_dlkm/lib is omitted because odm DLKMs should be accessed # via /odm/lib/modules directly. LOCAL_POST_INSTALL_CMD += ; ln -sf /odm/odm_dlkm/etc $(TARGET_ROOT_OUT)/odm_dlkm/etc +ALL_ROOTDIR_SYMLINKS += $(TARGET_ROOT_OUT)/odm_dlkm/etc # For /system_dlkm partition LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/system_dlkm @@ -162,6 +187,7 @@ ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache else LOCAL_POST_INSTALL_CMD += ; ln -sf /data/cache $(TARGET_ROOT_OUT)/cache + ALL_ROOTDIR_SYMLINKS += $(TARGET_ROOT_OUT)/cache endif ifdef BOARD_ROOT_EXTRA_SYMLINKS # BOARD_ROOT_EXTRA_SYMLINKS is a list of :. @@ -169,14 +195,19 @@ ifdef BOARD_ROOT_EXTRA_SYMLINKS $(eval p := $(subst :,$(space),$(s)))\ ; mkdir -p $(dir $(TARGET_ROOT_OUT)/$(word 2,$(p))) \ ; ln -sf $(word 1,$(p)) $(TARGET_ROOT_OUT)/$(word 2,$(p))) + ALL_ROOTDIR_SYMLINKS += $(foreach s,$(BOARD_ROOT_EXTRA_SYMLINKS),$(TARGET_ROOT_OUT)/$(call word-colon,2,$s)) endif # The init symlink must be a post install command of a file that is to TARGET_ROOT_OUT. # Since init.environ.rc is required for init and satisfies that requirement, we hijack it to create the symlink. LOCAL_POST_INSTALL_CMD += ; ln -sf /system/bin/init $(TARGET_ROOT_OUT)/init +ALL_ROOTDIR_SYMLINKS += $(TARGET_ROOT_OUT)/init + +ALL_DEFAULT_INSTALLED_MODULES += $(ALL_ROOTDIR_SYMLINKS) include $(BUILD_SYSTEM)/base_rules.mk +$(ALL_ROOTDIR_SYMLINKS): $(LOCAL_BUILT_MODULE) $(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in @echo "Generate: $< -> $@" @mkdir -p $(dir $@) From 2982f09d57fdf1ad3fb7aa10c4aa62243b50fd0d Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Fri, 11 Aug 2023 14:14:37 +0900 Subject: [PATCH 0312/1487] Dedup apex-scanning create_apex_data_dirs() now uses GetApexListFrom(dir) in apex_init_util.cpp. This is essentially a refactoring, but there are a few behavioral changes, which I think make more sense. - Emits no error when opendir(/apex) fails. - Emits errors when mkdir fails for each apex. - Does not abort `perform_apex_config` even though create_apex_data_dirs fails. Bug: 293546778 Test: check /data/misc/apexdata/ after boot Change-Id: I9d1a9710a6a626eec087c8c0fb1768667ffb036e --- init/apex_init_util.cpp | 2 +- init/apex_init_util.h | 4 ++++ init/builtins.cpp | 30 ++++++++---------------------- 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/init/apex_init_util.cpp b/init/apex_init_util.cpp index d88da390eff6..6d17f36e2201 100644 --- a/init/apex_init_util.cpp +++ b/init/apex_init_util.cpp @@ -82,7 +82,7 @@ static Result> CollectRcScriptsFromApex( return configs; } -static std::set GetApexListFrom(const std::string& apex_dir) { +std::set GetApexListFrom(const std::string& apex_dir) { std::set apex_list; auto dirp = std::unique_ptr(opendir(apex_dir.c_str()), closedir); if (!dirp) { diff --git a/init/apex_init_util.h b/init/apex_init_util.h index e55b3c0c9976..75dfee1ae4a4 100644 --- a/init/apex_init_util.h +++ b/init/apex_init_util.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include @@ -24,6 +25,9 @@ namespace android { namespace init { +// Scans apex_dir (/apex) to get the list of active APEXes. +std::set GetApexListFrom(const std::string& apex_dir); + // Parse all RC scripts for a given apex. Result ParseRcScriptsFromApex(const std::string& apex_name); diff --git a/init/builtins.cpp b/init/builtins.cpp index 2ced66d113f2..a5b762cbb834 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -1269,26 +1269,15 @@ static Result do_update_linker_config(const BuiltinArguments&) { /* * Creates a directory under /data/misc/apexdata/ for each APEX. */ -static Result create_apex_data_dirs() { - auto dirp = std::unique_ptr(opendir("/apex"), closedir); - if (!dirp) { - return ErrnoError() << "Unable to open apex directory"; - } - struct dirent* entry; - while ((entry = readdir(dirp.get())) != nullptr) { - if (entry->d_type != DT_DIR) continue; - - const char* name = entry->d_name; - // skip any starting with "." - if (name[0] == '.') continue; - - if (strchr(name, '@') != nullptr) continue; - - auto path = "/data/misc/apexdata/" + std::string(name); +static void create_apex_data_dirs() { + for (const auto& name : GetApexListFrom("/apex")) { + auto path = "/data/misc/apexdata/" + name; auto options = MkdirOptions{path, 0771, AID_ROOT, AID_SYSTEM, FscryptAction::kNone, "ref"}; - make_dir_with_options(options); + auto result = make_dir_with_options(options); + if (!result.ok()) { + LOG(ERROR) << result.error(); + } } - return {}; } static Result do_perform_apex_config(const BuiltinArguments& args) { @@ -1301,10 +1290,7 @@ static Result do_perform_apex_config(const BuiltinArguments& args) { } if (!bootstrap) { - auto create_dirs = create_apex_data_dirs(); - if (!create_dirs.ok()) { - return create_dirs.error(); - } + create_apex_data_dirs(); } auto parse_result = ParseRcScriptsFromAllApexes(bootstrap); From 90af4157c57de30ea0c3ab5ce2ab79c2ba36ef3b Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 11 Aug 2023 02:12:16 +0000 Subject: [PATCH 0313/1487] Add String16::c_str and start using it. This is for parity with String8::c_str and in general the first step in transition from String8|16.string() - to make it more similar to std::string. Bug: 295394788 Test: mma -j Change-Id: I6c1411bef07c761fb2fb3fb38c27801ac4cffc57 --- libutils/String16.cpp | 13 +++++-------- libutils/String8.cpp | 7 ++----- libutils/include/utils/String16.h | 8 +++++++- libutils/include/utils/String8.h | 6 +++--- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/libutils/String16.cpp b/libutils/String16.cpp index 68642d84f7ea..38d483e9495e 100644 --- a/libutils/String16.cpp +++ b/libutils/String16.cpp @@ -26,7 +26,7 @@ namespace android { static const StaticString16 emptyString(u""); static inline char16_t* getEmptyString() { - return const_cast(emptyString.string()); + return const_cast(emptyString.c_str()); } // --------------------------------------------------------------------------- @@ -112,10 +112,7 @@ String16::String16(const char16_t* o) : mString(allocFromUTF16(o, strlen16(o))) String16::String16(const char16_t* o, size_t len) : mString(allocFromUTF16(o, len)) {} -String16::String16(const String8& o) - : mString(allocFromUTF8(o.string(), o.size())) -{ -} +String16::String16(const String8& o) : mString(allocFromUTF8(o.c_str(), o.size())) {} String16::String16(const char* o) : mString(allocFromUTF8(o, strlen(o))) @@ -173,7 +170,7 @@ status_t String16::setTo(const String16& other, size_t len, size_t begin) LOG_ALWAYS_FATAL("Not implemented"); } - return setTo(other.string()+begin, len); + return setTo(other.c_str() + begin, len); } status_t String16::setTo(const char16_t* other) @@ -200,7 +197,7 @@ status_t String16::setTo(const char16_t* other, size_t len) } status_t String16::append(const String16& other) { - return append(other.string(), other.size()); + return append(other.c_str(), other.size()); } status_t String16::append(const char16_t* chrs, size_t otherLen) { @@ -286,7 +283,7 @@ bool String16::startsWith(const String16& prefix) const { const size_t ps = prefix.size(); if (ps > size()) return false; - return strzcmp16(mString, ps, prefix.string(), ps) == 0; + return strzcmp16(mString, ps, prefix.c_str(), ps) == 0; } bool String16::startsWith(const char16_t* prefix) const diff --git a/libutils/String8.cpp b/libutils/String8.cpp index 8d312b57ce2b..79b7edfe9a12 100644 --- a/libutils/String8.cpp +++ b/libutils/String8.cpp @@ -150,10 +150,7 @@ String8::String8(const char* o, size_t len) } } -String8::String8(const String16& o) - : mString(allocFromUTF16(o.string(), o.size())) -{ -} +String8::String8(const String16& o) : mString(allocFromUTF16(o.c_str(), o.size())) {} String8::String8(const char16_t* o) : mString(allocFromUTF16(o, strlen16(o))) @@ -267,7 +264,7 @@ status_t String8::append(const String8& other) return OK; } - return real_append(other.string(), otherLen); + return real_append(other.c_str(), otherLen); } status_t String8::append(const char* other) diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h index 3ef56a3cfa8f..d719aeaaa28e 100644 --- a/libutils/include/utils/String16.h +++ b/libutils/include/utils/String16.h @@ -53,6 +53,7 @@ class String16 ~String16(); + inline const char16_t* c_str() const; inline const char16_t* string() const; private: @@ -234,6 +235,11 @@ inline int strictly_order_type(const String16& lhs, const String16& rhs) return compare_type(lhs, rhs) < 0; } +inline const char16_t* String16::c_str() const +{ + return mString; +} + inline const char16_t* String16::string() const { return mString; @@ -241,7 +247,7 @@ inline const char16_t* String16::string() const inline std::string String16::std_string(const String16& str) { - return std::string(String8(str).string()); + return std::string(String8(str).c_str()); } inline String16& String16::operator=(const String16& other) diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h index 8b2dcf9a0a3a..e58f1a5d1992 100644 --- a/libutils/include/utils/String8.h +++ b/libutils/include/utils/String8.h @@ -193,14 +193,14 @@ class String8 * replaces whatever was there before. */ String8& appendPath(const char* leaf); - String8& appendPath(const String8& leaf) { return appendPath(leaf.string()); } + String8& appendPath(const String8& leaf) { return appendPath(leaf.c_str()); } /* * Like appendPath(), but does not affect this string. Returns a new one instead. */ String8 appendPathCopy(const char* leaf) const { String8 p(*this); p.appendPath(leaf); return p; } - String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.string()); } + String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.c_str()); } /* * Converts all separators in this string to /, the default path separator. @@ -255,7 +255,7 @@ inline const char* String8::string() const inline std::string String8::std_string(const String8& str) { - return std::string(str.string()); + return std::string(str.c_str()); } inline size_t String8::size() const From 18b746188c73a83ad57b99558914ba9421e8a20a Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Thu, 10 Aug 2023 23:29:50 +0000 Subject: [PATCH 0314/1487] Migrate String8/16 from .string() to c_str() This will align usage with std::string. Bug: 295394788 Test: make checkbuild Change-Id: Ic5c215b011197950dcbcb0339f44cc68fefc65a1 --- fs_mgr/libfiemap/binder.cpp | 26 +++++++++++++------------- healthd/BatteryMonitor.cpp | 31 ++++++++++++------------------- healthd/BatteryMonitor_v1.cpp | 31 ++++++++++++------------------- libutils/ProcessCallStack.cpp | 5 ++--- libutils/RefBase.cpp | 2 +- libutils/String16_fuzz.cpp | 6 +++--- libutils/String8_test.cpp | 20 ++++++++++---------- libutils/Tokenizer.cpp | 10 +++++----- 8 files changed, 58 insertions(+), 73 deletions(-) diff --git a/fs_mgr/libfiemap/binder.cpp b/fs_mgr/libfiemap/binder.cpp index 41e534af4a8d..439aac9695aa 100644 --- a/fs_mgr/libfiemap/binder.cpp +++ b/fs_mgr/libfiemap/binder.cpp @@ -77,7 +77,7 @@ class ImageManagerBinder final : public IImageManager { static FiemapStatus ToFiemapStatus(const char* func, const binder::Status& status) { if (!status.isOk()) { - LOG(ERROR) << func << " binder returned: " << status.toString8().string(); + LOG(ERROR) << func << " binder returned: " << status.toString8().c_str(); if (status.serviceSpecificErrorCode() != 0) { return FiemapStatus::FromErrorCode(status.serviceSpecificErrorCode()); } else { @@ -106,7 +106,7 @@ bool ImageManagerBinder::DeleteBackingImage(const std::string& name) { auto status = manager_->deleteBackingImage(name); if (!status.isOk()) { LOG(ERROR) << __PRETTY_FUNCTION__ - << " binder returned: " << status.exceptionMessage().string(); + << " binder returned: " << status.exceptionMessage().c_str(); return false; } return true; @@ -122,7 +122,7 @@ bool ImageManagerBinder::MapImageDevice(const std::string& name, auto status = manager_->mapImageDevice(name, timeout_ms_count, &map); if (!status.isOk()) { LOG(ERROR) << __PRETTY_FUNCTION__ - << " binder returned: " << status.exceptionMessage().string(); + << " binder returned: " << status.exceptionMessage().c_str(); return false; } *path = map.path; @@ -133,7 +133,7 @@ bool ImageManagerBinder::UnmapImageDevice(const std::string& name) { auto status = manager_->unmapImageDevice(name); if (!status.isOk()) { LOG(ERROR) << __PRETTY_FUNCTION__ - << " binder returned: " << status.exceptionMessage().string(); + << " binder returned: " << status.exceptionMessage().c_str(); return false; } return true; @@ -144,7 +144,7 @@ bool ImageManagerBinder::BackingImageExists(const std::string& name) { auto status = manager_->backingImageExists(name, &retval); if (!status.isOk()) { LOG(ERROR) << __PRETTY_FUNCTION__ - << " binder returned: " << status.exceptionMessage().string(); + << " binder returned: " << status.exceptionMessage().c_str(); return false; } return retval; @@ -155,7 +155,7 @@ bool ImageManagerBinder::IsImageMapped(const std::string& name) { auto status = manager_->isImageMapped(name, &retval); if (!status.isOk()) { LOG(ERROR) << __PRETTY_FUNCTION__ - << " binder returned: " << status.exceptionMessage().string(); + << " binder returned: " << status.exceptionMessage().c_str(); return false; } return retval; @@ -175,7 +175,7 @@ std::vector ImageManagerBinder::GetAllBackingImages() { auto status = manager_->getAllBackingImages(&retval); if (!status.isOk()) { LOG(ERROR) << __PRETTY_FUNCTION__ - << " binder returned: " << status.exceptionMessage().string(); + << " binder returned: " << status.exceptionMessage().c_str(); } return retval; } @@ -189,7 +189,7 @@ bool ImageManagerBinder::RemoveAllImages() { auto status = manager_->removeAllImages(); if (!status.isOk()) { LOG(ERROR) << __PRETTY_FUNCTION__ - << " binder returned: " << status.exceptionMessage().string(); + << " binder returned: " << status.exceptionMessage().c_str(); return false; } return true; @@ -199,7 +199,7 @@ bool ImageManagerBinder::DisableImage(const std::string& name) { auto status = manager_->disableImage(name); if (!status.isOk()) { LOG(ERROR) << __PRETTY_FUNCTION__ - << " binder returned: " << status.exceptionMessage().string(); + << " binder returned: " << status.exceptionMessage().c_str(); return false; } return true; @@ -209,7 +209,7 @@ bool ImageManagerBinder::RemoveDisabledImages() { auto status = manager_->removeDisabledImages(); if (!status.isOk()) { LOG(ERROR) << __PRETTY_FUNCTION__ - << " binder returned: " << status.exceptionMessage().string(); + << " binder returned: " << status.exceptionMessage().c_str(); return false; } return true; @@ -219,7 +219,7 @@ bool ImageManagerBinder::GetMappedImageDevice(const std::string& name, std::stri auto status = manager_->getMappedImageDevice(name, device); if (!status.isOk()) { LOG(ERROR) << __PRETTY_FUNCTION__ - << " binder returned: " << status.exceptionMessage().string(); + << " binder returned: " << status.exceptionMessage().c_str(); return false; } return !device->empty(); @@ -230,7 +230,7 @@ bool ImageManagerBinder::IsImageDisabled(const std::string& name) { auto status = manager_->isImageDisabled(name, &retval); if (!status.isOk()) { LOG(ERROR) << __PRETTY_FUNCTION__ - << " binder returned: " << status.exceptionMessage().string(); + << " binder returned: " << status.exceptionMessage().c_str(); return false; } return retval; @@ -249,7 +249,7 @@ std::unique_ptr IImageManager::Open(const std::string& dir, auto status = service->openImageService(dir, &manager); if (!status.isOk() || !manager) { - LOG(ERROR) << "Could not acquire IImageManager: " << status.exceptionMessage().string(); + LOG(ERROR) << "Could not acquire IImageManager: " << status.exceptionMessage().c_str(); return nullptr; } return std::make_unique(std::move(service), std::move(manager)); diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp index bd7955a7f8b4..15c30be412f8 100644 --- a/healthd/BatteryMonitor.cpp +++ b/healthd/BatteryMonitor.cpp @@ -444,12 +444,10 @@ void BatteryMonitor::updateValues(void) { for (size_t i = 0; i < mChargerNames.size(); i++) { String8 path; - path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, - mChargerNames[i].string()); + path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, mChargerNames[i].c_str()); if (getIntField(path)) { path.clear(); - path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, - mChargerNames[i].string()); + path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, mChargerNames[i].c_str()); switch(readPowerSupplyType(path)) { case ANDROID_POWER_SUPPLY_TYPE_AC: mHealthInfo->chargerAcOnline = true; @@ -466,26 +464,24 @@ void BatteryMonitor::updateValues(void) { default: path.clear(); path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH, - mChargerNames[i].string()); - if (access(path.string(), R_OK) == 0) + mChargerNames[i].c_str()); + if (access(path.c_str(), R_OK) == 0) mHealthInfo->chargerDockOnline = true; else KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n", - mChargerNames[i].string()); + mChargerNames[i].c_str()); } path.clear(); path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH, - mChargerNames[i].string()); - int ChargingCurrent = - (access(path.string(), R_OK) == 0) ? getIntField(path) : 0; + mChargerNames[i].c_str()); + int ChargingCurrent = (access(path.c_str(), R_OK) == 0) ? getIntField(path) : 0; path.clear(); path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH, - mChargerNames[i].string()); + mChargerNames[i].c_str()); int ChargingVoltage = - (access(path.string(), R_OK) == 0) ? getIntField(path) : - DEFAULT_VBUS_VOLTAGE; + (access(path.c_str(), R_OK) == 0) ? getIntField(path) : DEFAULT_VBUS_VOLTAGE; double power = ((double)ChargingCurrent / MILLION) * ((double)ChargingVoltage / MILLION); @@ -775,8 +771,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { case ANDROID_POWER_SUPPLY_TYPE_DOCK: path.clear(); path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path.string(), R_OK) == 0) - mChargerNames.add(String8(name)); + if (access(path.c_str(), R_OK) == 0) mChargerNames.add(String8(name)); break; case ANDROID_POWER_SUPPLY_TYPE_BATTERY: @@ -958,12 +953,10 @@ void BatteryMonitor::init(struct healthd_config *hc) { // Look for "is_dock" file path.clear(); path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path.string(), R_OK) == 0) { + if (access(path.c_str(), R_OK) == 0) { path.clear(); path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path.string(), R_OK) == 0) - mChargerNames.add(String8(name)); - + if (access(path.c_str(), R_OK) == 0) mChargerNames.add(String8(name)); } } } diff --git a/healthd/BatteryMonitor_v1.cpp b/healthd/BatteryMonitor_v1.cpp index b87c493b2579..b2d6518f7a29 100644 --- a/healthd/BatteryMonitor_v1.cpp +++ b/healthd/BatteryMonitor_v1.cpp @@ -358,12 +358,10 @@ void BatteryMonitor::updateValues(void) { for (size_t i = 0; i < mChargerNames.size(); i++) { String8 path; - path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, - mChargerNames[i].string()); + path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, mChargerNames[i].c_str()); if (getIntField(path)) { path.clear(); - path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, - mChargerNames[i].string()); + path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, mChargerNames[i].c_str()); switch(readPowerSupplyType(path)) { case ANDROID_POWER_SUPPLY_TYPE_AC: mHealthInfo->chargerAcOnline = true; @@ -380,26 +378,24 @@ void BatteryMonitor::updateValues(void) { default: path.clear(); path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH, - mChargerNames[i].string()); - if (access(path.string(), R_OK) == 0) + mChargerNames[i].c_str()); + if (access(path.c_str(), R_OK) == 0) mHealthInfo->chargerDockOnline = true; else KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n", - mChargerNames[i].string()); + mChargerNames[i].c_str()); } path.clear(); path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH, - mChargerNames[i].string()); - int ChargingCurrent = - (access(path.string(), R_OK) == 0) ? getIntField(path) : 0; + mChargerNames[i].c_str()); + int ChargingCurrent = (access(path.c_str(), R_OK) == 0) ? getIntField(path) : 0; path.clear(); path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH, - mChargerNames[i].string()); + mChargerNames[i].c_str()); int ChargingVoltage = - (access(path.string(), R_OK) == 0) ? getIntField(path) : - DEFAULT_VBUS_VOLTAGE; + (access(path.c_str(), R_OK) == 0) ? getIntField(path) : DEFAULT_VBUS_VOLTAGE; double power = ((double)ChargingCurrent / MILLION) * ((double)ChargingVoltage / MILLION); @@ -628,8 +624,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { case ANDROID_POWER_SUPPLY_TYPE_DOCK: path.clear(); path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path.string(), R_OK) == 0) - mChargerNames.add(String8(name)); + if (access(path.c_str(), R_OK) == 0) mChargerNames.add(String8(name)); break; case ANDROID_POWER_SUPPLY_TYPE_BATTERY: @@ -767,12 +762,10 @@ void BatteryMonitor::init(struct healthd_config *hc) { // Look for "is_dock" file path.clear(); path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path.string(), R_OK) == 0) { + if (access(path.c_str(), R_OK) == 0) { path.clear(); path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path.string(), R_OK) == 0) - mChargerNames.add(String8(name)); - + if (access(path.c_str(), R_OK) == 0) mChargerNames.add(String8(name)); } } } diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp index f054de98b393..4b27bdddd64a 100644 --- a/libutils/ProcessCallStack.cpp +++ b/libutils/ProcessCallStack.cpp @@ -205,8 +205,7 @@ void ProcessCallStack::print(Printer& printer) const { } void ProcessCallStack::printInternal(Printer& printer, Printer& csPrinter) const { - dumpProcessHeader(printer, getpid(), - getTimeString(mTimeUpdated).string()); + dumpProcessHeader(printer, getpid(), getTimeString(mTimeUpdated).c_str()); for (size_t i = 0; i < mThreadMap.size(); ++i) { pid_t tid = mThreadMap.keyAt(i); @@ -214,7 +213,7 @@ void ProcessCallStack::printInternal(Printer& printer, Printer& csPrinter) const const String8& threadName = threadInfo.threadName; printer.printLine(""); - printer.printFormatLine("\"%s\" sysTid=%d", threadName.string(), tid); + printer.printFormatLine("\"%s\" sysTid=%d", threadName.c_str(), tid); threadInfo.callStack.print(csPrinter); } diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp index ab122c73213e..e0a2846d4a7a 100644 --- a/libutils/RefBase.cpp +++ b/libutils/RefBase.cpp @@ -330,7 +330,7 @@ class RefBase::weakref_impl : public RefBase::weakref_type this); int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 0644); if (rc >= 0) { - (void)write(rc, text.string(), text.length()); + (void)write(rc, text.c_str(), text.length()); close(rc); ALOGI("STACK TRACE for %p saved in %s", this, name); } diff --git a/libutils/String16_fuzz.cpp b/libutils/String16_fuzz.cpp index d7e5ec783690..a271aeebd897 100644 --- a/libutils/String16_fuzz.cpp +++ b/libutils/String16_fuzz.cpp @@ -25,7 +25,7 @@ std::vector void { - str1.string(); + str1.c_str(); }), ([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void { str1.isStaticString(); @@ -39,7 +39,7 @@ std::vector void { - str1.contains(str2.string()); + str1.contains(str2.c_str()); }), ([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void { str1.compare(str2); @@ -52,7 +52,7 @@ std::vector void { int pos = dataProvider.ConsumeIntegralInRange(0, str1.size()); - str1.insert(pos, str2.string()); + str1.insert(pos, str2.c_str()); }), // Find and replace operations diff --git a/libutils/String8_test.cpp b/libutils/String8_test.cpp index 35fd512f442d..9c12cb12df84 100644 --- a/libutils/String8_test.cpp +++ b/libutils/String8_test.cpp @@ -36,7 +36,7 @@ class String8Test : public testing::Test { TEST_F(String8Test, Cstr) { String8 tmp("Hello, world!"); - EXPECT_STREQ(tmp.string(), "Hello, world!"); + EXPECT_STREQ(tmp.c_str(), "Hello, world!"); } TEST_F(String8Test, OperatorPlus) { @@ -45,16 +45,16 @@ TEST_F(String8Test, OperatorPlus) { // Test adding String8 + const char* const char* ccsrc2 = "world!"; String8 dst1 = src1 + ccsrc2; - EXPECT_STREQ(dst1.string(), "Hello, world!"); - EXPECT_STREQ(src1.string(), "Hello, "); + EXPECT_STREQ(dst1.c_str(), "Hello, world!"); + EXPECT_STREQ(src1.c_str(), "Hello, "); EXPECT_STREQ(ccsrc2, "world!"); // Test adding String8 + String8 String8 ssrc2("world!"); String8 dst2 = src1 + ssrc2; - EXPECT_STREQ(dst2.string(), "Hello, world!"); - EXPECT_STREQ(src1.string(), "Hello, "); - EXPECT_STREQ(ssrc2.string(), "world!"); + EXPECT_STREQ(dst2.c_str(), "Hello, world!"); + EXPECT_STREQ(src1.c_str(), "Hello, "); + EXPECT_STREQ(ssrc2.c_str(), "world!"); } TEST_F(String8Test, OperatorPlusEquals) { @@ -63,14 +63,14 @@ TEST_F(String8Test, OperatorPlusEquals) { // Testing String8 += String8 String8 src2(" is my passport."); src1 += src2; - EXPECT_STREQ(src1.string(), "My voice is my passport."); - EXPECT_STREQ(src2.string(), " is my passport."); + EXPECT_STREQ(src1.c_str(), "My voice is my passport."); + EXPECT_STREQ(src2.c_str(), " is my passport."); // Adding const char* to the previous string. const char* src3 = " Verify me."; src1 += src3; - EXPECT_STREQ(src1.string(), "My voice is my passport. Verify me."); - EXPECT_STREQ(src2.string(), " is my passport."); + EXPECT_STREQ(src1.c_str(), "My voice is my passport. Verify me."); + EXPECT_STREQ(src2.c_str(), " is my passport."); EXPECT_STREQ(src3, " Verify me."); } diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp index c3ec1652b292..9fc955c1a37d 100644 --- a/libutils/Tokenizer.cpp +++ b/libutils/Tokenizer.cpp @@ -50,15 +50,15 @@ status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) { *outTokenizer = nullptr; int result = OK; - int fd = ::open(filename.string(), O_RDONLY); + int fd = ::open(filename.c_str(), O_RDONLY); if (fd < 0) { result = -errno; - ALOGE("Error opening file '%s': %s", filename.string(), strerror(errno)); + ALOGE("Error opening file '%s': %s", filename.c_str(), strerror(errno)); } else { struct stat stat; if (fstat(fd, &stat)) { result = -errno; - ALOGE("Error getting size of file '%s': %s", filename.string(), strerror(errno)); + ALOGE("Error getting size of file '%s': %s", filename.c_str(), strerror(errno)); } else { size_t length = size_t(stat.st_size); @@ -80,7 +80,7 @@ status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) { ssize_t nrd = read(fd, buffer, length); if (nrd < 0) { result = -errno; - ALOGE("Error reading file '%s': %s", filename.string(), strerror(errno)); + ALOGE("Error reading file '%s': %s", filename.c_str(), strerror(errno)); delete[] buffer; buffer = nullptr; } else { @@ -106,7 +106,7 @@ status_t Tokenizer::fromContents(const String8& filename, String8 Tokenizer::getLocation() const { String8 result; - result.appendFormat("%s:%d", mFilename.string(), mLineNumber); + result.appendFormat("%s:%d", mFilename.c_str(), mLineNumber); return result; } From 141c6a886c47a043ee6d1572ec634e2f79a47089 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 11 Aug 2023 21:05:14 +0000 Subject: [PATCH 0315/1487] Avoid two SELinux related error messages at boot time It is expected that /metadata/ota/rollback-indicator and /metadata/gsi don't always exist, so don't call selinux_android_restorecon() on them when they don't exist. This eliminates the following error messages: 0 0 E selinux : SELinux: Could not get canonical path for /metadata/ota/rollback-indicator restorecon: No such file or directory. 0 0 E selinux : SELinux: Could not stat /metadata/gsi: No such file or directory. Test: Booted Cuttlefish and verified the error messages are gone Change-Id: I94c998556c85adde5f11f134178219ba7880c2be --- init/selinux.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/init/selinux.cpp b/init/selinux.cpp index ebdcaa62db38..ac102eb4e4ce 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -735,6 +735,14 @@ void SelinuxAvcLog(char* buf) { TEMP_FAILURE_RETRY(send(fd.get(), &request, sizeof(request), 0)); } +int RestoreconIfExists(const char* path, unsigned int flags) { + if (access(path, F_OK) != 0 && errno == ENOENT) { + // Avoid error message for path that is expected to not always exist. + return 0; + } + return selinux_android_restorecon(path, flags); +} + } // namespace void SelinuxRestoreContext() { @@ -762,9 +770,9 @@ void SelinuxRestoreContext() { // adb remount, snapshot-based updates, and DSUs all create files during // first-stage init. - selinux_android_restorecon(SnapshotManager::GetGlobalRollbackIndicatorPath().c_str(), 0); - selinux_android_restorecon("/metadata/gsi", SELINUX_ANDROID_RESTORECON_RECURSE | - SELINUX_ANDROID_RESTORECON_SKIP_SEHASH); + RestoreconIfExists(SnapshotManager::GetGlobalRollbackIndicatorPath().c_str(), 0); + RestoreconIfExists("/metadata/gsi", + SELINUX_ANDROID_RESTORECON_RECURSE | SELINUX_ANDROID_RESTORECON_SKIP_SEHASH); } int SelinuxKlogCallback(int type, const char* fmt, ...) { From 90d4f89e8bbe2fd5c4719d4d62b099bfe0ce9fc9 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Mon, 14 Aug 2023 15:07:15 -0700 Subject: [PATCH 0316/1487] Removing extra string creation for log Removin unneccessary string from being created in logging Test: m libsnapshot Change-Id: I123b6a10f349dfb0c275e630b5f02d1cec8c2687 --- fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp index 6d04c6a0c380..1dd63731a270 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp @@ -174,8 +174,7 @@ void CowWriterV2::InitBatchWrites() { current_data_pos_ = next_data_pos_; } - std::string batch_write = batch_write_ ? "enabled" : "disabled"; - LOG_INFO << "Batch writes: " << batch_write; + LOG_INFO << "Batch writes: " << batch_write_ ? "enabled" : "disabled"; } void CowWriterV2::InitWorkers() { From de6e446efa45477ddcc7051a4e8f711e5220f0fc Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 8 Aug 2023 13:58:46 -0700 Subject: [PATCH 0317/1487] Adding compressor class Adding in compressor class to clean up code for cow_compress.cpp. Since we are making some api changes (to zstd) that are unique to each compression methods, these should be implementation details should be hidden to the parent class Test: m libsnapshot Change-Id: I9194e2c615aefed078458f525382253228bc1b69 --- .../include/libsnapshot/cow_compress.h | 48 ++++ .../include/libsnapshot/cow_writer.h | 10 +- .../libsnapshot_cow/cow_compress.cpp | 222 +++++++++++------- .../libsnapshot/libsnapshot_cow/test_v2.cpp | 3 +- .../libsnapshot/libsnapshot_cow/writer_v2.cpp | 18 +- .../libsnapshot/libsnapshot_cow/writer_v2.h | 3 + 6 files changed, 206 insertions(+), 98 deletions(-) create mode 100644 fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h new file mode 100644 index 000000000000..8add041cd874 --- /dev/null +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h @@ -0,0 +1,48 @@ +// +// Copyright (C) 2023 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. +// + +#pragma once + +#include +#include +#include "libsnapshot/cow_format.h" + +namespace android { +namespace snapshot { + +class ICompressor { + public: + explicit ICompressor(uint32_t compression_level) : compression_level_(compression_level) {} + + virtual ~ICompressor() {} + // Factory methods for compression methods. + static std::unique_ptr Gz(uint32_t compression_level); + static std::unique_ptr Brotli(uint32_t compression_level); + static std::unique_ptr Lz4(uint32_t compression_level); + static std::unique_ptr Zstd(uint32_t compression_level); + + static std::unique_ptr Create(CowCompression compression); + + uint32_t GetCompressionLevel() const { return compression_level_; } + + [[nodiscard]] virtual std::basic_string Compress(const void* data, + size_t length) const = 0; + + private: + uint32_t compression_level_; +}; +} // namespace snapshot +} // namespace android \ No newline at end of file diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h index 74b8bb845533..3016e933b798 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h @@ -14,6 +14,8 @@ #pragma once +#include + #include #include @@ -107,16 +109,14 @@ class ICowWriter { class CompressWorker { public: - CompressWorker(CowCompression compression, uint32_t block_size); + CompressWorker(std::unique_ptr&& compressor, uint32_t block_size); bool RunThread(); void EnqueueCompressBlocks(const void* buffer, size_t num_blocks); bool GetCompressedBuffers(std::vector>* compressed_buf); void Finalize(); static uint32_t GetDefaultCompressionLevel(CowCompressionAlgorithm compression); - static std::basic_string Compress(CowCompression compression, const void* data, - size_t length); - static bool CompressBlocks(CowCompression compression, size_t block_size, const void* buffer, + static bool CompressBlocks(ICompressor* compressor, size_t block_size, const void* buffer, size_t num_blocks, std::vector>* compressed_data); @@ -128,7 +128,7 @@ class CompressWorker { std::vector> compressed_data; }; - CowCompression compression_; + std::unique_ptr compressor_; uint32_t block_size_; std::queue work_queue_; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp index 96d60161218d..d023f19e3a49 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp @@ -22,8 +22,11 @@ #include #include +#include +#include #include #include +#include #include #include #include @@ -51,6 +54,22 @@ std::optional CompressionAlgorithmFromString(std::strin } } +std::unique_ptr ICompressor::Create(CowCompression compression) { + switch (compression.algorithm) { + case kCowCompressLz4: + return ICompressor::Lz4(compression.compression_level); + case kCowCompressBrotli: + return ICompressor::Brotli(compression.compression_level); + case kCowCompressGz: + return ICompressor::Gz(compression.compression_level); + case kCowCompressZstd: + return ICompressor::Zstd(compression.compression_level); + case kCowCompressNone: + return nullptr; + } + return nullptr; +} + // 1. Default compression level is determined by compression algorithm // 2. There might be compatibility issues if a value is changed here, as some older versions of // Android will assume a different compression level, causing cow_size estimation differences that @@ -77,101 +96,116 @@ uint32_t CompressWorker::GetDefaultCompressionLevel(CowCompressionAlgorithm comp return 0; } -std::basic_string CompressWorker::Compress(CowCompression compression, const void* data, - size_t length) { - switch (compression.algorithm) { - case kCowCompressGz: { - const auto bound = compressBound(length); - std::basic_string buffer(bound, '\0'); - - uLongf dest_len = bound; - auto rv = compress2(buffer.data(), &dest_len, reinterpret_cast(data), - length, compression.compression_level); - if (rv != Z_OK) { - LOG(ERROR) << "compress2 returned: " << rv; - return {}; - } - buffer.resize(dest_len); - return buffer; +class GzCompressor final : public ICompressor { + public: + GzCompressor(uint32_t compression_level) : ICompressor(compression_level){}; + + std::basic_string Compress(const void* data, size_t length) const override { + const auto bound = compressBound(length); + std::basic_string buffer(bound, '\0'); + + uLongf dest_len = bound; + auto rv = compress2(buffer.data(), &dest_len, reinterpret_cast(data), length, + GetCompressionLevel()); + if (rv != Z_OK) { + LOG(ERROR) << "compress2 returned: " << rv; + return {}; } - case kCowCompressBrotli: { - const auto bound = BrotliEncoderMaxCompressedSize(length); - if (!bound) { - LOG(ERROR) << "BrotliEncoderMaxCompressedSize returned 0"; - return {}; - } - std::basic_string buffer(bound, '\0'); - - size_t encoded_size = bound; - auto rv = BrotliEncoderCompress( - compression.compression_level, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, - length, reinterpret_cast(data), &encoded_size, buffer.data()); - if (!rv) { - LOG(ERROR) << "BrotliEncoderCompress failed"; - return {}; - } - buffer.resize(encoded_size); - return buffer; + buffer.resize(dest_len); + return buffer; + }; +}; + +class Lz4Compressor final : public ICompressor { + public: + Lz4Compressor(uint32_t compression_level) : ICompressor(compression_level){}; + + std::basic_string Compress(const void* data, size_t length) const override { + const auto bound = LZ4_compressBound(length); + if (!bound) { + LOG(ERROR) << "LZ4_compressBound returned 0"; + return {}; } - case kCowCompressLz4: { - const auto bound = LZ4_compressBound(length); - if (!bound) { - LOG(ERROR) << "LZ4_compressBound returned 0"; - return {}; - } - std::basic_string buffer(bound, '\0'); - - const auto compressed_size = LZ4_compress_default( - static_cast(data), reinterpret_cast(buffer.data()), length, - buffer.size()); - if (compressed_size <= 0) { - LOG(ERROR) << "LZ4_compress_default failed, input size: " << length - << ", compression bound: " << bound << ", ret: " << compressed_size; - return {}; - } - // Don't run compression if the compressed output is larger - if (compressed_size >= length) { - buffer.resize(length); - memcpy(buffer.data(), data, length); - } else { - buffer.resize(compressed_size); - } - return buffer; + std::basic_string buffer(bound, '\0'); + + const auto compressed_size = + LZ4_compress_default(static_cast(data), + reinterpret_cast(buffer.data()), length, buffer.size()); + if (compressed_size <= 0) { + LOG(ERROR) << "LZ4_compress_default failed, input size: " << length + << ", compression bound: " << bound << ", ret: " << compressed_size; + return {}; } - case kCowCompressZstd: { - std::basic_string buffer(ZSTD_compressBound(length), '\0'); - const auto compressed_size = ZSTD_compress(buffer.data(), buffer.size(), data, length, - compression.compression_level); - if (compressed_size <= 0) { - LOG(ERROR) << "ZSTD compression failed " << compressed_size; - return {}; - } - // Don't run compression if the compressed output is larger - if (compressed_size >= length) { - buffer.resize(length); - memcpy(buffer.data(), data, length); - } else { - buffer.resize(compressed_size); - } - return buffer; + // Don't run compression if the compressed output is larger + if (compressed_size >= length) { + buffer.resize(length); + memcpy(buffer.data(), data, length); + } else { + buffer.resize(compressed_size); } - default: - LOG(ERROR) << "unhandled compression type: " << compression.algorithm; - break; - } - return {}; -} + return buffer; + }; +}; + +class BrotliCompressor final : public ICompressor { + public: + BrotliCompressor(uint32_t compression_level) : ICompressor(compression_level){}; + + std::basic_string Compress(const void* data, size_t length) const override { + const auto bound = BrotliEncoderMaxCompressedSize(length); + if (!bound) { + LOG(ERROR) << "BrotliEncoderMaxCompressedSize returned 0"; + return {}; + } + std::basic_string buffer(bound, '\0'); + + size_t encoded_size = bound; + auto rv = BrotliEncoderCompress( + GetCompressionLevel(), BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, length, + reinterpret_cast(data), &encoded_size, buffer.data()); + if (!rv) { + LOG(ERROR) << "BrotliEncoderCompress failed"; + return {}; + } + buffer.resize(encoded_size); + return buffer; + }; +}; + +class ZstdCompressor final : public ICompressor { + public: + ZstdCompressor(uint32_t compression_level) : ICompressor(compression_level){}; + + std::basic_string Compress(const void* data, size_t length) const override { + std::basic_string buffer(ZSTD_compressBound(length), '\0'); + const auto compressed_size = + ZSTD_compress(buffer.data(), buffer.size(), data, length, GetCompressionLevel()); + if (compressed_size <= 0) { + LOG(ERROR) << "ZSTD compression failed " << compressed_size; + return {}; + } + // Don't run compression if the compressed output is larger + if (compressed_size >= length) { + buffer.resize(length); + memcpy(buffer.data(), data, length); + } else { + buffer.resize(compressed_size); + } + return buffer; + }; +}; + bool CompressWorker::CompressBlocks(const void* buffer, size_t num_blocks, std::vector>* compressed_data) { - return CompressBlocks(compression_, block_size_, buffer, num_blocks, compressed_data); + return CompressBlocks(compressor_.get(), block_size_, buffer, num_blocks, compressed_data); } -bool CompressWorker::CompressBlocks(CowCompression compression, size_t block_size, - const void* buffer, size_t num_blocks, +bool CompressWorker::CompressBlocks(ICompressor* compressor, size_t block_size, const void* buffer, + size_t num_blocks, std::vector>* compressed_data) { const uint8_t* iter = reinterpret_cast(buffer); while (num_blocks) { - auto data = Compress(compression, iter, block_size); + auto data = compressor->Compress(iter, block_size); if (data.empty()) { PLOG(ERROR) << "CompressBlocks: Compression failed"; return false; @@ -270,6 +304,22 @@ bool CompressWorker::GetCompressedBuffers(std::vector return true; } +std::unique_ptr ICompressor::Brotli(uint32_t compression_level) { + return std::make_unique(compression_level); +} + +std::unique_ptr ICompressor::Gz(uint32_t compression_level) { + return std::make_unique(compression_level); +} + +std::unique_ptr ICompressor::Lz4(uint32_t compression_level) { + return std::make_unique(compression_level); +} + +std::unique_ptr ICompressor::Zstd(uint32_t compression_level) { + return std::make_unique(compression_level); +} + void CompressWorker::Finalize() { { std::unique_lock lock(lock_); @@ -278,8 +328,8 @@ void CompressWorker::Finalize() { cv_.notify_all(); } -CompressWorker::CompressWorker(CowCompression compression, uint32_t block_size) - : compression_(compression), block_size_(block_size) {} +CompressWorker::CompressWorker(std::unique_ptr&& compressor, uint32_t block_size) + : compressor_(std::move(compressor)), block_size_(block_size) {} } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp index 2258d9fb75cb..0ecad9d2c7a7 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp @@ -480,7 +480,8 @@ TEST_P(CompressionTest, HorribleStream) { std::string expected = "The quick brown fox jumps over the lazy dog."; expected.resize(4096, '\0'); - auto result = CompressWorker::Compress(compression, expected.data(), expected.size()); + std::unique_ptr compressor = ICompressor::Create(compression); + auto result = compressor->Compress(expected.data(), expected.size()); ASSERT_FALSE(result.empty()); HorribleStream stream(result); diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp index 6d04c6a0c380..7115821b63fb 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp @@ -184,7 +184,8 @@ void CowWriterV2::InitWorkers() { return; } for (int i = 0; i < num_compress_threads_; i++) { - auto wt = std::make_unique(compression_, header_.block_size); + std::unique_ptr compressor = ICompressor::Create(compression_); + auto wt = std::make_unique(std::move(compressor), header_.block_size); threads_.emplace_back(std::async(std::launch::async, &CompressWorker::RunThread, wt.get())); compress_threads_.push_back(std::move(wt)); } @@ -339,10 +340,12 @@ bool CowWriterV2::CompressBlocks(size_t num_blocks, const void* data) { const uint8_t* iter = reinterpret_cast(data); compressed_buf_.clear(); if (num_threads <= 1) { - return CompressWorker::CompressBlocks(compression_, options_.block_size, data, num_blocks, - &compressed_buf_); + if (!compressor_) { + compressor_ = ICompressor::Create(compression_); + } + return CompressWorker::CompressBlocks(compressor_.get(), options_.block_size, data, + num_blocks, &compressed_buf_); } - // Submit the blocks per thread. The retrieval of // compressed buffers has to be done in the same order. // We should not poll for completed buffers in a different order as the @@ -412,8 +415,11 @@ bool CowWriterV2::EmitBlocks(uint64_t new_block_start, const void* data, size_t buf_iter_++; return data; } else { - auto data = - CompressWorker::Compress(compression_, iter, header_.block_size); + if (!compressor_) { + compressor_ = ICompressor::Create(compression_); + } + + auto data = compressor_->Compress(iter, header_.block_size); return data; } }(); diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h index 3f357e024cf0..131a068455ba 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h @@ -65,6 +65,9 @@ class CowWriterV2 : public CowWriterBase { private: CowFooter footer_{}; CowCompression compression_; + // in the case that we are using one thread for compression, we can store and re-use the same + // compressor + std::unique_ptr compressor_; uint64_t current_op_pos_ = 0; uint64_t next_op_pos_ = 0; uint64_t next_data_pos_ = 0; From 03acfdbeb6dcf6ffb32b1823a91d8b29bbce03b5 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Wed, 9 Aug 2023 13:48:08 -0700 Subject: [PATCH 0318/1487] Optimize zstd compression reuse the same context for zstd compression. One context should be used per compression thread for optimal performance. Discussion and reccomendations can be found at go/android-hw-compression-vendor Results (level 3 compression) full ota on raven with optimizations: 1191.304 seconds without optimizations: 1461.854 seconds compression ratio remains unchanged and merge time difference are negligible ~1% delta (probably just noise) Test: ota_from_target_files, update_device.py Change-Id: I3feede9f1f119874e369c54b29c594475fbf7376 --- .../libsnapshot/libsnapshot_cow/cow_compress.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp index d023f19e3a49..466b93c25b27 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -174,12 +175,18 @@ class BrotliCompressor final : public ICompressor { class ZstdCompressor final : public ICompressor { public: - ZstdCompressor(uint32_t compression_level) : ICompressor(compression_level){}; + ZstdCompressor(uint32_t compression_level) + : ICompressor(compression_level), zstd_context_(ZSTD_createCCtx(), ZSTD_freeCCtx) { + ZSTD_CCtx_setParameter(zstd_context_.get(), ZSTD_c_compressionLevel, compression_level); + // FIXME: hardcoding a value of 12 here for 4k blocks, should change to be either set by + // user, or optimized depending on block size + ZSTD_CCtx_setParameter(zstd_context_.get(), ZSTD_c_windowLog, 12); + }; std::basic_string Compress(const void* data, size_t length) const override { std::basic_string buffer(ZSTD_compressBound(length), '\0'); const auto compressed_size = - ZSTD_compress(buffer.data(), buffer.size(), data, length, GetCompressionLevel()); + ZSTD_compress2(zstd_context_.get(), buffer.data(), buffer.size(), data, length); if (compressed_size <= 0) { LOG(ERROR) << "ZSTD compression failed " << compressed_size; return {}; @@ -193,6 +200,9 @@ class ZstdCompressor final : public ICompressor { } return buffer; }; + + private: + std::unique_ptr zstd_context_; }; bool CompressWorker::CompressBlocks(const void* buffer, size_t num_blocks, From 8d9940bdaf637fcefaf6d1f91212de7a0d0d8da7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 15 Aug 2023 15:13:52 -0700 Subject: [PATCH 0319/1487] Update OWNERS. Change-Id: Ib069b181fd48d73e5320f44c435b8814f269d291 --- fs_mgr/libsnapshot/OWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/fs_mgr/libsnapshot/OWNERS b/fs_mgr/libsnapshot/OWNERS index 9d2b877aca56..1ee4175cffca 100644 --- a/fs_mgr/libsnapshot/OWNERS +++ b/fs_mgr/libsnapshot/OWNERS @@ -3,3 +3,4 @@ balsini@google.com dvander@google.com elsk@google.com akailash@google.com +zhangkelvin@google.com From fb7e268552867da13229eb8d8aee77dee4f6d2bc Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 9 Aug 2023 10:31:56 -0700 Subject: [PATCH 0320/1487] snapuserd: Fix race condition in MergeWorker::WaitForMergeBegin. The pre-conditions and post-conditions to cv.wait() in this function are different, which leads to a race. If the merge is never initiated, but I/O is terminated, the wait() will hang. This is easy to hit in tests where I/O terminates quickly, but should not affect actual OTA flow in practice. Bug: 269361087 Test: snapuserd_test Change-Id: I85ed9c357031ec6fd74d6a3f49d85e6cbb037eee --- .../snapuserd_transitions.cpp | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp index 52e4f89cd124..f3e00195266a 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp @@ -189,35 +189,32 @@ void SnapshotHandler::InitiateMerge() { cv.notify_all(); } +static inline bool IsMergeBeginError(MERGE_IO_TRANSITION io_state) { + return io_state == MERGE_IO_TRANSITION::READ_AHEAD_FAILURE || + io_state == MERGE_IO_TRANSITION::IO_TERMINATED; +} + // Invoked by Merge thread - Waits on RA thread to resume merging. Will // be waken up RA thread. bool SnapshotHandler::WaitForMergeBegin() { - { - std::unique_lock lock(lock_); - while (!MergeInitiated()) { - cv.wait(lock); + std::unique_lock lock(lock_); - if (io_state_ == MERGE_IO_TRANSITION::READ_AHEAD_FAILURE || - io_state_ == MERGE_IO_TRANSITION::IO_TERMINATED) { - SNAP_LOG(ERROR) << "WaitForMergeBegin failed with state: " << io_state_; - return false; - } - } + cv.wait(lock, [this]() -> bool { return MergeInitiated() || IsMergeBeginError(io_state_); }); - while (!(io_state_ == MERGE_IO_TRANSITION::MERGE_BEGIN || - io_state_ == MERGE_IO_TRANSITION::READ_AHEAD_FAILURE || - io_state_ == MERGE_IO_TRANSITION::IO_TERMINATED)) { - cv.wait(lock); - } + if (IsMergeBeginError(io_state_)) { + SNAP_LOG(ERROR) << "WaitForMergeBegin failed with state: " << io_state_; + return false; + } - if (io_state_ == MERGE_IO_TRANSITION::READ_AHEAD_FAILURE || - io_state_ == MERGE_IO_TRANSITION::IO_TERMINATED) { - SNAP_LOG(ERROR) << "WaitForMergeBegin failed with state: " << io_state_; - return false; - } + cv.wait(lock, [this]() -> bool { + return io_state_ == MERGE_IO_TRANSITION::MERGE_BEGIN || IsMergeBeginError(io_state_); + }); - return true; + if (IsMergeBeginError(io_state_)) { + SNAP_LOG(ERROR) << "WaitForMergeBegin failed with state: " << io_state_; + return false; } + return true; } // Invoked by RA thread - Flushes the RA block to scratch space if necessary From ed7716f2c46eaf846f16791bec21a2836c1bcc99 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 8 Aug 2023 12:47:28 -0700 Subject: [PATCH 0321/1487] snapuserd: Add snapuserd_test to presubmit and VTS. Bug: 269361087 Test: presubmit Change-Id: Ic80025b1e75f049abdc7fdbcfdd5a142f56d702e --- fs_mgr/TEST_MAPPING | 8 +++++++- fs_mgr/libsnapshot/snapuserd/Android.bp | 25 ++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING index d357e4571dcf..169496929bdd 100644 --- a/fs_mgr/TEST_MAPPING +++ b/fs_mgr/TEST_MAPPING @@ -28,6 +28,9 @@ //{"name": "vabc_legacy_tests"}, { "name": "cow_api_test" + }, + { + "name": "snapuserd_test" } ], "kernel-presubmit": [ @@ -42,8 +45,11 @@ }, { "name": "vab_legacy_tests" - } + }, // TODO: b/279009697 //{"name": "vabc_legacy_tests"} + { + "name": "snapuserd_test" + } ] } diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 6548cc8a75b0..e56ffbe63d47 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -214,8 +214,8 @@ cc_test { require_root: false, } -cc_test { - name: "snapuserd_test", +cc_defaults { + name: "snapuserd_test_defaults", defaults: [ "fs_mgr_defaults", "libsnapshot_cow_defaults", @@ -256,5 +256,24 @@ cc_test { min_shipping_api_level: 30, }, auto_gen_config: true, - require_root: false, + require_root: true, + compile_multilib: "first", +} + +cc_test { + name: "snapuserd_test", + defaults: ["snapuserd_test_defaults"], + host_supported: true, + test_suites: [ + "device-tests", + ], +} + +// vts tests cannot be host_supported. +cc_test { + name: "vts_snapuserd_test", + defaults: ["snapuserd_test_defaults"], + test_suites: [ + "vts", + ], } From b702fddd2e0907740f0656550016ea9fcda5e72b Mon Sep 17 00:00:00 2001 From: Snehal Date: Fri, 11 Aug 2023 09:48:22 +0000 Subject: [PATCH 0322/1487] Change name to trusty-coverage-controller Test: builds and passes tests Bug: None Change-Id: I89eec23312f79f4da43c491ce58aa4f246c7ab34 --- trusty/utils/coverage-controller/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trusty/utils/coverage-controller/Android.bp b/trusty/utils/coverage-controller/Android.bp index 1aa88cc12086..e6d30d912d12 100644 --- a/trusty/utils/coverage-controller/Android.bp +++ b/trusty/utils/coverage-controller/Android.bp @@ -17,7 +17,7 @@ package { } cc_binary { - name: "coverage-controller", + name: "trusty-coverage-controller", vendor: true, srcs: ["controller.cpp"], From c37838eec8d7b5bcec74e8293a0bdb655991a4e7 Mon Sep 17 00:00:00 2001 From: Bruce Po Date: Wed, 16 Aug 2023 17:36:55 +0000 Subject: [PATCH 0323/1487] Revert "Remove cutils threads.h header completely." This reverts commit d3550e33148c48c4accdccb7f822701e5bea025d. Reason for revert: DroidMonitor-triggered revert due to breakage https://android-build.googleplex.com/builds/quarterdeck?branch=git_tm-qpr-dev-plus-aosp&target=aosp_sunfish-userdebug&lkgb=10667572&lkbb=10667604&fkbb=10667601, bug http://b/296247274 Change-Id: I3f3864dc21fcb34cbb2ff524c43c3d92bd260ff6 BUG: 296247274 --- libcutils/include/cutils/threads.h | 15 +++++++++++++++ libcutils/include_outside_system/cutils/threads.h | 1 + 2 files changed, 16 insertions(+) create mode 100644 libcutils/include/cutils/threads.h create mode 120000 libcutils/include_outside_system/cutils/threads.h diff --git a/libcutils/include/cutils/threads.h b/libcutils/include/cutils/threads.h new file mode 100644 index 000000000000..9bc3429bec29 --- /dev/null +++ b/libcutils/include/cutils/threads.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2007 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. + */ diff --git a/libcutils/include_outside_system/cutils/threads.h b/libcutils/include_outside_system/cutils/threads.h new file mode 120000 index 000000000000..99330ffadfe3 --- /dev/null +++ b/libcutils/include_outside_system/cutils/threads.h @@ -0,0 +1 @@ +../../include/cutils/threads.h \ No newline at end of file From 6cf9cd0123016879454fe0eff15ba78223a68527 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Wed, 16 Aug 2023 22:37:14 +0000 Subject: [PATCH 0324/1487] Revert "Revert "Remove cutils threads.h header completely."" This reverts commit c37838eec8d7b5bcec74e8293a0bdb655991a4e7. Reason for revert: b/296247274 root-cause fixed Change-Id: I859e7500a1dd09e3a66986cda9e62adf5d7a524a --- libcutils/include/cutils/threads.h | 15 --------------- libcutils/include_outside_system/cutils/threads.h | 1 - 2 files changed, 16 deletions(-) delete mode 100644 libcutils/include/cutils/threads.h delete mode 120000 libcutils/include_outside_system/cutils/threads.h diff --git a/libcutils/include/cutils/threads.h b/libcutils/include/cutils/threads.h deleted file mode 100644 index 9bc3429bec29..000000000000 --- a/libcutils/include/cutils/threads.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ diff --git a/libcutils/include_outside_system/cutils/threads.h b/libcutils/include_outside_system/cutils/threads.h deleted file mode 120000 index 99330ffadfe3..000000000000 --- a/libcutils/include_outside_system/cutils/threads.h +++ /dev/null @@ -1 +0,0 @@ -../../include/cutils/threads.h \ No newline at end of file From 96b78feec1f326fbfcfee9714a0dcaaa1a3683e1 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 15 Aug 2023 14:34:39 -0700 Subject: [PATCH 0325/1487] Fix zstd optimization api usage ZSTD_c_windowLog should be set as log base 2 of max block size. Changing hardcoded value to be determined by this variable. Test: m libsnapshot Change-Id: I09be447b7f1e95cb72a6a42eddb4035f61a43aad --- .../include/libsnapshot/cow_compress.h | 4 ++-- .../libsnapshot/libsnapshot_cow/cow_compress.cpp | 15 +++++++-------- fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp | 2 +- fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp | 7 ++++--- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h index 8add041cd874..97974c414524 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h @@ -32,9 +32,9 @@ class ICompressor { static std::unique_ptr Gz(uint32_t compression_level); static std::unique_ptr Brotli(uint32_t compression_level); static std::unique_ptr Lz4(uint32_t compression_level); - static std::unique_ptr Zstd(uint32_t compression_level); + static std::unique_ptr Zstd(uint32_t compression_level, const int32_t BLOCK_SZ); - static std::unique_ptr Create(CowCompression compression); + static std::unique_ptr Create(CowCompression compression, const int32_t BLOCK_SZ); uint32_t GetCompressionLevel() const { return compression_level_; } diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp index 466b93c25b27..71ac59f20d20 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp @@ -55,7 +55,8 @@ std::optional CompressionAlgorithmFromString(std::strin } } -std::unique_ptr ICompressor::Create(CowCompression compression) { +std::unique_ptr ICompressor::Create(CowCompression compression, + const int32_t BLOCK_SZ) { switch (compression.algorithm) { case kCowCompressLz4: return ICompressor::Lz4(compression.compression_level); @@ -64,7 +65,7 @@ std::unique_ptr ICompressor::Create(CowCompression compression) { case kCowCompressGz: return ICompressor::Gz(compression.compression_level); case kCowCompressZstd: - return ICompressor::Zstd(compression.compression_level); + return ICompressor::Zstd(compression.compression_level, BLOCK_SZ); case kCowCompressNone: return nullptr; } @@ -175,12 +176,10 @@ class BrotliCompressor final : public ICompressor { class ZstdCompressor final : public ICompressor { public: - ZstdCompressor(uint32_t compression_level) + ZstdCompressor(uint32_t compression_level, const uint32_t MAX_BLOCK_SIZE) : ICompressor(compression_level), zstd_context_(ZSTD_createCCtx(), ZSTD_freeCCtx) { ZSTD_CCtx_setParameter(zstd_context_.get(), ZSTD_c_compressionLevel, compression_level); - // FIXME: hardcoding a value of 12 here for 4k blocks, should change to be either set by - // user, or optimized depending on block size - ZSTD_CCtx_setParameter(zstd_context_.get(), ZSTD_c_windowLog, 12); + ZSTD_CCtx_setParameter(zstd_context_.get(), ZSTD_c_windowLog, log2(MAX_BLOCK_SIZE)); }; std::basic_string Compress(const void* data, size_t length) const override { @@ -326,8 +325,8 @@ std::unique_ptr ICompressor::Lz4(uint32_t compression_level) { return std::make_unique(compression_level); } -std::unique_ptr ICompressor::Zstd(uint32_t compression_level) { - return std::make_unique(compression_level); +std::unique_ptr ICompressor::Zstd(uint32_t compression_level, const int32_t BLOCK_SZ) { + return std::make_unique(compression_level, BLOCK_SZ); } void CompressWorker::Finalize() { diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp index 0ecad9d2c7a7..e59bd927fe08 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp @@ -480,7 +480,7 @@ TEST_P(CompressionTest, HorribleStream) { std::string expected = "The quick brown fox jumps over the lazy dog."; expected.resize(4096, '\0'); - std::unique_ptr compressor = ICompressor::Create(compression); + std::unique_ptr compressor = ICompressor::Create(compression, 4096); auto result = compressor->Compress(expected.data(), expected.size()); ASSERT_FALSE(result.empty()); diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp index 7115821b63fb..4172fc9c34a5 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp @@ -184,7 +184,8 @@ void CowWriterV2::InitWorkers() { return; } for (int i = 0; i < num_compress_threads_; i++) { - std::unique_ptr compressor = ICompressor::Create(compression_); + std::unique_ptr compressor = + ICompressor::Create(compression_, header_.block_size); auto wt = std::make_unique(std::move(compressor), header_.block_size); threads_.emplace_back(std::async(std::launch::async, &CompressWorker::RunThread, wt.get())); compress_threads_.push_back(std::move(wt)); @@ -341,7 +342,7 @@ bool CowWriterV2::CompressBlocks(size_t num_blocks, const void* data) { compressed_buf_.clear(); if (num_threads <= 1) { if (!compressor_) { - compressor_ = ICompressor::Create(compression_); + compressor_ = ICompressor::Create(compression_, header_.block_size); } return CompressWorker::CompressBlocks(compressor_.get(), options_.block_size, data, num_blocks, &compressed_buf_); @@ -416,7 +417,7 @@ bool CowWriterV2::EmitBlocks(uint64_t new_block_start, const void* data, size_t return data; } else { if (!compressor_) { - compressor_ = ICompressor::Create(compression_); + compressor_ = ICompressor::Create(compression_, header_.block_size); } auto data = compressor_->Compress(iter, header_.block_size); From 21aab6cb8384c3e7d53118c9684b450c7604b4b7 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Wed, 16 Aug 2023 15:19:57 -0700 Subject: [PATCH 0326/1487] Fix warning remove some unused headers and fix warning: Moving a temporary object prevents copy elision Test: m libsnapshot Change-Id: Idec3e051837dab5f1b95e677d1cdb09e9a57e73e --- fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp index f37aed1afe63..1b5d72484a5a 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp @@ -17,9 +17,7 @@ #include #include -#include #include -#include #include #include #include @@ -103,7 +101,7 @@ bool CowReader::Parse(android::base::borrowed_fd fd, std::optional lab footer_ = parser.footer(); fd_size_ = parser.fd_size(); last_label_ = parser.last_label(); - ops_ = std::move(parser.ops()); + ops_ = parser.ops(); data_loc_ = parser.data_loc(); // If we're resuming a write, we're not ready to merge From 36882e98b4b33d48949cfcc3700f39f24489bebd Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 15 Aug 2023 13:32:48 -0700 Subject: [PATCH 0327/1487] ZSTD read from wrong buf Fix zstd to read from ignore_buf rather than buf since that is where we are first copying the date Test: zstd ota Change-Id: I5032300e4628ecd7e49f1fa9f76dc9a828fb58e6 --- fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp index 3692c1a8aa9c..2aaf3883f638 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp @@ -351,7 +351,7 @@ class ZstdDecompressor final : public IDecompressor { return decompressed_size; } std::vector ignore_buf(decompressed_size); - if (!Decompress(buffer, decompressed_size)) { + if (!Decompress(ignore_buf.data(), decompressed_size)) { return -1; } memcpy(buffer, ignore_buf.data() + ignore_bytes, buffer_size); From 4b503b968cc9822a39588c2d198280aff85efbc6 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Thu, 17 Aug 2023 15:12:49 -0700 Subject: [PATCH 0328/1487] Fix uninitialized var compiler warnings Test: th Bug: 293313353 Change-Id: I87420a21a9c2ce1987179bf70767ea15b26cd5a5 --- init/first_stage_init.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index 7fabbac517a2..88300cb29c36 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -67,7 +67,7 @@ enum class BootMode { void FreeRamdisk(DIR* dir, dev_t dev) { int dfd = dirfd(dir); - dirent* de; + dirent* de = nullptr; while ((de = readdir(dir)) != nullptr) { if (de->d_name == "."s || de->d_name == ".."s) { continue; @@ -76,7 +76,7 @@ void FreeRamdisk(DIR* dir, dev_t dev) { bool is_dir = false; if (de->d_type == DT_DIR || de->d_type == DT_UNKNOWN) { - struct stat info; + struct stat info {}; if (fstatat(dfd, de->d_name, &info, AT_SYMLINK_NOFOLLOW) != 0) { continue; } @@ -171,7 +171,7 @@ std::string GetModuleLoadList(BootMode boot_mode, const std::string& dir_path) { } if (module_load_file != "modules.load") { - struct stat fileStat; + struct stat fileStat {}; std::string load_path = dir_path + "/" + module_load_file; // Fall back to modules.load if the other files aren't accessible if (stat(load_path.c_str(), &fileStat)) { @@ -185,11 +185,11 @@ std::string GetModuleLoadList(BootMode boot_mode, const std::string& dir_path) { #define MODULE_BASE_DIR "/lib/modules" bool LoadKernelModules(BootMode boot_mode, bool want_console, bool want_parallel, int& modules_loaded) { - struct utsname uts; + struct utsname uts {}; if (uname(&uts)) { LOG(FATAL) << "Failed to get kernel version."; } - int major, minor; + int major = 0, minor = 0; if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) { LOG(FATAL) << "Failed to parse kernel version " << uts.release; } @@ -199,13 +199,13 @@ bool LoadKernelModules(BootMode boot_mode, bool want_console, bool want_parallel LOG(INFO) << "Unable to open /lib/modules, skipping module loading."; return true; } - dirent* entry; + dirent* entry = nullptr; std::vector module_dirs; while ((entry = readdir(base_dir.get()))) { if (entry->d_type != DT_DIR) { continue; } - int dir_major, dir_minor; + int dir_major = 0, dir_minor = 0; if (sscanf(entry->d_name, "%d.%d", &dir_major, &dir_minor) != 2 || dir_major != major || dir_minor != minor) { continue; @@ -374,7 +374,7 @@ int FirstStageMain(int argc, char** argv) { PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk"; } - struct stat old_root_info; + struct stat old_root_info {}; if (stat("/", &old_root_info) != 0) { PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk"; old_root_dir.reset(); @@ -483,7 +483,7 @@ int FirstStageMain(int argc, char** argv) { } } - struct stat new_root_info; + struct stat new_root_info {}; if (stat("/", &new_root_info) != 0) { PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk"; old_root_dir.reset(); From 6e074fc31ee0a58eaa8f3c35affbe54918165747 Mon Sep 17 00:00:00 2001 From: Snehal Date: Mon, 14 Aug 2023 14:31:14 +0000 Subject: [PATCH 0329/1487] Add UUIDs to profraw filenames Bug: 295866435 Change-Id: Ie9390f412c70202d1583e29ac83c30778ae02f70 --- .../utils/coverage-controller/controller.cpp | 33 +++++++++++++++---- trusty/utils/coverage-controller/controller.h | 3 ++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/trusty/utils/coverage-controller/controller.cpp b/trusty/utils/coverage-controller/controller.cpp index 730c0109b0ca..0047046d7566 100644 --- a/trusty/utils/coverage-controller/controller.cpp +++ b/trusty/utils/coverage-controller/controller.cpp @@ -14,11 +14,16 @@ * limitations under the License. */ +#include +#include #include +#include +#include +#include +#include +#include #include #include -#include -#include #include #include "controller.h" @@ -48,10 +53,10 @@ void Controller::run(std::string output_dir) { if (complete_cnt != counters[index] && start_cnt == complete_cnt) { WRITE_ONCE(control->cntrl_flags, FLAG_NONE); - std::string fmt = "/%d.%lu.profraw"; - int sz = std::snprintf(nullptr, 0, fmt.c_str(), index, counters[index]); - std::string filename(sz+1, '.'); - std::sprintf(filename.data(), fmt.c_str(), index, counters[index]); + std::string filename; + filename = android::base::StringPrintf("/%s.%lu.profraw", + uuid_list_[index].c_str(), + counters[index]); filename.insert(0, output_dir); android::base::Result res = record_list_[index]->SaveFile(filename); counters[index]++; @@ -79,6 +84,7 @@ void Controller::setUpShm() { struct line_coverage_client_resp resp; uint32_t cur_index = record_list_.size(); struct uuid zero_uuid = {0, 0, 0, { 0 }}; + char uuid_str[UUID_STR_SIZE]; req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_SEND_LIST; int rc = write(coverage_srv_fd, &req, sizeof(req)); if (rc != (int)sizeof(req)) { @@ -98,6 +104,21 @@ void Controller::setUpShm() { } if(uuid_set_.find(resp.send_list_args.uuid) == uuid_set_.end()) { uuid_set_.insert(resp.send_list_args.uuid); + sprintf(uuid_str, + "%08" PRIx32 "-%04" PRIx16 "-%04" PRIx16 "-%02" PRIx8 "%02" PRIx8 + "-%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8, + resp.send_list_args.uuid.time_low, + resp.send_list_args.uuid.time_mid, + resp.send_list_args.uuid.time_hi_and_version, + resp.send_list_args.uuid.clock_seq_and_node[0], + resp.send_list_args.uuid.clock_seq_and_node[1], + resp.send_list_args.uuid.clock_seq_and_node[2], + resp.send_list_args.uuid.clock_seq_and_node[3], + resp.send_list_args.uuid.clock_seq_and_node[4], + resp.send_list_args.uuid.clock_seq_and_node[5], + resp.send_list_args.uuid.clock_seq_and_node[6], + resp.send_list_args.uuid.clock_seq_and_node[7]); + uuid_list_.push_back(uuid_str); record_list_.push_back(std::make_unique(TIPC_DEV, &resp.send_list_args.uuid)); counters.push_back(0); diff --git a/trusty/utils/coverage-controller/controller.h b/trusty/utils/coverage-controller/controller.h index b771c16150d8..f7789bfed076 100644 --- a/trusty/utils/coverage-controller/controller.h +++ b/trusty/utils/coverage-controller/controller.h @@ -26,6 +26,8 @@ #define TEST_SRV_PORT "com.android.trusty.sancov.test.srv" #define TEST_SRV_MODULE "srv.syms.elf" +#define UUID_STR_SIZE (37) + #define FLAG_NONE 0x0 #define FLAG_RUN 0x1 #define FLAG_TOGGLE_CLEAR 0x2 @@ -52,6 +54,7 @@ class Controller { private: std::vector>record_list_; std::setuuid_set_; + std::vectoruuid_list_; std::vector counters; int coverage_srv_fd; From 6d1b644930d2c89ce967bcecc7fa4af0290e8fcd Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Mon, 14 Aug 2023 15:47:29 +0000 Subject: [PATCH 0330/1487] Drop String::empty() This method causes confuction and bugs by having the same name, but different meaning versus std::string::empty(). Bug: 295394788 Test: make checkbuild Change-Id: I15aadc023b20559930e4ec79f43f7032e8cd90d0 --- libutils/include/utils/String8.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h index e58f1a5d1992..ace0243f3314 100644 --- a/libutils/include/utils/String8.h +++ b/libutils/include/utils/String8.h @@ -52,8 +52,6 @@ class String8 explicit String8(const char32_t* o, size_t numChars); ~String8(); - static inline const String8 empty(); - static String8 format(const char* fmt, ...) __attribute__((format (printf, 1, 2))); static String8 formatV(const char* fmt, va_list args); @@ -240,10 +238,6 @@ inline int strictly_order_type(const String8& lhs, const String8& rhs) return compare_type(lhs, rhs) < 0; } -inline const String8 String8::empty() { - return String8(); -} - inline const char* String8::c_str() const { return mString; From 2676893dd89fd7127c34a2f211dd02b5a8d7a647 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Mon, 14 Aug 2023 17:05:51 +0000 Subject: [PATCH 0331/1487] Implement String8|16::empty and String16::length This time following std::string::empty meaning. String16::length is for parity with String8::length and to follow std::string::length/size duo. Bug: 295394788 Test: mma Change-Id: I43df2cbb9ca6f980a4cf6d971064d594d661f884 --- libutils/include/utils/String16.h | 14 ++++++++++++++ libutils/include/utils/String8.h | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h index d719aeaaa28e..b48b90765612 100644 --- a/libutils/include/utils/String16.h +++ b/libutils/include/utils/String16.h @@ -60,6 +60,10 @@ class String16 static inline std::string std_string(const String16& str); public: size_t size() const; + inline bool empty() const; + + inline size_t length() const; + void setTo(const String16& other); status_t setTo(const char16_t* other); status_t setTo(const char16_t* other, size_t len); @@ -250,6 +254,16 @@ inline std::string String16::std_string(const String16& str) return std::string(String8(str).c_str()); } +inline bool String16::empty() const +{ + return length() == 0; +} + +inline size_t String16::length() const +{ + return size(); +} + inline String16& String16::operator=(const String16& other) { setTo(other); diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h index ace0243f3314..10eef06cd020 100644 --- a/libutils/include/utils/String8.h +++ b/libutils/include/utils/String8.h @@ -64,6 +64,7 @@ class String8 inline size_t size() const; inline size_t bytes() const; + inline bool empty() const; inline bool isEmpty() const; size_t length() const; @@ -257,6 +258,11 @@ inline size_t String8::size() const return length(); } +inline bool String8::empty() const +{ + return length() == 0; +} + inline bool String8::isEmpty() const { return length() == 0; From f59712928233f6abadd888e7d014b6fa4a20e932 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Mon, 14 Aug 2023 18:18:26 +0000 Subject: [PATCH 0332/1487] Migrate from android::String isEmpty to empty This empty method is different from the old one - it aligns with std::string definition. Bug: 295394788 Test: make checkbuild Change-Id: Id6baed8cde01a75a8839ad6b4475a31ba1f49c8a --- healthd/BatteryMonitor.cpp | 142 +++++++++++++++++----------------- healthd/BatteryMonitor_v1.cpp | 100 ++++++++++++------------ libutils/String8_fuzz.cpp | 2 +- 3 files changed, 122 insertions(+), 122 deletions(-) diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp index 15c30be412f8..e4cf582fbdcf 100644 --- a/healthd/BatteryMonitor.cpp +++ b/healthd/BatteryMonitor.cpp @@ -361,7 +361,7 @@ static bool isScopedPowerSupply(const char* name) { void BatteryMonitor::updateValues(void) { initHealthInfo(mHealthInfo.get()); - if (!mHealthdConfig->batteryPresentPath.isEmpty()) + if (!mHealthdConfig->batteryPresentPath.empty()) mHealthInfo->batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath); else mHealthInfo->batteryPresent = mBatteryDevicePresent; @@ -371,43 +371,43 @@ void BatteryMonitor::updateValues(void) { : getIntField(mHealthdConfig->batteryCapacityPath); mHealthInfo->batteryVoltageMillivolts = getIntField(mHealthdConfig->batteryVoltagePath) / 1000; - if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) + if (!mHealthdConfig->batteryCurrentNowPath.empty()) mHealthInfo->batteryCurrentMicroamps = getIntField(mHealthdConfig->batteryCurrentNowPath); - if (!mHealthdConfig->batteryFullChargePath.isEmpty()) + if (!mHealthdConfig->batteryFullChargePath.empty()) mHealthInfo->batteryFullChargeUah = getIntField(mHealthdConfig->batteryFullChargePath); - if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) + if (!mHealthdConfig->batteryCycleCountPath.empty()) mHealthInfo->batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath); - if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) + if (!mHealthdConfig->batteryChargeCounterPath.empty()) mHealthInfo->batteryChargeCounterUah = getIntField(mHealthdConfig->batteryChargeCounterPath); - if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) + if (!mHealthdConfig->batteryCurrentAvgPath.empty()) mHealthInfo->batteryCurrentAverageMicroamps = getIntField(mHealthdConfig->batteryCurrentAvgPath); - if (!mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty()) + if (!mHealthdConfig->batteryChargeTimeToFullNowPath.empty()) mHealthInfo->batteryChargeTimeToFullNowSeconds = getIntField(mHealthdConfig->batteryChargeTimeToFullNowPath); - if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty()) + if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty()) mHealthInfo->batteryFullChargeDesignCapacityUah = getIntField(mHealthdConfig->batteryFullChargeDesignCapacityUahPath); - if (!mHealthdConfig->batteryHealthStatusPath.isEmpty()) + if (!mHealthdConfig->batteryHealthStatusPath.empty()) mBatteryHealthStatus = getIntField(mHealthdConfig->batteryHealthStatusPath); - if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty()) + if (!mHealthdConfig->batteryStateOfHealthPath.empty()) mHealthInfo->batteryHealthData->batteryStateOfHealth = getIntField(mHealthdConfig->batteryStateOfHealthPath); - if (!mHealthdConfig->batteryManufacturingDatePath.isEmpty()) + if (!mHealthdConfig->batteryManufacturingDatePath.empty()) mHealthInfo->batteryHealthData->batteryManufacturingDateSeconds = getIntField(mHealthdConfig->batteryManufacturingDatePath); - if (!mHealthdConfig->batteryFirstUsageDatePath.isEmpty()) + if (!mHealthdConfig->batteryFirstUsageDatePath.empty()) mHealthInfo->batteryHealthData->batteryFirstUsageSeconds = getIntField(mHealthdConfig->batteryFirstUsageDatePath); @@ -506,17 +506,17 @@ static void doLogValues(const HealthInfo& props, const struct healthd_config& he props.batteryStatus); len = strlen(dmesgline); - if (!healthd_config.batteryCurrentNowPath.isEmpty()) { + if (!healthd_config.batteryCurrentNowPath.empty()) { len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " c=%d", props.batteryCurrentMicroamps); } - if (!healthd_config.batteryFullChargePath.isEmpty()) { + if (!healthd_config.batteryFullChargePath.empty()) { len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " fc=%d", props.batteryFullChargeUah); } - if (!healthd_config.batteryCycleCountPath.isEmpty()) { + if (!healthd_config.batteryCycleCountPath.empty()) { len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " cc=%d", props.batteryCycleCount); } @@ -550,7 +550,7 @@ bool BatteryMonitor::isChargerOnline() { int BatteryMonitor::getChargeStatus() { BatteryStatus result = BatteryStatus::UNKNOWN; - if (!mHealthdConfig->batteryStatusPath.isEmpty()) { + if (!mHealthdConfig->batteryStatusPath.empty()) { std::string buf; if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0) result = getBatteryStatus(buf.c_str()); @@ -561,7 +561,7 @@ int BatteryMonitor::getChargeStatus() { status_t BatteryMonitor::setChargingPolicy(int value) { status_t ret = NAME_NOT_FOUND; bool result; - if (!mHealthdConfig->chargingPolicyPath.isEmpty()) { + if (!mHealthdConfig->chargingPolicyPath.empty()) { result = writeToFile(mHealthdConfig->chargingPolicyPath, value); if (!result) { KLOG_WARNING(LOG_TAG, "setChargingPolicy fail\n"); @@ -575,7 +575,7 @@ status_t BatteryMonitor::setChargingPolicy(int value) { int BatteryMonitor::getChargingPolicy() { BatteryChargingPolicy result = BatteryChargingPolicy::DEFAULT; - if (!mHealthdConfig->chargingPolicyPath.isEmpty()) { + if (!mHealthdConfig->chargingPolicyPath.empty()) { std::string buf; if (readFromFile(mHealthdConfig->chargingPolicyPath, &buf) > 0) result = getBatteryChargingPolicy(buf.c_str()); @@ -585,15 +585,15 @@ int BatteryMonitor::getChargingPolicy() { int BatteryMonitor::getBatteryHealthData(int id) { if (id == BATTERY_PROP_MANUFACTURING_DATE) { - if (!mHealthdConfig->batteryManufacturingDatePath.isEmpty()) + if (!mHealthdConfig->batteryManufacturingDatePath.empty()) return getIntField(mHealthdConfig->batteryManufacturingDatePath); } if (id == BATTERY_PROP_FIRST_USAGE_DATE) { - if (!mHealthdConfig->batteryFirstUsageDatePath.isEmpty()) + if (!mHealthdConfig->batteryFirstUsageDatePath.empty()) return getIntField(mHealthdConfig->batteryFirstUsageDatePath); } if (id == BATTERY_PROP_STATE_OF_HEALTH) { - if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty()) + if (!mHealthdConfig->batteryStateOfHealthPath.empty()) return getIntField(mHealthdConfig->batteryStateOfHealthPath); } return 0; @@ -607,7 +607,7 @@ status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { switch(id) { case BATTERY_PROP_CHARGE_COUNTER: - if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) { + if (!mHealthdConfig->batteryChargeCounterPath.empty()) { val->valueInt64 = getIntField(mHealthdConfig->batteryChargeCounterPath); ret = OK; @@ -617,7 +617,7 @@ status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { break; case BATTERY_PROP_CURRENT_NOW: - if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { + if (!mHealthdConfig->batteryCurrentNowPath.empty()) { val->valueInt64 = getIntField(mHealthdConfig->batteryCurrentNowPath); ret = OK; @@ -627,7 +627,7 @@ status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { break; case BATTERY_PROP_CURRENT_AVG: - if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) { + if (!mHealthdConfig->batteryCurrentAvgPath.empty()) { val->valueInt64 = getIntField(mHealthdConfig->batteryCurrentAvgPath); ret = OK; @@ -637,7 +637,7 @@ status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { break; case BATTERY_PROP_CAPACITY: - if (!mHealthdConfig->batteryCapacityPath.isEmpty()) { + if (!mHealthdConfig->batteryCapacityPath.empty()) { val->valueInt64 = getIntField(mHealthdConfig->batteryCapacityPath); ret = OK; @@ -704,35 +704,35 @@ void BatteryMonitor::dumpState(int fd) { props.batteryVoltageMillivolts, props.batteryTemperatureTenthsCelsius); write(fd, vs, strlen(vs)); - if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { + if (!mHealthdConfig->batteryCurrentNowPath.empty()) { v = getIntField(mHealthdConfig->batteryCurrentNowPath); snprintf(vs, sizeof(vs), "current now: %d\n", v); write(fd, vs, strlen(vs)); } - if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) { + if (!mHealthdConfig->batteryCurrentAvgPath.empty()) { v = getIntField(mHealthdConfig->batteryCurrentAvgPath); snprintf(vs, sizeof(vs), "current avg: %d\n", v); write(fd, vs, strlen(vs)); } - if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) { + if (!mHealthdConfig->batteryChargeCounterPath.empty()) { v = getIntField(mHealthdConfig->batteryChargeCounterPath); snprintf(vs, sizeof(vs), "charge counter: %d\n", v); write(fd, vs, strlen(vs)); } - if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { + if (!mHealthdConfig->batteryCurrentNowPath.empty()) { snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrentMicroamps); write(fd, vs, strlen(vs)); } - if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) { + if (!mHealthdConfig->batteryCycleCountPath.empty()) { snprintf(vs, sizeof(vs), "cycle count: %d\n", props.batteryCycleCount); write(fd, vs, strlen(vs)); } - if (!mHealthdConfig->batteryFullChargePath.isEmpty()) { + if (!mHealthdConfig->batteryFullChargePath.empty()) { snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullChargeUah); write(fd, vs, strlen(vs)); } @@ -782,7 +782,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { if (isScopedPowerSupply(name)) continue; mBatteryDevicePresent = true; - if (mHealthdConfig->batteryStatusPath.isEmpty()) { + if (mHealthdConfig->batteryStatusPath.empty()) { path.clear(); path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH, name); @@ -790,7 +790,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryStatusPath = path; } - if (mHealthdConfig->batteryHealthPath.isEmpty()) { + if (mHealthdConfig->batteryHealthPath.empty()) { path.clear(); path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH, name); @@ -798,7 +798,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryHealthPath = path; } - if (mHealthdConfig->batteryPresentPath.isEmpty()) { + if (mHealthdConfig->batteryPresentPath.empty()) { path.clear(); path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH, name); @@ -806,7 +806,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryPresentPath = path; } - if (mHealthdConfig->batteryCapacityPath.isEmpty()) { + if (mHealthdConfig->batteryCapacityPath.empty()) { path.clear(); path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH, name); @@ -814,7 +814,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryCapacityPath = path; } - if (mHealthdConfig->batteryVoltagePath.isEmpty()) { + if (mHealthdConfig->batteryVoltagePath.empty()) { path.clear(); path.appendFormat("%s/%s/voltage_now", POWER_SUPPLY_SYSFS_PATH, name); @@ -823,7 +823,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { } } - if (mHealthdConfig->batteryFullChargePath.isEmpty()) { + if (mHealthdConfig->batteryFullChargePath.empty()) { path.clear(); path.appendFormat("%s/%s/charge_full", POWER_SUPPLY_SYSFS_PATH, name); @@ -831,7 +831,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryFullChargePath = path; } - if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) { + if (mHealthdConfig->batteryCurrentNowPath.empty()) { path.clear(); path.appendFormat("%s/%s/current_now", POWER_SUPPLY_SYSFS_PATH, name); @@ -839,7 +839,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryCurrentNowPath = path; } - if (mHealthdConfig->batteryCycleCountPath.isEmpty()) { + if (mHealthdConfig->batteryCycleCountPath.empty()) { path.clear(); path.appendFormat("%s/%s/cycle_count", POWER_SUPPLY_SYSFS_PATH, name); @@ -847,27 +847,27 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryCycleCountPath = path; } - if (mHealthdConfig->batteryCapacityLevelPath.isEmpty()) { + if (mHealthdConfig->batteryCapacityLevelPath.empty()) { path.clear(); path.appendFormat("%s/%s/capacity_level", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryCapacityLevelPath = path; } - if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty()) { + if (mHealthdConfig->batteryChargeTimeToFullNowPath.empty()) { path.clear(); path.appendFormat("%s/%s/time_to_full_now", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryChargeTimeToFullNowPath = path; } - if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty()) { + if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty()) { path.clear(); path.appendFormat("%s/%s/charge_full_design", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryFullChargeDesignCapacityUahPath = path; } - if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) { + if (mHealthdConfig->batteryCurrentAvgPath.empty()) { path.clear(); path.appendFormat("%s/%s/current_avg", POWER_SUPPLY_SYSFS_PATH, name); @@ -875,7 +875,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryCurrentAvgPath = path; } - if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) { + if (mHealthdConfig->batteryChargeCounterPath.empty()) { path.clear(); path.appendFormat("%s/%s/charge_counter", POWER_SUPPLY_SYSFS_PATH, name); @@ -883,7 +883,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryChargeCounterPath = path; } - if (mHealthdConfig->batteryTemperaturePath.isEmpty()) { + if (mHealthdConfig->batteryTemperaturePath.empty()) { path.clear(); path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH, name); @@ -892,7 +892,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { } } - if (mHealthdConfig->batteryTechnologyPath.isEmpty()) { + if (mHealthdConfig->batteryTechnologyPath.empty()) { path.clear(); path.appendFormat("%s/%s/technology", POWER_SUPPLY_SYSFS_PATH, name); @@ -900,7 +900,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryTechnologyPath = path; } - if (mHealthdConfig->batteryStateOfHealthPath.isEmpty()) { + if (mHealthdConfig->batteryStateOfHealthPath.empty()) { path.clear(); path.appendFormat("%s/%s/state_of_health", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) { @@ -913,32 +913,32 @@ void BatteryMonitor::init(struct healthd_config *hc) { } } - if (mHealthdConfig->batteryHealthStatusPath.isEmpty()) { + if (mHealthdConfig->batteryHealthStatusPath.empty()) { path.clear(); path.appendFormat("%s/%s/health_status", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryHealthStatusPath = path; } - if (mHealthdConfig->batteryManufacturingDatePath.isEmpty()) { + if (mHealthdConfig->batteryManufacturingDatePath.empty()) { path.clear(); path.appendFormat("%s/%s/manufacturing_date", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryManufacturingDatePath = path; } - if (mHealthdConfig->batteryFirstUsageDatePath.isEmpty()) { + if (mHealthdConfig->batteryFirstUsageDatePath.empty()) { path.clear(); path.appendFormat("%s/%s/first_usage_date", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryFirstUsageDatePath = path; } - if (mHealthdConfig->chargingStatePath.isEmpty()) { + if (mHealthdConfig->chargingStatePath.empty()) { path.clear(); path.appendFormat("%s/%s/charging_state", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->chargingStatePath = path; } - if (mHealthdConfig->chargingPolicyPath.isEmpty()) { + if (mHealthdConfig->chargingPolicyPath.empty()) { path.clear(); path.appendFormat("%s/%s/charging_policy", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->chargingPolicyPath = path; @@ -968,43 +968,43 @@ void BatteryMonitor::init(struct healthd_config *hc) { hc->periodic_chores_interval_fast = -1; hc->periodic_chores_interval_slow = -1; } else { - if (mHealthdConfig->batteryStatusPath.isEmpty()) + if (mHealthdConfig->batteryStatusPath.empty()) KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n"); - if (mHealthdConfig->batteryHealthPath.isEmpty()) + if (mHealthdConfig->batteryHealthPath.empty()) KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n"); - if (mHealthdConfig->batteryPresentPath.isEmpty()) + if (mHealthdConfig->batteryPresentPath.empty()) KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n"); - if (mHealthdConfig->batteryCapacityPath.isEmpty()) + if (mHealthdConfig->batteryCapacityPath.empty()) KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n"); - if (mHealthdConfig->batteryVoltagePath.isEmpty()) + if (mHealthdConfig->batteryVoltagePath.empty()) KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n"); - if (mHealthdConfig->batteryTemperaturePath.isEmpty()) + if (mHealthdConfig->batteryTemperaturePath.empty()) KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n"); - if (mHealthdConfig->batteryTechnologyPath.isEmpty()) + if (mHealthdConfig->batteryTechnologyPath.empty()) KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n"); - if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) + if (mHealthdConfig->batteryCurrentNowPath.empty()) KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n"); - if (mHealthdConfig->batteryFullChargePath.isEmpty()) + if (mHealthdConfig->batteryFullChargePath.empty()) KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n"); - if (mHealthdConfig->batteryCycleCountPath.isEmpty()) + if (mHealthdConfig->batteryCycleCountPath.empty()) KLOG_WARNING(LOG_TAG, "BatteryCycleCountPath not found\n"); - if (mHealthdConfig->batteryCapacityLevelPath.isEmpty()) + if (mHealthdConfig->batteryCapacityLevelPath.empty()) KLOG_WARNING(LOG_TAG, "batteryCapacityLevelPath not found\n"); - if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty()) + if (mHealthdConfig->batteryChargeTimeToFullNowPath.empty()) KLOG_WARNING(LOG_TAG, "batteryChargeTimeToFullNowPath. not found\n"); - if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty()) + if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty()) KLOG_WARNING(LOG_TAG, "batteryFullChargeDesignCapacityUahPath. not found\n"); - if (mHealthdConfig->batteryStateOfHealthPath.isEmpty()) + if (mHealthdConfig->batteryStateOfHealthPath.empty()) KLOG_WARNING(LOG_TAG, "batteryStateOfHealthPath not found\n"); - if (mHealthdConfig->batteryHealthStatusPath.isEmpty()) + if (mHealthdConfig->batteryHealthStatusPath.empty()) KLOG_WARNING(LOG_TAG, "batteryHealthStatusPath not found\n"); - if (mHealthdConfig->batteryManufacturingDatePath.isEmpty()) + if (mHealthdConfig->batteryManufacturingDatePath.empty()) KLOG_WARNING(LOG_TAG, "batteryManufacturingDatePath not found\n"); - if (mHealthdConfig->batteryFirstUsageDatePath.isEmpty()) + if (mHealthdConfig->batteryFirstUsageDatePath.empty()) KLOG_WARNING(LOG_TAG, "batteryFirstUsageDatePath not found\n"); - if (mHealthdConfig->chargingStatePath.isEmpty()) + if (mHealthdConfig->chargingStatePath.empty()) KLOG_WARNING(LOG_TAG, "chargingStatePath not found\n"); - if (mHealthdConfig->chargingPolicyPath.isEmpty()) + if (mHealthdConfig->chargingPolicyPath.empty()) KLOG_WARNING(LOG_TAG, "chargingPolicyPath not found\n"); } diff --git a/healthd/BatteryMonitor_v1.cpp b/healthd/BatteryMonitor_v1.cpp index b2d6518f7a29..686c338cc10e 100644 --- a/healthd/BatteryMonitor_v1.cpp +++ b/healthd/BatteryMonitor_v1.cpp @@ -301,7 +301,7 @@ static bool isScopedPowerSupply(const char* name) { void BatteryMonitor::updateValues(void) { initHealthInfo(mHealthInfo.get()); - if (!mHealthdConfig->batteryPresentPath.isEmpty()) + if (!mHealthdConfig->batteryPresentPath.empty()) mHealthInfo->batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath); else mHealthInfo->batteryPresent = mBatteryDevicePresent; @@ -311,28 +311,28 @@ void BatteryMonitor::updateValues(void) { : getIntField(mHealthdConfig->batteryCapacityPath); mHealthInfo->batteryVoltageMillivolts = getIntField(mHealthdConfig->batteryVoltagePath) / 1000; - if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) + if (!mHealthdConfig->batteryCurrentNowPath.empty()) mHealthInfo->batteryCurrentMicroamps = getIntField(mHealthdConfig->batteryCurrentNowPath); - if (!mHealthdConfig->batteryFullChargePath.isEmpty()) + if (!mHealthdConfig->batteryFullChargePath.empty()) mHealthInfo->batteryFullChargeUah = getIntField(mHealthdConfig->batteryFullChargePath); - if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) + if (!mHealthdConfig->batteryCycleCountPath.empty()) mHealthInfo->batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath); - if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) + if (!mHealthdConfig->batteryChargeCounterPath.empty()) mHealthInfo->batteryChargeCounterUah = getIntField(mHealthdConfig->batteryChargeCounterPath); - if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) + if (!mHealthdConfig->batteryCurrentAvgPath.empty()) mHealthInfo->batteryCurrentAverageMicroamps = getIntField(mHealthdConfig->batteryCurrentAvgPath); - if (!mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty()) + if (!mHealthdConfig->batteryChargeTimeToFullNowPath.empty()) mHealthInfo->batteryChargeTimeToFullNowSeconds = getIntField(mHealthdConfig->batteryChargeTimeToFullNowPath); - if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty()) + if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty()) mHealthInfo->batteryFullChargeDesignCapacityUah = getIntField(mHealthdConfig->batteryFullChargeDesignCapacityUahPath); @@ -420,17 +420,17 @@ static void doLogValues(const HealthInfo& props, const struct healthd_config& he props.batteryStatus); len = strlen(dmesgline); - if (!healthd_config.batteryCurrentNowPath.isEmpty()) { + if (!healthd_config.batteryCurrentNowPath.empty()) { len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " c=%d", props.batteryCurrentMicroamps); } - if (!healthd_config.batteryFullChargePath.isEmpty()) { + if (!healthd_config.batteryFullChargePath.empty()) { len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " fc=%d", props.batteryFullChargeUah); } - if (!healthd_config.batteryCycleCountPath.isEmpty()) { + if (!healthd_config.batteryCycleCountPath.empty()) { len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " cc=%d", props.batteryCycleCount); } @@ -464,7 +464,7 @@ bool BatteryMonitor::isChargerOnline() { int BatteryMonitor::getChargeStatus() { BatteryStatus result = BatteryStatus::UNKNOWN; - if (!mHealthdConfig->batteryStatusPath.isEmpty()) { + if (!mHealthdConfig->batteryStatusPath.empty()) { std::string buf; if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0) result = getBatteryStatus(buf.c_str()); @@ -480,7 +480,7 @@ status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { switch(id) { case BATTERY_PROP_CHARGE_COUNTER: - if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) { + if (!mHealthdConfig->batteryChargeCounterPath.empty()) { val->valueInt64 = getIntField(mHealthdConfig->batteryChargeCounterPath); ret = OK; @@ -490,7 +490,7 @@ status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { break; case BATTERY_PROP_CURRENT_NOW: - if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { + if (!mHealthdConfig->batteryCurrentNowPath.empty()) { val->valueInt64 = getIntField(mHealthdConfig->batteryCurrentNowPath); ret = OK; @@ -500,7 +500,7 @@ status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { break; case BATTERY_PROP_CURRENT_AVG: - if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) { + if (!mHealthdConfig->batteryCurrentAvgPath.empty()) { val->valueInt64 = getIntField(mHealthdConfig->batteryCurrentAvgPath); ret = OK; @@ -510,7 +510,7 @@ status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { break; case BATTERY_PROP_CAPACITY: - if (!mHealthdConfig->batteryCapacityPath.isEmpty()) { + if (!mHealthdConfig->batteryCapacityPath.empty()) { val->valueInt64 = getIntField(mHealthdConfig->batteryCapacityPath); ret = OK; @@ -557,35 +557,35 @@ void BatteryMonitor::dumpState(int fd) { props.batteryVoltageMillivolts, props.batteryTemperatureTenthsCelsius); write(fd, vs, strlen(vs)); - if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { + if (!mHealthdConfig->batteryCurrentNowPath.empty()) { v = getIntField(mHealthdConfig->batteryCurrentNowPath); snprintf(vs, sizeof(vs), "current now: %d\n", v); write(fd, vs, strlen(vs)); } - if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) { + if (!mHealthdConfig->batteryCurrentAvgPath.empty()) { v = getIntField(mHealthdConfig->batteryCurrentAvgPath); snprintf(vs, sizeof(vs), "current avg: %d\n", v); write(fd, vs, strlen(vs)); } - if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) { + if (!mHealthdConfig->batteryChargeCounterPath.empty()) { v = getIntField(mHealthdConfig->batteryChargeCounterPath); snprintf(vs, sizeof(vs), "charge counter: %d\n", v); write(fd, vs, strlen(vs)); } - if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { + if (!mHealthdConfig->batteryCurrentNowPath.empty()) { snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrentMicroamps); write(fd, vs, strlen(vs)); } - if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) { + if (!mHealthdConfig->batteryCycleCountPath.empty()) { snprintf(vs, sizeof(vs), "cycle count: %d\n", props.batteryCycleCount); write(fd, vs, strlen(vs)); } - if (!mHealthdConfig->batteryFullChargePath.isEmpty()) { + if (!mHealthdConfig->batteryFullChargePath.empty()) { snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullChargeUah); write(fd, vs, strlen(vs)); } @@ -635,7 +635,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { if (isScopedPowerSupply(name)) continue; mBatteryDevicePresent = true; - if (mHealthdConfig->batteryStatusPath.isEmpty()) { + if (mHealthdConfig->batteryStatusPath.empty()) { path.clear(); path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH, name); @@ -643,7 +643,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryStatusPath = path; } - if (mHealthdConfig->batteryHealthPath.isEmpty()) { + if (mHealthdConfig->batteryHealthPath.empty()) { path.clear(); path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH, name); @@ -651,7 +651,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryHealthPath = path; } - if (mHealthdConfig->batteryPresentPath.isEmpty()) { + if (mHealthdConfig->batteryPresentPath.empty()) { path.clear(); path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH, name); @@ -659,7 +659,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryPresentPath = path; } - if (mHealthdConfig->batteryCapacityPath.isEmpty()) { + if (mHealthdConfig->batteryCapacityPath.empty()) { path.clear(); path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH, name); @@ -667,7 +667,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryCapacityPath = path; } - if (mHealthdConfig->batteryVoltagePath.isEmpty()) { + if (mHealthdConfig->batteryVoltagePath.empty()) { path.clear(); path.appendFormat("%s/%s/voltage_now", POWER_SUPPLY_SYSFS_PATH, name); @@ -676,7 +676,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { } } - if (mHealthdConfig->batteryFullChargePath.isEmpty()) { + if (mHealthdConfig->batteryFullChargePath.empty()) { path.clear(); path.appendFormat("%s/%s/charge_full", POWER_SUPPLY_SYSFS_PATH, name); @@ -684,7 +684,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryFullChargePath = path; } - if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) { + if (mHealthdConfig->batteryCurrentNowPath.empty()) { path.clear(); path.appendFormat("%s/%s/current_now", POWER_SUPPLY_SYSFS_PATH, name); @@ -692,7 +692,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryCurrentNowPath = path; } - if (mHealthdConfig->batteryCycleCountPath.isEmpty()) { + if (mHealthdConfig->batteryCycleCountPath.empty()) { path.clear(); path.appendFormat("%s/%s/cycle_count", POWER_SUPPLY_SYSFS_PATH, name); @@ -700,27 +700,27 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryCycleCountPath = path; } - if (mHealthdConfig->batteryCapacityLevelPath.isEmpty()) { + if (mHealthdConfig->batteryCapacityLevelPath.empty()) { path.clear(); path.appendFormat("%s/%s/capacity_level", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryCapacityLevelPath = path; } - if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty()) { + if (mHealthdConfig->batteryChargeTimeToFullNowPath.empty()) { path.clear(); path.appendFormat("%s/%s/time_to_full_now", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryChargeTimeToFullNowPath = path; } - if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty()) { + if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty()) { path.clear(); path.appendFormat("%s/%s/charge_full_design", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryFullChargeDesignCapacityUahPath = path; } - if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) { + if (mHealthdConfig->batteryCurrentAvgPath.empty()) { path.clear(); path.appendFormat("%s/%s/current_avg", POWER_SUPPLY_SYSFS_PATH, name); @@ -728,7 +728,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryCurrentAvgPath = path; } - if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) { + if (mHealthdConfig->batteryChargeCounterPath.empty()) { path.clear(); path.appendFormat("%s/%s/charge_counter", POWER_SUPPLY_SYSFS_PATH, name); @@ -736,7 +736,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { mHealthdConfig->batteryChargeCounterPath = path; } - if (mHealthdConfig->batteryTemperaturePath.isEmpty()) { + if (mHealthdConfig->batteryTemperaturePath.empty()) { path.clear(); path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH, name); @@ -745,7 +745,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { } } - if (mHealthdConfig->batteryTechnologyPath.isEmpty()) { + if (mHealthdConfig->batteryTechnologyPath.empty()) { path.clear(); path.appendFormat("%s/%s/technology", POWER_SUPPLY_SYSFS_PATH, name); @@ -777,31 +777,31 @@ void BatteryMonitor::init(struct healthd_config *hc) { hc->periodic_chores_interval_fast = -1; hc->periodic_chores_interval_slow = -1; } else { - if (mHealthdConfig->batteryStatusPath.isEmpty()) + if (mHealthdConfig->batteryStatusPath.empty()) KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n"); - if (mHealthdConfig->batteryHealthPath.isEmpty()) + if (mHealthdConfig->batteryHealthPath.empty()) KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n"); - if (mHealthdConfig->batteryPresentPath.isEmpty()) + if (mHealthdConfig->batteryPresentPath.empty()) KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n"); - if (mHealthdConfig->batteryCapacityPath.isEmpty()) + if (mHealthdConfig->batteryCapacityPath.empty()) KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n"); - if (mHealthdConfig->batteryVoltagePath.isEmpty()) + if (mHealthdConfig->batteryVoltagePath.empty()) KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n"); - if (mHealthdConfig->batteryTemperaturePath.isEmpty()) + if (mHealthdConfig->batteryTemperaturePath.empty()) KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n"); - if (mHealthdConfig->batteryTechnologyPath.isEmpty()) + if (mHealthdConfig->batteryTechnologyPath.empty()) KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n"); - if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) + if (mHealthdConfig->batteryCurrentNowPath.empty()) KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n"); - if (mHealthdConfig->batteryFullChargePath.isEmpty()) + if (mHealthdConfig->batteryFullChargePath.empty()) KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n"); - if (mHealthdConfig->batteryCycleCountPath.isEmpty()) + if (mHealthdConfig->batteryCycleCountPath.empty()) KLOG_WARNING(LOG_TAG, "BatteryCycleCountPath not found\n"); - if (mHealthdConfig->batteryCapacityLevelPath.isEmpty()) + if (mHealthdConfig->batteryCapacityLevelPath.empty()) KLOG_WARNING(LOG_TAG, "batteryCapacityLevelPath not found\n"); - if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty()) + if (mHealthdConfig->batteryChargeTimeToFullNowPath.empty()) KLOG_WARNING(LOG_TAG, "batteryChargeTimeToFullNowPath. not found\n"); - if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty()) + if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty()) KLOG_WARNING(LOG_TAG, "batteryFullChargeDesignCapacityUahPath. not found\n"); } diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp index e5dcd316ecb0..09dcacd8afc2 100644 --- a/libutils/String8_fuzz.cpp +++ b/libutils/String8_fuzz.cpp @@ -34,7 +34,7 @@ std::vectorbytes(); }, [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - str1->isEmpty(); + str1->empty(); }, [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { str1->length(); From d479afa0372598d1417fbd4ba7cd2459df1aed4a Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Fri, 18 Aug 2023 13:13:54 -0700 Subject: [PATCH 0333/1487] Load kernel modules from /lib/modules/`uname -r`_$(page_size) if present To support booting from both 4k/16k kernels, init need to tell which kernel we are currently booting and load the right modules. To resolve this issue, we store 16K modules into /lib/modules/`uname -r`_16k directory. Test: th Bug: 293313353 Change-Id: I4a8296384537a71e16cd20e76e6c5dfb9074f574 --- init/first_stage_init.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index 88300cb29c36..3239eb7ca203 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -153,6 +154,15 @@ void PrepareSwitchRoot() { Copy(snapuserd, dst); } } + +std::string GetPageSizeSuffix() { + static const size_t page_size = sysconf(_SC_PAGE_SIZE); + if (page_size <= 4096) { + return ""; + } + return android::base::StringPrintf("_%zuk", page_size / 1024); +} + } // namespace std::string GetModuleLoadList(BootMode boot_mode, const std::string& dir_path) { @@ -201,10 +211,18 @@ bool LoadKernelModules(BootMode boot_mode, bool want_console, bool want_parallel } dirent* entry = nullptr; std::vector module_dirs; + const std::string release_specific_module_dir = uts.release + GetPageSizeSuffix(); while ((entry = readdir(base_dir.get()))) { if (entry->d_type != DT_DIR) { continue; } + if (entry->d_name == release_specific_module_dir) { + LOG(INFO) << "Release specific kernel module dir " << release_specific_module_dir + << " found, loading modules from here with no fallbacks."; + module_dirs.clear(); + module_dirs.emplace_back(entry->d_name); + break; + } int dir_major = 0, dir_minor = 0; if (sscanf(entry->d_name, "%d.%d", &dir_major, &dir_minor) != 2 || dir_major != major || dir_minor != minor) { @@ -228,6 +246,7 @@ bool LoadKernelModules(BootMode boot_mode, bool want_console, bool want_parallel bool retval = m.LoadListedModules(!want_console); modules_loaded = m.GetModuleCount(); if (modules_loaded > 0) { + LOG(INFO) << "Loaded " << modules_loaded << " modules from " << dir_path; return retval; } } @@ -237,6 +256,7 @@ bool LoadKernelModules(BootMode boot_mode, bool want_console, bool want_parallel : m.LoadListedModules(!want_console); modules_loaded = m.GetModuleCount(); if (modules_loaded > 0) { + LOG(INFO) << "Loaded " << modules_loaded << " modules from " << MODULE_BASE_DIR; return retval; } return true; From 646e001bb5e232f38a79cc5ac3d9b4ed9c74ac65 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Mon, 21 Aug 2023 17:34:37 +0900 Subject: [PATCH 0334/1487] init: clean up DelayService() ServiceList's services_update_finished flag was overlapped with the global flag: is_default_mount_namespace_ready. Now DelayService() relies on the is_default_mount_namespace_ready flag. Add a service description with 'updatable' flag and invoke 'start ' in 'on init' block (which comes before APEX activation). See the log for "Cannot start an updatable service". Bug: 293535323 Test: see the comment Change-Id: I9341ba1a95d9b3b7c6081b530850d61f105f0a56 --- init/builtins.cpp | 3 +-- init/service.cpp | 4 ++-- init/service_list.cpp | 7 ++----- init/service_list.h | 9 ++------- 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/init/builtins.cpp b/init/builtins.cpp index a5b762cbb834..7715424f5162 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -1304,8 +1304,7 @@ static Result do_perform_apex_config(const BuiltinArguments& args) { } if (!bootstrap) { - // Now start delayed services - ServiceList::GetInstance().MarkServicesUpdate(); + ServiceList::GetInstance().StartDelayedServices(); } return {}; } diff --git a/init/service.cpp b/init/service.cpp index a0b3478c0b41..5e900ee4d0b0 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -420,7 +420,7 @@ Result Service::ExecStart() { } }); - if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) { + if (is_updatable() && !IsDefaultMountNamespaceReady()) { // Don't delay the service for ExecStart() as the semantic is that // the caller might depend on the side effect of the execution. return Error() << "Cannot start an updatable service '" << name_ @@ -581,7 +581,7 @@ Result Service::Start() { } }); - if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) { + if (is_updatable() && !IsDefaultMountNamespaceReady()) { ServiceList::GetInstance().DelayService(*this); return Error() << "Cannot start an updatable service '" << name_ << "' before configs from APEXes are all loaded. " diff --git a/init/service_list.cpp b/init/service_list.cpp index 937d82e20c6b..1c56e8a596c7 100644 --- a/init/service_list.cpp +++ b/init/service_list.cpp @@ -76,10 +76,7 @@ bool ServiceList::IsPostData() { return post_data_; } -void ServiceList::MarkServicesUpdate() { - services_update_finished_ = true; - - // start the delayed services +void ServiceList::StartDelayedServices() { for (const auto& name : delayed_service_names_) { Service* service = FindService(name); if (service == nullptr) { @@ -94,7 +91,7 @@ void ServiceList::MarkServicesUpdate() { } void ServiceList::DelayService(const Service& service) { - if (services_update_finished_) { + if (IsDefaultMountNamespaceReady()) { LOG(ERROR) << "Cannot delay the start of service '" << service.name() << "' because all services are already updated. Ignoring."; return; diff --git a/init/service_list.h b/init/service_list.h index f858bc37086f..44e84535cdab 100644 --- a/init/service_list.h +++ b/init/service_list.h @@ -85,14 +85,10 @@ class ServiceList { void MarkPostData(); bool IsPostData(); - void MarkServicesUpdate(); - bool IsServicesUpdated() const { return services_update_finished_; } void DelayService(const Service& service); + void StartDelayedServices(); - void ResetState() { - post_data_ = false; - services_update_finished_ = false; - } + void ResetState() { post_data_ = false; } auto size() const { return services_.size(); } @@ -100,7 +96,6 @@ class ServiceList { std::vector> services_; bool post_data_ = false; - bool services_update_finished_ = false; std::vector delayed_service_names_; }; From d6b65fb307fa38ad44fe4da38497d4f78fcdad7a Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Tue, 22 Aug 2023 09:59:26 +0900 Subject: [PATCH 0335/1487] init: reset errno in do_start do_start() ignores ENOENT intentionally to avoid logspam. It's implemented in ErrorIgnoreEnoent. However, without resetting errno, ErrorIgnoreEnoent will ignore unrelated errors from Service::Start() due to the sticking errono set from other commands. Bug: 296821716 Test: launch_cvd Change-Id: I71d3113bdb69bdca82e2ff4f3a793301749f6c08 --- init/builtins.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/init/builtins.cpp b/init/builtins.cpp index 7715424f5162..a70e86683f52 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -746,6 +746,7 @@ static Result do_setrlimit(const BuiltinArguments& args) { static Result do_start(const BuiltinArguments& args) { Service* svc = ServiceList::GetInstance().FindService(args[1]); if (!svc) return Error() << "service " << args[1] << " not found"; + errno = 0; if (auto result = svc->Start(); !result.ok()) { return ErrorIgnoreEnoent() << "Could not start service: " << result.error(); } From e10d8405a2ec05d5e81dcaa5cdd645a072100989 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Tue, 25 Jul 2023 14:50:18 -0700 Subject: [PATCH 0336/1487] libprocessgroup: fix reset of file_v2_name ProfileAttribute::Reset does not reset file_v2_name, fix that. Also provide ProfileAttribute::file_name() to consolidate the code. Bug: 292636609 Signed-off-by: Suren Baghdasaryan (cherry picked from commit 2ffbeaef3a926b0b5fd873136588deb3ec61ef96) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:72254810d9d63f8267d32d251456a78cd4891698) Merged-In: I5b33ca47b4fa5cabf582c8804bd13f72f6e58411 Change-Id: I5b33ca47b4fa5cabf582c8804bd13f72f6e58411 --- libprocessgroup/task_profiles.cpp | 22 +++++++++++++--------- libprocessgroup/task_profiles.h | 8 +++++--- libprocessgroup/task_profiles_test.cpp | 7 +++---- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 44dba2a16694..59b135013326 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -114,9 +114,16 @@ bool FdCacheHelper::IsAppDependentPath(const std::string& path) { IProfileAttribute::~IProfileAttribute() = default; -void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name) { +const std::string& ProfileAttribute::file_name() const { + if (controller()->version() == 2 && !file_v2_name_.empty()) return file_v2_name_; + return file_name_; +} + +void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) { controller_ = controller; file_name_ = file_name; + file_v2_name_ = file_v2_name; } bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { @@ -129,12 +136,11 @@ bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { return true; } - const std::string& file_name = - controller()->version() == 2 && !file_v2_name_.empty() ? file_v2_name_ : file_name_; if (subgroup.empty()) { - *path = StringPrintf("%s/%s", controller()->path(), file_name.c_str()); + *path = StringPrintf("%s/%s", controller()->path(), file_name().c_str()); } else { - *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(), file_name.c_str()); + *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(), + file_name().c_str()); } return true; } @@ -144,9 +150,7 @@ bool ProfileAttribute::GetPathForUID(uid_t uid, std::string* path) const { 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()); + *path = StringPrintf("%s/uid_%u/%s", controller()->path(), uid, file_name().c_str()); return true; } @@ -816,7 +820,7 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { attributes_[name] = std::make_unique(controller, file_attr, file_v2_attr); } else { - iter->second->Reset(controller, file_attr); + iter->second->Reset(controller, file_attr, file_v2_attr); } } else { LOG(WARNING) << "Controller " << controller_name << " is not found"; diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index a62c5b0a9e8c..ac8918e650fc 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -32,7 +32,8 @@ class IProfileAttribute { public: virtual ~IProfileAttribute() = 0; - virtual void Reset(const CgroupController& controller, const std::string& file_name) = 0; + virtual void Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) = 0; virtual const CgroupController* controller() const = 0; virtual const std::string& file_name() const = 0; virtual bool GetPathForTask(int tid, std::string* path) const = 0; @@ -50,8 +51,9 @@ class ProfileAttribute : public IProfileAttribute { ~ProfileAttribute() = default; const CgroupController* controller() const override { return &controller_; } - const std::string& file_name() const override { return file_name_; } - void Reset(const CgroupController& controller, const std::string& file_name) override; + const std::string& file_name() const override; + void Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) override; bool GetPathForTask(int tid, std::string* path) const override; bool GetPathForUID(uid_t uid, std::string* path) const override; diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp index eadbe7697b07..da74bb012f8f 100644 --- a/libprocessgroup/task_profiles_test.cpp +++ b/libprocessgroup/task_profiles_test.cpp @@ -102,7 +102,8 @@ class ProfileAttributeMock : public IProfileAttribute { public: ProfileAttributeMock(const std::string& file_name) : file_name_(file_name) {} ~ProfileAttributeMock() override = default; - void Reset(const CgroupController& controller, const std::string& file_name) override { + void Reset(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) override { CHECK(false); } const CgroupController* controller() const override { @@ -125,9 +126,7 @@ class ProfileAttributeMock : public IProfileAttribute { return true; }; - bool GetPathForUID(uid_t, std::string*) const override { - return false; - } + bool GetPathForUID(uid_t, std::string*) const override { return false; } private: const std::string file_name_; From cfd2e50e2db63e98e18418b1ec63eb9272a7425a Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Tue, 25 Jul 2023 15:45:45 -0700 Subject: [PATCH 0337/1487] libprocessgroup: optimize SetAttributeAction::ExecuteForProcess performance Current implementation of SetAttributeAction::ExecuteForProcess reuses SetAttributeAction::ExecuteForTask while not utilizing available uid/pid information. This results in a call to GetPathForTask() which is an expensive function due to it reading and parsing /proc/$pid/cgroups. This can be avoided if we utilize available uid/pid info and the fact that cgroup v2 attributes share the cgroup v2 hierarchy as process groups, which use a known path template. Bug: 292636609 Signed-off-by: Suren Baghdasaryan (cherry picked from commit 961c01ce23bb886583ca8cac1640806346c09a7f) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:1e81ee13638c5ca03157db674009d4cf7c2a1263) Merged-In: I02e3046bd85d0dfebc68ab444f1796bb54cc69c7 Change-Id: I02e3046bd85d0dfebc68ab444f1796bb54cc69c7 --- libprocessgroup/task_profiles.cpp | 45 +++++++++++++++++++------- libprocessgroup/task_profiles.h | 4 +++ libprocessgroup/task_profiles_test.cpp | 3 ++ 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 59b135013326..f51b07671bf1 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -126,6 +126,16 @@ void ProfileAttribute::Reset(const CgroupController& controller, const std::stri file_v2_name_ = file_v2_name; } +bool ProfileAttribute::GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const { + if (controller()->version() == 2) { + // all cgroup v2 attributes use the same process group hierarchy + *path = StringPrintf("%s/uid_%u/pid_%d/%s", controller()->path(), uid, pid, + file_name().c_str()); + return true; + } + return GetPathForTask(pid, path); +} + bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { std::string subgroup; if (!controller()->GetTaskGroup(tid, &subgroup)) { @@ -209,18 +219,7 @@ bool SetTimerSlackAction::ExecuteForTask(int) const { #endif -bool SetAttributeAction::ExecuteForProcess(uid_t, pid_t pid) const { - return ExecuteForTask(pid); -} - -bool SetAttributeAction::ExecuteForTask(int tid) const { - std::string path; - - if (!attribute_->GetPathForTask(tid, &path)) { - LOG(ERROR) << "Failed to find cgroup for tid " << tid; - return false; - } - +bool SetAttributeAction::WriteValueToFile(const std::string& path) const { if (!WriteStringToFile(value_, path)) { if (access(path.c_str(), F_OK) < 0) { if (optional_) { @@ -240,6 +239,28 @@ bool SetAttributeAction::ExecuteForTask(int tid) const { return true; } +bool SetAttributeAction::ExecuteForProcess(uid_t uid, pid_t pid) const { + std::string path; + + if (!attribute_->GetPathForProcess(uid, pid, &path)) { + LOG(ERROR) << "Failed to find cgroup for uid " << uid << " pid " << pid; + return false; + } + + return WriteValueToFile(path); +} + +bool SetAttributeAction::ExecuteForTask(int tid) const { + std::string path; + + if (!attribute_->GetPathForTask(tid, &path)) { + LOG(ERROR) << "Failed to find cgroup for tid " << tid; + return false; + } + + return WriteValueToFile(path); +} + bool SetAttributeAction::ExecuteForUID(uid_t uid) const { std::string path; diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index ac8918e650fc..4663f64e2a7e 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -36,6 +36,7 @@ class IProfileAttribute { const std::string& file_v2_name) = 0; virtual const CgroupController* controller() const = 0; virtual const std::string& file_name() const = 0; + virtual bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const = 0; virtual bool GetPathForTask(int tid, std::string* path) const = 0; virtual bool GetPathForUID(uid_t uid, std::string* path) const = 0; }; @@ -55,6 +56,7 @@ class ProfileAttribute : public IProfileAttribute { void Reset(const CgroupController& controller, const std::string& file_name, const std::string& file_v2_name) override; + bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const override; bool GetPathForTask(int tid, std::string* path) const override; bool GetPathForUID(uid_t uid, std::string* path) const override; @@ -133,6 +135,8 @@ class SetAttributeAction : public ProfileAction { const IProfileAttribute* attribute_; std::string value_; bool optional_; + + bool WriteValueToFile(const std::string& path) const; }; // Set cgroup profile element diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp index da74bb012f8f..99d819a7cc4c 100644 --- a/libprocessgroup/task_profiles_test.cpp +++ b/libprocessgroup/task_profiles_test.cpp @@ -111,6 +111,9 @@ class ProfileAttributeMock : public IProfileAttribute { return {}; } const std::string& file_name() const override { return file_name_; } + bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const override { + return GetPathForTask(pid, path); + } bool GetPathForTask(int tid, std::string* path) const override { #ifdef __ANDROID__ CHECK(CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, path)); From d35715c0210b6bdb7010968a445f1fe0eb521d98 Mon Sep 17 00:00:00 2001 From: Alessio Balsini Date: Tue, 22 Aug 2023 10:02:19 +0100 Subject: [PATCH 0338/1487] Update bug component from Android Systems to OTA client It's been a while since the Android Systems bug component does not access the creation of new bugs for triage, instead, new bugs must be created in the subcomponents of the team. This change updates the bug component originally associated to this subsystem from the Android Systems' 30545 to OTA client's 1014951. Test: none Bug: 270571229 Change-Id: I5455086bf777dd20abb2e2f0360f76a003120126 Signed-off-by: Alessio Balsini --- fs_mgr/libsnapshot/OWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs_mgr/libsnapshot/OWNERS b/fs_mgr/libsnapshot/OWNERS index 1ee4175cffca..c8b1003779bf 100644 --- a/fs_mgr/libsnapshot/OWNERS +++ b/fs_mgr/libsnapshot/OWNERS @@ -1,4 +1,4 @@ -# Bug component: 30545 +# Bug component: 1014951 balsini@google.com dvander@google.com elsk@google.com From 2326e056bdb699d6ce11653d515cecff6f636da3 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 22 Aug 2023 14:23:37 -0700 Subject: [PATCH 0339/1487] Add documentation to README adding documentation on how to use fastboot-info inside of fastboot README Test: na Bug: 297084293 Change-Id: Ic2d17c92a776f1cae9ef80f6b615ddbc841afb74 --- fastboot/README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/fastboot/README.md b/fastboot/README.md index 63db5c38bf2d..55583eb0efc0 100644 --- a/fastboot/README.md +++ b/fastboot/README.md @@ -165,6 +165,28 @@ The various currently defined commands are: using the new bootloader. +## Flashing Logic + +Fastboot binary will follow directions listed out fastboot-info.txt +build artifact for fastboot flashall && fastboot update comamnds. +This build artifact will live inside of ANDROID_PRODUCT_OUT && +target_files_package && updatepackage. + + +The currently defined commands are: + + flash %s Flash a given partition. Optional arguments include + --slot-other, {filename_path}, --apply-vbmeta + + reboot %s Reboot to either bootloader or fastbootd + + update-super Updates the super partition + + if-wipe Conditionally run some other functionality if + wipe is specified + + erase %s Erase a given partition (can only be used in conjunction) + with if-wipe -> eg. if-wipe erase cache ## Client Variables From b497e6f317e66e5dcfa4d3ed08c6e563c66e7a2a Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 22 Aug 2023 09:41:09 -0700 Subject: [PATCH 0340/1487] Fix one liner Ensuring that the expression is evaluated before being outputed. In response to comment from aosp/2708333 Test: th Change-Id: I073c143f1c4e32af11e235ce782947b250117dc5 --- fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp index d3c3d59a7f25..ee445a2d0c16 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp @@ -174,7 +174,7 @@ void CowWriterV2::InitBatchWrites() { current_data_pos_ = next_data_pos_; } - LOG_INFO << "Batch writes: " << batch_write_ ? "enabled" : "disabled"; + LOG_INFO << "Batch writes: " << (batch_write_ ? "enabled" : "disabled"); } void CowWriterV2::InitWorkers() { From eb70926ad6c344a61ecbad5bc326dfaac6fe184b Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 22 Aug 2023 16:49:25 -0700 Subject: [PATCH 0341/1487] Add unit test for cow compressor performance Adding test to measure performance differences between cow compression algorithms + levels. This gives us an easy way to test performance between the tunables without having to run an OTA every time. Ultimately we want this to be separate from cow_api_test so it would be nice to have this be it's own binary. Can add some tests for decompression + compressing from a part of an actual img file too. Test: m cow_benchmark Change-Id: Iba92ae3c0b2ad4ff6f842556b701b223d7d37823 --- .../include/libsnapshot/cow_compress.h | 1 - fs_mgr/libsnapshot/tools/Android.bp | 22 ++ fs_mgr/libsnapshot/tools/cow_benchmark.cpp | 188 ++++++++++++++++++ 3 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 fs_mgr/libsnapshot/tools/Android.bp create mode 100644 fs_mgr/libsnapshot/tools/cow_benchmark.cpp diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h index 97974c414524..cf6561559574 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h @@ -17,7 +17,6 @@ #pragma once #include -#include #include "libsnapshot/cow_format.h" namespace android { diff --git a/fs_mgr/libsnapshot/tools/Android.bp b/fs_mgr/libsnapshot/tools/Android.bp new file mode 100644 index 000000000000..cfa0cefe764c --- /dev/null +++ b/fs_mgr/libsnapshot/tools/Android.bp @@ -0,0 +1,22 @@ + +cc_binary { + name: "cow_benchmark", + host_supported: true, + defaults: [ + "fs_mgr_defaults", + "libsnapshot_cow_defaults", + ], + + srcs: ["cow_benchmark.cpp"], + + static_libs: [ + "libsnapshot_cow", + ], + + shared_libs: [ + "libbase", + "liblog", + ], + + cflags: ["-Werror"], +} diff --git a/fs_mgr/libsnapshot/tools/cow_benchmark.cpp b/fs_mgr/libsnapshot/tools/cow_benchmark.cpp new file mode 100644 index 000000000000..da2b87922927 --- /dev/null +++ b/fs_mgr/libsnapshot/tools/cow_benchmark.cpp @@ -0,0 +1,188 @@ + +#include + +#include +#include +#include + +#include +#include + +static const uint32_t BLOCK_SZ = 4096; +static const uint32_t SEED_NUMBER = 10; + +namespace android { +namespace snapshot { + +static std::string CompressionToString(CowCompression& compression) { + std::string output; + switch (compression.algorithm) { + case kCowCompressBrotli: + output.append("brotli"); + break; + case kCowCompressGz: + output.append("gz"); + break; + case kCowCompressLz4: + output.append("lz4"); + break; + case kCowCompressZstd: + output.append("zstd"); + break; + case kCowCompressNone: + return "No Compression"; + } + output.append(" " + std::to_string(compression.compression_level)); + return output; +} + +void OneShotCompressionTest() { + std::cout << "\n-------One Shot Compressor Perf Analysis-------\n"; + + std::vector compression_list = { + {kCowCompressLz4, 0}, {kCowCompressBrotli, 1}, {kCowCompressBrotli, 3}, + {kCowCompressBrotli, 11}, {kCowCompressZstd, 3}, {kCowCompressZstd, 6}, + {kCowCompressZstd, 9}, {kCowCompressZstd, 22}, {kCowCompressGz, 1}, + {kCowCompressGz, 3}, {kCowCompressGz, 6}, {kCowCompressGz, 9}}; + std::vector> compressors; + for (auto i : compression_list) { + compressors.emplace_back(ICompressor::Create(i, BLOCK_SZ)); + } + + // Allocate a buffer of size 8 blocks. + std::array buffer; + + // Generate a random 4k buffer of characters + std::default_random_engine gen(SEED_NUMBER); + std::uniform_int_distribution distribution(0, 10); + for (int i = 0; i < buffer.size(); i++) { + buffer[i] = static_cast(distribution(gen)); + } + + std::vector> latencies; + std::vector> ratios; + + for (size_t i = 0; i < compressors.size(); i++) { + const auto start = std::chrono::steady_clock::now(); + std::basic_string compressed_data = + compressors[i]->Compress(buffer.data(), buffer.size()); + const auto end = std::chrono::steady_clock::now(); + const auto latency = + std::chrono::duration_cast(end - start) / 1000.0; + const double compression_ratio = + static_cast(compressed_data.size()) * 1.00 / buffer.size(); + + std::cout << "Metrics for " << CompressionToString(compression_list[i]) << ": latency -> " + << latency.count() << "ms " + << " compression ratio ->" << compression_ratio << " \n"; + + latencies.emplace_back( + std::make_pair(latency.count(), CompressionToString(compression_list[i]))); + ratios.emplace_back( + std::make_pair(compression_ratio, CompressionToString(compression_list[i]))); + } + + int best_speed = 0; + int best_ratio = 0; + + for (size_t i = 1; i < latencies.size(); i++) { + if (latencies[i].first < latencies[best_speed].first) { + best_speed = i; + } + if (ratios[i].first < ratios[best_ratio].first) { + best_ratio = i; + } + } + + std::cout << "BEST SPEED: " << latencies[best_speed].first << "ms " + << latencies[best_speed].second << "\n"; + std::cout << "BEST RATIO: " << ratios[best_ratio].first << " " << ratios[best_ratio].second + << "\n"; +} + +void IncrementalCompressionTest() { + std::cout << "\n-------Incremental Compressor Perf Analysis-------\n"; + + std::vector compression_list = { + {kCowCompressLz4, 0}, {kCowCompressBrotli, 1}, {kCowCompressBrotli, 3}, + {kCowCompressBrotli, 11}, {kCowCompressZstd, 3}, {kCowCompressZstd, 6}, + {kCowCompressZstd, 9}, {kCowCompressZstd, 22}, {kCowCompressGz, 1}, + {kCowCompressGz, 3}, {kCowCompressGz, 6}, {kCowCompressGz, 9}}; + std::vector> compressors; + for (auto i : compression_list) { + compressors.emplace_back(ICompressor::Create(i, BLOCK_SZ)); + } + + // Allocate a buffer of size 8 blocks. + std::array buffer; + + // Generate a random 4k buffer of characters + std::default_random_engine gen(SEED_NUMBER); + std::uniform_int_distribution distribution(0, 10); + for (int i = 0; i < buffer.size(); i++) { + buffer[i] = static_cast(distribution(gen)); + } + + std::vector> latencies; + std::vector> ratios; + + for (size_t i = 0; i < compressors.size(); i++) { + std::vector> compressed_data_vec; + int num_blocks = buffer.size() / BLOCK_SZ; + const uint8_t* iter = reinterpret_cast(buffer.data()); + + const auto start = std::chrono::steady_clock::now(); + while (num_blocks > 0) { + std::basic_string compressed_data = compressors[i]->Compress(iter, BLOCK_SZ); + compressed_data_vec.emplace_back(compressed_data); + num_blocks--; + iter += BLOCK_SZ; + } + + const auto end = std::chrono::steady_clock::now(); + const auto latency = + std::chrono::duration_cast(end - start) / 1000.0; + + size_t size = 0; + for (auto& i : compressed_data_vec) { + size += i.size(); + } + const double compression_ratio = size * 1.00 / buffer.size(); + + std::cout << "Metrics for " << CompressionToString(compression_list[i]) << ": latency -> " + << latency.count() << "ms " + << " compression ratio ->" << compression_ratio << " \n"; + + latencies.emplace_back( + std::make_pair(latency.count(), CompressionToString(compression_list[i]))); + ratios.emplace_back( + std::make_pair(compression_ratio, CompressionToString(compression_list[i]))); + } + + int best_speed = 0; + int best_ratio = 0; + + for (size_t i = 1; i < latencies.size(); i++) { + if (latencies[i].first < latencies[best_speed].first) { + best_speed = i; + } + if (ratios[i].first < ratios[best_ratio].first) { + best_ratio = i; + } + } + + std::cout << "BEST SPEED: " << latencies[best_speed].first << "ms " + << latencies[best_speed].second << "\n"; + std::cout << "BEST RATIO: " << ratios[best_ratio].first << " " << ratios[best_ratio].second + << "\n"; +} + +} // namespace snapshot +} // namespace android + +int main() { + android::snapshot::OneShotCompressionTest(); + android::snapshot::IncrementalCompressionTest(); + + return 0; +} \ No newline at end of file From 1d98fe0d393f05283f3a10a896f1054ecd3043cd Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 13 Jul 2021 17:14:20 -0700 Subject: [PATCH 0342/1487] Lose convertToResPath to aapt. aapt (not aapt2) is the only user. Test: treehugger Change-Id: Ie69f84f4f805c69f838e345b44755a316b9f9b06 --- libutils/String8.cpp | 20 ------------------- libutils/String8_fuzz.cpp | 3 --- .../arm64/source-based/libutils.so.lsdump | 16 --------------- .../arm_arm64/source-based/libutils.so.lsdump | 16 --------------- libutils/include/utils/String8.h | 9 --------- 5 files changed, 64 deletions(-) diff --git a/libutils/String8.cpp b/libutils/String8.cpp index 79b7edfe9a12..2b72847e52bd 100644 --- a/libutils/String8.cpp +++ b/libutils/String8.cpp @@ -39,10 +39,6 @@ namespace android { -// Separator used by resource paths. This is not platform dependent contrary -// to OS_PATH_SEPARATOR. -#define RES_PATH_SEPARATOR '/' - static inline char* getEmptyString() { static SharedBuffer* gEmptyStringBuf = [] { SharedBuffer* buf = SharedBuffer::alloc(1); @@ -582,20 +578,4 @@ String8& String8::appendPath(const char* name) } } -String8& String8::convertToResPath() -{ -#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR - size_t len = length(); - if (len > 0) { - char * buf = lockBuffer(len); - for (char * end = buf + len; buf < end; ++buf) { - if (*buf == OS_PATH_SEPARATOR) - *buf = RES_PATH_SEPARATOR; - } - unlockBuffer(len); - } -#endif - return *this; -} - }; // namespace android diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp index e5dcd316ecb0..a1cb3354af53 100644 --- a/libutils/String8_fuzz.cpp +++ b/libutils/String8_fuzz.cpp @@ -82,9 +82,6 @@ std::vector void { str1->getPathDir(); }, - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - str1->convertToResPath(); - }, [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { std::shared_ptr path_out_str = std::make_shared(); diff --git a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump index c89af9e8b220..46baddecde7b 100644 --- a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump +++ b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump @@ -724,9 +724,6 @@ { "name" : "_ZN7android7String813appendFormatVEPKcSt9__va_list" }, - { - "name" : "_ZN7android7String816convertToResPathEv" - }, { "name" : "_ZN7android7String85clearEv" }, @@ -6927,19 +6924,6 @@ "return_type" : "_ZTIi", "source_file" : "system/core/libutils/include/utils/String8.h" }, - { - "function_name" : "android::String8::convertToResPath", - "linker_set_key" : "_ZN7android7String816convertToResPathEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPN7android7String8E" - } - ], - "return_type" : "_ZTIRN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String8::clear", "linker_set_key" : "_ZN7android7String85clearEv", diff --git a/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump b/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump index f88da15e00bb..219c76665bb9 100644 --- a/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump +++ b/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump @@ -724,9 +724,6 @@ { "name" : "_ZN7android7String813appendFormatVEPKcSt9__va_list" }, - { - "name" : "_ZN7android7String816convertToResPathEv" - }, { "name" : "_ZN7android7String85clearEv" }, @@ -6923,19 +6920,6 @@ "return_type" : "_ZTIi", "source_file" : "system/core/libutils/include/utils/String8.h" }, - { - "function_name" : "android::String8::convertToResPath", - "linker_set_key" : "_ZN7android7String816convertToResPathEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPN7android7String8E" - } - ], - "return_type" : "_ZTIRN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String8::clear", "linker_set_key" : "_ZN7android7String85clearEv", diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h index e58f1a5d1992..43909f7f7b73 100644 --- a/libutils/include/utils/String8.h +++ b/libutils/include/utils/String8.h @@ -202,15 +202,6 @@ class String8 { String8 p(*this); p.appendPath(leaf); return p; } String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.c_str()); } - /* - * Converts all separators in this string to /, the default path separator. - * - * If the default OS separator is backslash, this converts all - * backslashes to slashes, in-place. Otherwise it does nothing. - * Returns self. - */ - String8& convertToResPath(); - private: status_t real_append(const char* other, size_t numChars); char* find_extension(void) const; From 3343ca2380dc6ccea641dc3b99156c2d15c2f9d8 Mon Sep 17 00:00:00 2001 From: Yinchu Chen Date: Fri, 25 Aug 2023 04:22:06 +0000 Subject: [PATCH 0343/1487] Increase the number of service supplementary group OEM can add self-owned groups, but the system init cannot support if the group numbers are over than 12, relax some restrictions as appropriate. Bug: b/296826987 Signed-off-by: Haichao Li Change-Id: I231d9f6c82e93c08bc97ca32df70e5b28760acbc --- init/service.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/init/service.h b/init/service.h index b858eeff03d6..9f09cefb8618 100644 --- a/init/service.h +++ b/init/service.h @@ -60,7 +60,7 @@ #define SVC_GENTLE_KILL 0x2000 // This service should be stopped with SIGTERM instead of SIGKILL // Will still be SIGKILLed after timeout period of 200 ms -#define NR_SVC_SUPP_GIDS 12 // twelve supplementary groups +#define NR_SVC_SUPP_GIDS 32 // thirty two supplementary groups namespace android { namespace init { From 81c4e225bf1546ff3f9ce4019f5bd3a58c57ba5f Mon Sep 17 00:00:00 2001 From: Cole Faust Date: Fri, 25 Aug 2023 15:34:08 -0700 Subject: [PATCH 0344/1487] Make simg2img host-only This is supposed to be a host tool, but was being installed on cuttlefish devices. Bug: 205632228 Test: Presubmits Change-Id: I9eb1ae1a5c171253617fa12283e2ec651afb5539 --- libsparse/Android.bp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libsparse/Android.bp b/libsparse/Android.bp index 5a7d0fc78f7c..44907a1f0770 100644 --- a/libsparse/Android.bp +++ b/libsparse/Android.bp @@ -41,9 +41,8 @@ cc_library { ], } -cc_binary { +cc_binary_host { name: "simg2img", - host_supported: true, srcs: [ "simg2img.cpp", "sparse_crc32.cpp", @@ -62,9 +61,8 @@ cc_binary { }, } -cc_binary { +cc_binary_host { name: "img2simg", - host_supported: true, srcs: ["img2simg.cpp"], static_libs: [ "libsparse", From 1ef66b70ffb91c4e94acae268137f8a915271337 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Thu, 24 Aug 2023 15:44:56 -0700 Subject: [PATCH 0345/1487] Fixing optimization logic Adding a hard pattern check for optimized task formation. To keep behavior consistent, we will remove the old initialization path and add resize tasks after attempting optimization. Test: fastboot_test Bug: 297085098 Change-Id: Ie0e656af9be7abdd130290fe547ffbf385ce75d6 --- fastboot/fastboot.cpp | 61 ++++++++++------------ fastboot/task.cpp | 116 ++++++++++++++++-------------------------- fastboot/task.h | 38 ++++++++------ 3 files changed, 93 insertions(+), 122 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 71a228ea1053..8c607dd8370d 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1678,7 +1678,7 @@ bool AddResizeTasks(const FlashingPlan* fp, std::vector>* } for (size_t i = 0; i < tasks->size(); i++) { if (auto flash_task = tasks->at(i)->AsFlashTask()) { - if (should_flash_in_userspace(*metadata.get(), flash_task->GetPartitionAndSlot())) { + if (FlashTask::IsDynamicParitition(fp->source, flash_task)) { if (!loc) { loc = i; } @@ -1760,25 +1760,15 @@ std::vector> ParseFastbootInfo(const FlashingPlan* fp, } tasks.emplace_back(std::move(task)); } - if (auto flash_super_task = OptimizedFlashSuperTask::InitializeFromTasks(fp, tasks)) { - auto it = tasks.begin(); - for (size_t i = 0; i < tasks.size(); i++) { - if (auto flash_task = tasks[i]->AsFlashTask()) { - if (should_flash_in_userspace(flash_task->GetPartitionAndSlot())) { - break; - } - } - if (auto wipe_task = tasks[i]->AsWipeTask()) { - break; - } - it++; - } - tasks.insert(it, std::move(flash_super_task)); + + if (auto flash_super_task = OptimizedFlashSuperTask::Initialize(fp, tasks)) { + tasks.emplace_back(std::move(flash_super_task)); } else { if (!AddResizeTasks(fp, &tasks)) { LOG(WARNING) << "Failed to add resize tasks"; - }; + } } + return tasks; } @@ -1885,30 +1875,35 @@ std::vector> FlashAllTool::CollectTasksFromImageList() { // or in bootloader fastboot. std::vector> tasks; AddFlashTasks(boot_images_, tasks); - if (auto flash_super_task = OptimizedFlashSuperTask::Initialize(fp_, os_images_)) { + + // Sync the super partition. This will reboot to userspace fastboot if needed. + tasks.emplace_back(std::make_unique(fp_)); + for (const auto& [image, slot] : os_images_) { + // Retrofit devices have two super partitions, named super_a and super_b. + // On these devices, secondary slots must be flashed as physical + // partitions (otherwise they would not mount on first boot). To enforce + // this, we delete any logical partitions for the "other" slot. + if (is_retrofit_device(fp_->fb)) { + std::string partition_name = image->part_name + "_"s + slot; + if (image->IsSecondary() && should_flash_in_userspace(partition_name)) { + fp_->fb->DeletePartition(partition_name); + } + tasks.emplace_back(std::make_unique(fp_, partition_name)); + } + } + + AddFlashTasks(os_images_, tasks); + + if (auto flash_super_task = OptimizedFlashSuperTask::Initialize(fp_, tasks)) { tasks.emplace_back(std::move(flash_super_task)); } else { - // Sync the super partition. This will reboot to userspace fastboot if needed. - tasks.emplace_back(std::make_unique(fp_)); // Resize any logical partition to 0, so each partition is reset to 0 // extents, and will achieve more optimal allocation. - for (const auto& [image, slot] : os_images_) { - // Retrofit devices have two super partitions, named super_a and super_b. - // On these devices, secondary slots must be flashed as physical - // partitions (otherwise they would not mount on first boot). To enforce - // this, we delete any logical partitions for the "other" slot. - if (is_retrofit_device(fp_->fb)) { - std::string partition_name = image->part_name + "_"s + slot; - if (image->IsSecondary() && should_flash_in_userspace(partition_name)) { - fp_->fb->DeletePartition(partition_name); - } - tasks.emplace_back(std::make_unique(fp_, partition_name)); - } - tasks.emplace_back(std::make_unique(fp_, image->part_name, "0", slot)); + if (!AddResizeTasks(fp_, &tasks)) { + LOG(WARNING) << "Failed to add resize tasks"; } } - AddFlashTasks(os_images_, tasks); return tasks; } diff --git a/fastboot/task.cpp b/fastboot/task.cpp index 146064cc5b3f..f0eed0cd1c7b 100644 --- a/fastboot/task.cpp +++ b/fastboot/task.cpp @@ -15,6 +15,7 @@ // #include "task.h" +#include #include #include @@ -30,6 +31,15 @@ FlashTask::FlashTask(const std::string& slot, const std::string& pname, const st const bool apply_vbmeta, const FlashingPlan* fp) : pname_(pname), fname_(fname), slot_(slot), apply_vbmeta_(apply_vbmeta), fp_(fp) {} +bool FlashTask::IsDynamicParitition(const ImageSource* source, const FlashTask* task) { + std::vector contents; + if (!source->ReadFile("super_empty.img", &contents)) { + return false; + } + auto metadata = android::fs_mgr::ReadFromImageBlob(contents.data(), contents.size()); + return should_flash_in_userspace(*metadata.get(), task->GetPartitionAndSlot()); +} + void FlashTask::Run() { auto flash = [&](const std::string& partition) { if (should_flash_in_userspace(partition) && !is_userspace_fastboot() && !fp_->force_flash) { @@ -46,7 +56,7 @@ void FlashTask::Run() { do_for_partitions(pname_, slot_, flash, true); } -std::string FlashTask::ToString() { +std::string FlashTask::ToString() const { std::string apply_vbmeta_string = ""; if (apply_vbmeta_) { apply_vbmeta_string = " --apply_vbmeta"; @@ -54,7 +64,7 @@ std::string FlashTask::ToString() { return "flash" + apply_vbmeta_string + " " + pname_ + " " + fname_; } -std::string FlashTask::GetPartitionAndSlot() { +std::string FlashTask::GetPartitionAndSlot() const { auto slot = slot_; if (slot.empty()) { slot = get_current_slot(); @@ -92,7 +102,7 @@ void RebootTask::Run() { } } -std::string RebootTask::ToString() { +std::string RebootTask::ToString() const { return "reboot " + reboot_target_; } @@ -120,79 +130,36 @@ void OptimizedFlashSuperTask::Run() { // Send the data to the device. flash_partition_files(super_name_, files); } -std::string OptimizedFlashSuperTask::ToString() { +std::string OptimizedFlashSuperTask::ToString() const { return "optimized-flash-super"; } -std::unique_ptr OptimizedFlashSuperTask::Initialize( - const FlashingPlan* fp, std::vector& os_images) { - if (!fp->should_optimize_flash_super) { - LOG(INFO) << "super optimization is disabled"; - return nullptr; - } - if (!supports_AB()) { - LOG(VERBOSE) << "Cannot optimize flashing super on non-AB device"; - return nullptr; - } - if (fp->slot_override == "all") { - LOG(VERBOSE) << "Cannot optimize flashing super for all slots"; - return nullptr; - } - - // Does this device use dynamic partitions at all? - unique_fd fd = fp->source->OpenFile("super_empty.img"); - - if (fd < 0) { - LOG(VERBOSE) << "could not open super_empty.img"; - return nullptr; - } - - std::string super_name; - // Try to find whether there is a super partition. - if (fp->fb->GetVar("super-partition-name", &super_name) != fastboot::SUCCESS) { - super_name = "super"; - } - - uint64_t partition_size; - std::string partition_size_str; - if (fp->fb->GetVar("partition-size:" + super_name, &partition_size_str) != fastboot::SUCCESS) { - LOG(VERBOSE) << "Cannot optimize super flashing: could not determine super partition"; - return nullptr; - } - partition_size_str = fb_fix_numeric_var(partition_size_str); - if (!android::base::ParseUint(partition_size_str, &partition_size)) { - LOG(VERBOSE) << "Could not parse " << super_name << " size: " << partition_size_str; - return nullptr; - } - - std::unique_ptr helper = std::make_unique(*fp->source); - if (!helper->Open(fd)) { - return nullptr; - } - - for (const auto& entry : os_images) { - auto partition = GetPartitionName(entry, fp->current_slot); - auto image = entry.first; - - if (!helper->AddPartition(partition, image->img_name, image->optional_if_no_image)) { - return nullptr; +// This looks for a block within tasks that has the following pattern [reboot fastboot, +// update-super, $LIST_OF_DYNAMIC_FLASH_TASKS] and returns true if this is found.Theoretically +// this check is just a pattern match and could break if fastboot-info has a bunch of junk commands +// but all devices should pretty much follow this pattern +bool OptimizedFlashSuperTask::CanOptimize(const ImageSource* source, + const std::vector>& tasks) { + for (size_t i = 0; i < tasks.size(); i++) { + auto reboot_task = tasks[i]->AsRebootTask(); + if (!reboot_task || reboot_task->GetTarget() != "fastboot") { + continue; + } + // The check for i >= tasks.size() - 2 is because we are peeking two tasks ahead. We need to + // check for an update-super && flash {dynamic_partition} + if (i >= tasks.size() - 2 || !tasks[i + 1]->AsUpdateSuperTask()) { + continue; + } + auto flash_task = tasks[i + 2]->AsFlashTask(); + if (!FlashTask::IsDynamicParitition(source, flash_task)) { + continue; } + return true; } - - auto s = helper->GetSparseLayout(); - if (!s) return nullptr; - - // Remove images that we already flashed, just in case we have non-dynamic OS images. - auto remove_if_callback = [&](const ImageEntry& entry) -> bool { - return helper->WillFlash(GetPartitionName(entry, fp->current_slot)); - }; - os_images.erase(std::remove_if(os_images.begin(), os_images.end(), remove_if_callback), - os_images.end()); - return std::make_unique(super_name, std::move(helper), std::move(s), - partition_size, fp); + return false; } -std::unique_ptr OptimizedFlashSuperTask::InitializeFromTasks( +std::unique_ptr OptimizedFlashSuperTask::Initialize( const FlashingPlan* fp, std::vector>& tasks) { if (!fp->should_optimize_flash_super) { LOG(INFO) << "super optimization is disabled"; @@ -206,6 +173,9 @@ std::unique_ptr OptimizedFlashSuperTask::InitializeFrom LOG(VERBOSE) << "Cannot optimize flashing super for all slots"; return nullptr; } + if (!CanOptimize(fp->source, tasks)) { + return nullptr; + } // Does this device use dynamic partitions at all? unique_fd fd = fp->source->OpenFile("super_empty.img"); @@ -288,7 +258,7 @@ void UpdateSuperTask::Run() { } fp_->fb->RawCommand(command, "Updating super partition"); } -std::string UpdateSuperTask::ToString() { +std::string UpdateSuperTask::ToString() const { return "update-super"; } @@ -305,7 +275,7 @@ void ResizeTask::Run() { do_for_partitions(pname_, slot_, resize_partition, false); } -std::string ResizeTask::ToString() { +std::string ResizeTask::ToString() const { return "resize " + pname_; } @@ -315,7 +285,7 @@ void DeleteTask::Run() { fp_->fb->DeletePartition(pname_); } -std::string DeleteTask::ToString() { +std::string DeleteTask::ToString() const { return "delete " + pname_; } @@ -335,6 +305,6 @@ void WipeTask::Run() { fb_perform_format(pname_, 1, partition_type, "", fp_->fs_options, fp_); } -std::string WipeTask::ToString() { +std::string WipeTask::ToString() const { return "erase " + pname_; } diff --git a/fastboot/task.h b/fastboot/task.h index f7c8801f9239..6ebe381230d3 100644 --- a/fastboot/task.h +++ b/fastboot/task.h @@ -30,17 +30,18 @@ class FlashTask; class RebootTask; class UpdateSuperTask; class WipeTask; - +class ResizeTask; class Task { public: Task() = default; virtual void Run() = 0; - virtual std::string ToString() = 0; + virtual std::string ToString() const = 0; virtual FlashTask* AsFlashTask() { return nullptr; } virtual RebootTask* AsRebootTask() { return nullptr; } virtual UpdateSuperTask* AsUpdateSuperTask() { return nullptr; } virtual WipeTask* AsWipeTask() { return nullptr; } + virtual ResizeTask* AsResizeTask() { return nullptr; } virtual ~Task() = default; }; @@ -51,12 +52,13 @@ class FlashTask : public Task { const bool apply_vbmeta, const FlashingPlan* fp); virtual FlashTask* AsFlashTask() override { return this; } + static bool IsDynamicParitition(const ImageSource* source, const FlashTask* task); void Run() override; - std::string ToString() override; - std::string GetPartition() { return pname_; } - std::string GetImageName() { return fname_; } - std::string GetSlot() { return slot_; } - std::string GetPartitionAndSlot(); + std::string ToString() const override; + std::string GetPartition() const { return pname_; } + std::string GetImageName() const { return fname_; } + std::string GetSlot() const { return slot_; } + std::string GetPartitionAndSlot() const; private: const std::string pname_; @@ -72,7 +74,8 @@ class RebootTask : public Task { RebootTask(const FlashingPlan* fp, const std::string& reboot_target); virtual RebootTask* AsRebootTask() override { return this; } void Run() override; - std::string ToString() override; + std::string ToString() const override; + std::string GetTarget() const { return reboot_target_; }; private: const std::string reboot_target_ = ""; @@ -83,13 +86,15 @@ class OptimizedFlashSuperTask : public Task { public: OptimizedFlashSuperTask(const std::string& super_name, std::unique_ptr helper, SparsePtr sparse_layout, uint64_t super_size, const FlashingPlan* fp); - static std::unique_ptr Initialize(const FlashingPlan* fp, - std::vector& os_images); - static std::unique_ptr InitializeFromTasks( + + static std::unique_ptr Initialize( const FlashingPlan* fp, std::vector>& tasks); + static bool CanOptimize(const ImageSource* source, + const std::vector>& tasks); + using ImageEntry = std::pair; void Run() override; - std::string ToString() override; + std::string ToString() const override; private: const std::string super_name_; @@ -105,7 +110,7 @@ class UpdateSuperTask : public Task { virtual UpdateSuperTask* AsUpdateSuperTask() override { return this; } void Run() override; - std::string ToString() override; + std::string ToString() const override; private: const FlashingPlan* fp_; @@ -116,7 +121,8 @@ class ResizeTask : public Task { ResizeTask(const FlashingPlan* fp, const std::string& pname, const std::string& size, const std::string& slot); void Run() override; - std::string ToString() override; + std::string ToString() const override; + virtual ResizeTask* AsResizeTask() override { return this; } private: const FlashingPlan* fp_; @@ -129,7 +135,7 @@ class DeleteTask : public Task { public: DeleteTask(const FlashingPlan* fp, const std::string& pname); void Run() override; - std::string ToString() override; + std::string ToString() const override; private: const FlashingPlan* fp_; @@ -141,7 +147,7 @@ class WipeTask : public Task { WipeTask(const FlashingPlan* fp, const std::string& pname); virtual WipeTask* AsWipeTask() override { return this; } void Run() override; - std::string ToString() override; + std::string ToString() const override; private: const FlashingPlan* fp_; From 1fff690c180a06e76e2e89b08cf20c6ef8c5efcd Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Thu, 24 Aug 2023 09:47:43 -0700 Subject: [PATCH 0346/1487] Adding testing for optimized flash super Adding test cases for correct formation of optimized flash super task. We are adding an explicit pattern match for this task to be correctly formed. Changing Optimized flash task to only remove the reboot to userspace as a user might want to reboot back to bootloader after flashing. We also need to change a couple functions to take a IFastbootDriver to mock up the initialization path. Test: fastboot_test Bug: 297085098 Change-Id: Ic5c63bd4057ca6d64647134e5ce33fef12077fdb --- fastboot/fastboot.cpp | 20 +++--- fastboot/fastboot.h | 4 +- fastboot/fastboot_driver.h | 3 - fastboot/fuzzy_fastboot/main.cpp | 45 ++++++------- fastboot/task.cpp | 14 ++-- fastboot/task.h | 6 +- fastboot/task_test.cpp | 111 ++++++++++++++++++++++++++++++- 7 files changed, 152 insertions(+), 51 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 8c607dd8370d..81787f58e2aa 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1285,7 +1285,7 @@ std::string get_current_slot() { return current_slot; } -static int get_slot_count() { +static int get_slot_count(fastboot::IFastBootDriver* fb) { std::string var; int count = 0; if (fb->GetVar("slot-count", &var) != fastboot::SUCCESS || @@ -1295,8 +1295,8 @@ static int get_slot_count() { return count; } -bool supports_AB() { - return get_slot_count() >= 2; +bool supports_AB(fastboot::IFastBootDriver* fb) { + return get_slot_count(fb) >= 2; } // Given a current slot, this returns what the 'other' slot is. @@ -1308,7 +1308,7 @@ static std::string get_other_slot(const std::string& current_slot, int count) { } static std::string get_other_slot(const std::string& current_slot) { - return get_other_slot(current_slot, get_slot_count()); + return get_other_slot(current_slot, get_slot_count(fb)); } static std::string get_other_slot(int count) { @@ -1316,7 +1316,7 @@ static std::string get_other_slot(int count) { } static std::string get_other_slot() { - return get_other_slot(get_current_slot(), get_slot_count()); + return get_other_slot(get_current_slot(), get_slot_count(fb)); } static std::string verify_slot(const std::string& slot_name, bool allow_all) { @@ -1325,7 +1325,7 @@ static std::string verify_slot(const std::string& slot_name, bool allow_all) { if (allow_all) { return "all"; } else { - int count = get_slot_count(); + int count = get_slot_count(fb); if (count > 0) { return "a"; } else { @@ -1334,7 +1334,7 @@ static std::string verify_slot(const std::string& slot_name, bool allow_all) { } } - int count = get_slot_count(); + int count = get_slot_count(fb); if (count == 0) die("Device does not support slots"); if (slot == "other") { @@ -1407,7 +1407,7 @@ void do_for_partitions(const std::string& part, const std::string& slot, slot.c_str()); } if (has_slot == "yes") { - for (int i = 0; i < get_slot_count(); i++) { + for (int i = 0; i < get_slot_count(fb); i++) { do_for_partition(part, std::string(1, (char)(i + 'a')), func, force_slot); } } else { @@ -1528,7 +1528,7 @@ void do_flash(const char* pname, const char* fname, const bool apply_vbmeta, // Sets slot_override as the active slot. If slot_override is blank, // set current slot as active instead. This clears slot-unbootable. static void set_active(const std::string& slot_override) { - if (!supports_AB()) return; + if (!supports_AB(fb)) return; if (slot_override != "") { fb->SetActive(slot_override); @@ -1845,7 +1845,7 @@ void FlashAllTool::DetermineSlot() { fp_->secondary_slot = get_other_slot(); } if (fp_->secondary_slot == "") { - if (supports_AB()) { + if (supports_AB(fb)) { fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n"); } fp_->skip_secondary = true; diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index 75b8d290f385..35deea7d2a96 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -29,10 +29,8 @@ #include #include -#include "fastboot_driver.h" #include "fastboot_driver_interface.h" #include "filesystem.h" -#include "super_flash_helper.h" #include "task.h" #include "util.h" @@ -183,12 +181,12 @@ struct NetworkSerial { }; Result ParseNetworkSerial(const std::string& serial); -bool supports_AB(); std::string GetPartitionName(const ImageEntry& entry, const std::string& current_slot_); void flash_partition_files(const std::string& partition, const std::vector& files); int64_t get_sparse_limit(int64_t size, const FlashingPlan* fp); std::vector resparse_file(sparse_file* s, int64_t max_size); +bool supports_AB(fastboot::IFastBootDriver* fb); bool is_retrofit_device(fastboot::IFastBootDriver* fb); bool is_logical(const std::string& partition); void fb_perform_format(const std::string& partition, int skip_if_not_supported, diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h index 8774eadc6a6f..48b90ed7d789 100644 --- a/fastboot/fastboot_driver.h +++ b/fastboot/fastboot_driver.h @@ -27,7 +27,6 @@ */ #pragma once #include -#include #include #include #include @@ -37,10 +36,8 @@ #include #include #include -#include #include -#include "constants.h" #include "fastboot_driver_interface.h" #include "transport.h" diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp index e6359374eb32..95778e144711 100644 --- a/fastboot/fuzzy_fastboot/main.cpp +++ b/fastboot/fuzzy_fastboot/main.cpp @@ -50,6 +50,7 @@ #include #include +#include "constants.h" #include "fastboot_driver.h" #include "usb.h" @@ -929,8 +930,7 @@ TEST_F(Fuzz, BadCommandTooLarge) { ASSERT_TRUE(UsbStillAvailible()) << USB_PORT_GONE; std::string resp; - EXPECT_EQ(fb->GetVar("product", &resp), SUCCESS) - << "Device is unresponsive to getvar command"; + EXPECT_EQ(fb->GetVar("product", &resp), SUCCESS) << "Device is unresponsive to getvar command"; } TEST_F(Fuzz, CommandTooLarge) { @@ -986,11 +986,10 @@ TEST_F(Fuzz, SparseZeroLength) { TEST_F(Fuzz, SparseZeroBlkSize) { // handcrafted malform sparse file with zero as block size const std::vector buf = { - '\x3a', '\xff', '\x26', '\xed', '\x01', '\x00', '\x00', '\x00', '\x1c', '\x00', '\x0c', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\xc2', '\xca', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', - '\x10', '\x00', '\x00', '\x00', '\x11', '\x22', '\x33', '\x44' - }; + '\x3a', '\xff', '\x26', '\xed', '\x01', '\x00', '\x00', '\x00', '\x1c', '\x00', '\x0c', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x01', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\xc2', '\xca', '\x00', '\x00', '\x01', + '\x00', '\x00', '\x00', '\x10', '\x00', '\x00', '\x00', '\x11', '\x22', '\x33', '\x44'}; ASSERT_EQ(DownloadCommand(buf.size()), SUCCESS) << "Device rejected download command"; ASSERT_EQ(SendBuffer(buf), SUCCESS) << "Downloading payload failed"; @@ -1005,13 +1004,10 @@ TEST_F(Fuzz, SparseZeroBlkSize) { TEST_F(Fuzz, SparseVeryLargeBlkSize) { // handcrafted sparse file with block size of ~4GB and divisible 4 const std::vector buf = { - '\x3a', '\xff', '\x26', '\xed', '\x01', '\x00', '\x00', '\x00', - '\x1c', '\x00', '\x0c', '\x00', '\xF0', '\xFF', '\xFF', '\xFF', - '\x01', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\xc3', '\xca', '\x00', '\x00', - '\x01', '\x00', '\x00', '\x00', '\x0c', '\x00', '\x00', '\x00', - '\x11', '\x22', '\x33', '\x44' - }; + '\x3a', '\xff', '\x26', '\xed', '\x01', '\x00', '\x00', '\x00', '\x1c', '\x00', '\x0c', + '\x00', '\xF0', '\xFF', '\xFF', '\xFF', '\x01', '\x00', '\x00', '\x00', '\x01', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\xc3', '\xca', '\x00', '\x00', '\x01', + '\x00', '\x00', '\x00', '\x0c', '\x00', '\x00', '\x00', '\x11', '\x22', '\x33', '\x44'}; ASSERT_EQ(DownloadCommand(buf.size()), SUCCESS) << "Device rejected download command"; ASSERT_EQ(SendBuffer(buf), SUCCESS) << "Downloading payload failed"; @@ -1022,11 +1018,10 @@ TEST_F(Fuzz, SparseVeryLargeBlkSize) { TEST_F(Fuzz, SparseTrimmed) { // handcrafted malform sparse file which is trimmed const std::vector buf = { - '\x3a', '\xff', '\x26', '\xed', '\x01', '\x00', '\x00', '\x00', '\x1c', '\x00', '\x0c', '\x00', - '\x00', '\x10', '\x00', '\x00', '\x00', '\x00', '\x08', '\x00', '\x01', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\xc1', '\xca', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x80', '\x11', '\x22', '\x33', '\x44' - }; + '\x3a', '\xff', '\x26', '\xed', '\x01', '\x00', '\x00', '\x00', '\x1c', '\x00', '\x0c', + '\x00', '\x00', '\x10', '\x00', '\x00', '\x00', '\x00', '\x08', '\x00', '\x01', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\xc1', '\xca', '\x00', '\x00', '\x01', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x80', '\x11', '\x22', '\x33', '\x44'}; ASSERT_EQ(DownloadCommand(buf.size()), SUCCESS) << "Device rejected download command"; ASSERT_EQ(SendBuffer(buf), SUCCESS) << "Downloading payload failed"; @@ -1041,11 +1036,10 @@ TEST_F(Fuzz, SparseTrimmed) { TEST_F(Fuzz, SparseInvalidChurk) { // handcrafted malform sparse file with invalid churk const std::vector buf = { - '\x3a', '\xff', '\x26', '\xed', '\x01', '\x00', '\x00', '\x00', '\x1c', '\x00', '\x0c', '\x00', - '\x00', '\x10', '\x00', '\x00', '\x00', '\x00', '\x08', '\x00', '\x01', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\xc1', '\xca', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', - '\x10', '\x00', '\x00', '\x00', '\x11', '\x22', '\x33', '\x44' - }; + '\x3a', '\xff', '\x26', '\xed', '\x01', '\x00', '\x00', '\x00', '\x1c', '\x00', '\x0c', + '\x00', '\x00', '\x10', '\x00', '\x00', '\x00', '\x00', '\x08', '\x00', '\x01', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\xc1', '\xca', '\x00', '\x00', '\x01', + '\x00', '\x00', '\x00', '\x10', '\x00', '\x00', '\x00', '\x11', '\x22', '\x33', '\x44'}; ASSERT_EQ(DownloadCommand(buf.size()), SUCCESS) << "Device rejected download command"; ASSERT_EQ(SendBuffer(buf), SUCCESS) << "Downloading payload failed"; @@ -1895,7 +1889,8 @@ int main(int argc, char** argv) { if (!fastboot::FastBootTest::IsFastbootOverTcp()) { printf("\n"); const auto matcher = [](usb_ifc_info* info) -> int { - return fastboot::FastBootTest::MatchFastboot(info, fastboot::FastBootTest::device_serial); + return fastboot::FastBootTest::MatchFastboot(info, + fastboot::FastBootTest::device_serial); }; Transport* transport = nullptr; while (!transport) { diff --git a/fastboot/task.cpp b/fastboot/task.cpp index f0eed0cd1c7b..f13dd55b35be 100644 --- a/fastboot/task.cpp +++ b/fastboot/task.cpp @@ -15,8 +15,7 @@ // #include "task.h" -#include -#include +#include "fastboot_driver.h" #include #include @@ -130,6 +129,7 @@ void OptimizedFlashSuperTask::Run() { // Send the data to the device. flash_partition_files(super_name_, files); } + std::string OptimizedFlashSuperTask::ToString() const { return "optimized-flash-super"; } @@ -165,7 +165,7 @@ std::unique_ptr OptimizedFlashSuperTask::Initialize( LOG(INFO) << "super optimization is disabled"; return nullptr; } - if (!supports_AB()) { + if (!supports_AB(fp->fb)) { LOG(VERBOSE) << "Cannot optimize flashing super on non-AB device"; return nullptr; } @@ -218,17 +218,21 @@ std::unique_ptr OptimizedFlashSuperTask::Initialize( auto s = helper->GetSparseLayout(); if (!s) return nullptr; - // Remove images that we already flashed, just in case we have non-dynamic OS images. + + // Remove tasks that are concatenated into this optimized task auto remove_if_callback = [&](const auto& task) -> bool { if (auto flash_task = task->AsFlashTask()) { return helper->WillFlash(flash_task->GetPartitionAndSlot()); } else if (auto update_super_task = task->AsUpdateSuperTask()) { return true; } else if (auto reboot_task = task->AsRebootTask()) { - return true; + if (reboot_task->GetTarget() == "fastboot") { + return true; + } } return false; }; + tasks.erase(std::remove_if(tasks.begin(), tasks.end(), remove_if_callback), tasks.end()); return std::make_unique(super_name, std::move(helper), std::move(s), diff --git a/fastboot/task.h b/fastboot/task.h index 6ebe381230d3..a98c87419c52 100644 --- a/fastboot/task.h +++ b/fastboot/task.h @@ -15,10 +15,8 @@ // #pragma once -#include #include -#include "fastboot_driver.h" #include "super_flash_helper.h" #include "util.h" @@ -29,6 +27,7 @@ using ImageEntry = std::pair; class FlashTask; class RebootTask; class UpdateSuperTask; +class OptimizedFlashSuperTask; class WipeTask; class ResizeTask; class Task { @@ -40,6 +39,7 @@ class Task { virtual FlashTask* AsFlashTask() { return nullptr; } virtual RebootTask* AsRebootTask() { return nullptr; } virtual UpdateSuperTask* AsUpdateSuperTask() { return nullptr; } + virtual OptimizedFlashSuperTask* AsOptimizedFlashSuperTask() { return nullptr; } virtual WipeTask* AsWipeTask() { return nullptr; } virtual ResizeTask* AsResizeTask() { return nullptr; } @@ -86,13 +86,13 @@ class OptimizedFlashSuperTask : public Task { public: OptimizedFlashSuperTask(const std::string& super_name, std::unique_ptr helper, SparsePtr sparse_layout, uint64_t super_size, const FlashingPlan* fp); + virtual OptimizedFlashSuperTask* AsOptimizedFlashSuperTask() override { return this; } static std::unique_ptr Initialize( const FlashingPlan* fp, std::vector>& tasks); static bool CanOptimize(const ImageSource* source, const std::vector>& tasks); - using ImageEntry = std::pair; void Run() override; std::string ToString() const override; diff --git a/fastboot/task_test.cpp b/fastboot/task_test.cpp index 1ba3f4ae426e..42be3cb653ec 100644 --- a/fastboot/task_test.cpp +++ b/fastboot/task_test.cpp @@ -19,11 +19,10 @@ #include "fastboot_driver_mock.h" #include -#include #include #include -#include #include "android-base/strings.h" +#include "gmock/gmock.h" using android::base::Split; using testing::_; @@ -235,3 +234,111 @@ TEST_F(ParseTest, CorrectTaskLists) { << "size of fastboot-info task list: " << fastboot_info_tasks.size() << " size of hardcoded task list: " << hardcoded_tasks.size(); } + +TEST_F(ParseTest, CanOptimizeTest) { + if (!get_android_product_out()) { + GTEST_SKIP(); + } + + LocalImageSource s; + fp->source = &s; + fp->sparse_limit = std::numeric_limits::max(); + + fastboot::MockFastbootDriver fb; + fp->fb = &fb; + fp->should_optimize_flash_super = false; + fp->should_use_fastboot_info = true; + + std::vector, bool>> patternmatchtest = { + {{"flash boot", "flash init_boot", "flash vendor_boot", "reboot fastboot", + "update-super", "flash product", "flash system", "flash system_ext", "flash odm", + "if-wipe erase userdata"}, + true}, + {{"flash boot", "flash init_boot", "flash vendor_boot", "reboot fastboot", + "update-super", "flash product", "flash system", "flash system_ext", "flash odm", + "if-wipe erase userdata"}, + true}, + {{"flash boot", "flash init_boot", "flash vendor_boot", "reboot fastboot", + "flash product", "flash system", "flash system_ext", "flash odm", + "if-wipe erase userdata"}, + false}, + {{"flash boot", "flash init_boot", "flash vendor_boot", "update-super", "flash product", + "flash system", "flash system_ext", "flash odm", "if-wipe erase userdata"}, + false}, + }; + + auto remove_if_callback = [&](const auto& task) -> bool { return !!task->AsResizeTask(); }; + + for (auto& test : patternmatchtest) { + std::vector> tasks = ParseFastbootInfo(fp.get(), test.first); + tasks.erase(std::remove_if(tasks.begin(), tasks.end(), remove_if_callback), tasks.end()); + ASSERT_EQ(OptimizedFlashSuperTask::CanOptimize(fp->source, tasks), test.second); + } +} +// Note: this test is exclusively testing that optimized flash super pattern matches a given task +// list and is able to optimized based on a correct sequence of tasks +TEST_F(ParseTest, OptimizedFlashSuperPatternMatchTest) { + if (!get_android_product_out()) { + GTEST_SKIP(); + } + + LocalImageSource s; + fp->source = &s; + fp->sparse_limit = std::numeric_limits::max(); + + fastboot::MockFastbootDriver fb; + fp->fb = &fb; + fp->should_optimize_flash_super = true; + fp->should_use_fastboot_info = true; + + ON_CALL(fb, GetVar("super-partition-name", _, _)) + .WillByDefault(testing::Return(fastboot::BAD_ARG)); + + ON_CALL(fb, GetVar("slot-count", _, _)) + .WillByDefault(testing::DoAll(testing::SetArgPointee<1>("2"), + testing::Return(fastboot::SUCCESS))); + + ON_CALL(fb, GetVar("partition-size:super", _, _)) + .WillByDefault(testing::DoAll(testing::SetArgPointee<1>("1000"), + testing::Return(fastboot::SUCCESS))); + + std::vector, bool>> patternmatchtest = { + {{"flash boot", "flash init_boot", "flash vendor_boot", "reboot fastboot", + "update-super", "flash product", "flash system", "flash system_ext", "flash odm", + "if-wipe erase userdata"}, + true}, + {{"flash boot", "flash init_boot", "flash vendor_boot", "reboot fastboot", + "update-super", "flash product", "flash system", "flash system_ext", "flash odm", + "if-wipe erase userdata"}, + true}, + {{"flash boot", "flash init_boot", "flash vendor_boot", "reboot fastboot", + "flash product", "flash system", "flash system_ext", "flash odm", + "if-wipe erase userdata"}, + false}, + {{"flash boot", "flash init_boot", "flash vendor_boot", "update-super", "flash product", + "flash system", "flash system_ext", "flash odm", "if-wipe erase userdata"}, + false}, + }; + + for (auto& test : patternmatchtest) { + std::vector> tasks = ParseFastbootInfo(fp.get(), test.first); + // Check to make sure we have an optimized flash super task && no more dynamic partition + // flashing tasks + auto&& IsOptimized = [](const FlashingPlan* fp, + const std::vector>& tasks) { + bool contains_optimized_task = false; + for (auto& task : tasks) { + if (auto optimized_task = task->AsOptimizedFlashSuperTask()) { + contains_optimized_task = true; + } + if (auto flash_task = task->AsFlashTask()) { + if (FlashTask::IsDynamicParitition(fp->source, flash_task)) { + return false; + } + } + } + return contains_optimized_task; + }; + ASSERT_EQ(IsOptimized(fp.get(), tasks), test.second); + } +} From 2d4261ca4356839711b55397418bf63c334a9da3 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Wed, 23 Aug 2023 13:36:41 -0700 Subject: [PATCH 0347/1487] documenting optimized flash super Adding documentation on the explicit pattern match we are going to add to optimizing flash super. Test: na Change-Id: I57c19fb2a85d74beea5b91e38f6f46fa47637117 --- fastboot/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fastboot/README.md b/fastboot/README.md index 55583eb0efc0..28e623ca798b 100644 --- a/fastboot/README.md +++ b/fastboot/README.md @@ -188,6 +188,21 @@ The currently defined commands are: erase %s Erase a given partition (can only be used in conjunction) with if-wipe -> eg. if-wipe erase cache +Flashing Optimization: + + After generating the list of tasks to execute, Fastboot will try and + optimize the flashing of the dynamic partitions by constructing an + optimized flash super task. Fastboot will explicitly pattern match the + following commands and try and concatenate it into this task. (doing so + will allow us to avoid the reboot into userspace fastbootd which takes + significant time) + + //Optimizable Block + reboot fastboot + update-super ---> generate optimized flash super task + $FOR EACH {dynamic partition} + flash {dynamic partition} + ## Client Variables The "getvar:%s" command is used to read client variables which From afe1163ade57699c1d251f0ae06100a2af42b952 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Fri, 25 Aug 2023 14:02:24 -0700 Subject: [PATCH 0348/1487] Adding test for IsDynamicPartition Adding a test case for checking if flash task is a dynamic partition flash task. This function is used since is-logical only works in fastbootd, and should_flash_in_userspace() only works if $ANDROID_PRODUCT_OUT is set. This function works with fastboot update when called in bootloader without $OUT dir set Test: fastboot_test Change-Id: I65309f97e04fdfc449e61de5cd3a6feff18bc9ab --- fastboot/task_test.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/fastboot/task_test.cpp b/fastboot/task_test.cpp index 42be3cb653ec..1e25b6f63e39 100644 --- a/fastboot/task_test.cpp +++ b/fastboot/task_test.cpp @@ -234,6 +234,35 @@ TEST_F(ParseTest, CorrectTaskLists) { << "size of fastboot-info task list: " << fastboot_info_tasks.size() << " size of hardcoded task list: " << hardcoded_tasks.size(); } +TEST_F(ParseTest, IsDynamicParitiontest) { + if (!get_android_product_out()) { + GTEST_SKIP(); + } + + LocalImageSource s; + fp->source = &s; + + fastboot::MockFastbootDriver fb; + fp->fb = &fb; + fp->should_optimize_flash_super = true; + fp->should_use_fastboot_info = true; + + std::vector> test_cases = { + {"flash boot", false}, + {"flash init_boot", false}, + {"flash --apply-vbmeta vbmeta", false}, + {"flash product", true}, + {"flash system", true}, + {"flash --slot-other system system_other.img", true}, + }; + for (auto& test : test_cases) { + std::unique_ptr task = + ParseFastbootInfoLine(fp.get(), android::base::Tokenize(test.first, " ")); + auto flash_task = task->AsFlashTask(); + ASSERT_FALSE(flash_task == nullptr); + ASSERT_EQ(FlashTask::IsDynamicParitition(fp->source, flash_task), test.second); + } +} TEST_F(ParseTest, CanOptimizeTest) { if (!get_android_product_out()) { @@ -275,6 +304,7 @@ TEST_F(ParseTest, CanOptimizeTest) { ASSERT_EQ(OptimizedFlashSuperTask::CanOptimize(fp->source, tasks), test.second); } } + // Note: this test is exclusively testing that optimized flash super pattern matches a given task // list and is able to optimized based on a correct sequence of tasks TEST_F(ParseTest, OptimizedFlashSuperPatternMatchTest) { From 18ff56d8d7a45706288d6f32752dc2802c5d44bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=C3=A9baud=20Weksteen?= Date: Thu, 31 Aug 2023 14:22:15 +1000 Subject: [PATCH 0349/1487] Remove SeamendcHostTest from TEST_MAPPING Bug: 297794885 Test: TH Change-Id: I49c6caa575ccd570085de15ddf51ea9a71abe90f --- init/TEST_MAPPING | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/init/TEST_MAPPING b/init/TEST_MAPPING index 402b501b9a67..36ca3793bcf9 100644 --- a/init/TEST_MAPPING +++ b/init/TEST_MAPPING @@ -8,14 +8,6 @@ }, { "name": "MicrodroidHostTestCases" - }, - { - "name": "CtsSecurityHostTestCases", - "options": [ - { - "include-filter": "android.security.cts.SeamendcHostTest" - } - ] } ], "hwasan-presubmit": [ @@ -27,14 +19,6 @@ }, { "name": "MicrodroidHostTestCases" - }, - { - "name": "CtsSecurityHostTestCases", - "options": [ - { - "include-filter": "android.security.cts.SeamendcHostTest" - } - ] } ] } From dba385eddaf8dc0178d8b7f0d4c8c4f97024801e Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Thu, 24 Aug 2023 13:40:36 -0700 Subject: [PATCH 0350/1487] Ignore 16K kernel modules when running on 4K kernel Test: th Bug: 293313353 Change-Id: I02ea01c8e67b9ded164c7492eea3be0aead75de1 --- init/first_stage_init.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index 3239eb7ca203..c6a287ab6278 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -163,6 +163,21 @@ std::string GetPageSizeSuffix() { return android::base::StringPrintf("_%zuk", page_size / 1024); } +constexpr bool EndsWith(const std::string_view str, const std::string_view suffix) { + return str.size() >= suffix.size() && + 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix); +} + +constexpr std::string_view GetPageSizeSuffix(std::string_view dirname) { + if (EndsWith(dirname, "_16k")) { + return "_16k"; + } + if (EndsWith(dirname, "_64k")) { + return "_64k"; + } + return ""; +} + } // namespace std::string GetModuleLoadList(BootMode boot_mode, const std::string& dir_path) { @@ -211,7 +226,8 @@ bool LoadKernelModules(BootMode boot_mode, bool want_console, bool want_parallel } dirent* entry = nullptr; std::vector module_dirs; - const std::string release_specific_module_dir = uts.release + GetPageSizeSuffix(); + const auto page_size_suffix = GetPageSizeSuffix(); + const std::string release_specific_module_dir = uts.release + page_size_suffix; while ((entry = readdir(base_dir.get()))) { if (entry->d_type != DT_DIR) { continue; @@ -223,6 +239,10 @@ bool LoadKernelModules(BootMode boot_mode, bool want_console, bool want_parallel module_dirs.emplace_back(entry->d_name); break; } + // Ignore _16k/_64k module dirs on 4K kernels + if (GetPageSizeSuffix(entry->d_name) != page_size_suffix) { + continue; + } int dir_major = 0, dir_minor = 0; if (sscanf(entry->d_name, "%d.%d", &dir_major, &dir_minor) != 2 || dir_major != major || dir_minor != minor) { From 0b627d92c45baca2070f0ad88154a49472de542a Mon Sep 17 00:00:00 2001 From: Dmitrii Merkurev Date: Sun, 3 Sep 2023 17:30:46 +0100 Subject: [PATCH 0351/1487] fastboot: get rid of manual transport memory management Existing code has transport memory leaks. Use smart pointers for transport to get rid of those cases and manual memory management Test: atest fastboot_test Test: manually checked transport isn't leaking anymore Bug: 296629925 Change-Id: Ifdf162d5084f61ae5c1d2b56a897464af58100da Signed-off-by: Dmitrii Merkurev --- fastboot/fastboot.cpp | 58 +++++++++++++--------------- fastboot/fastboot_driver.cpp | 10 ++--- fastboot/fastboot_driver.h | 9 ++--- fastboot/fastboot_driver_test.cpp | 38 ++++++++++-------- fastboot/fuzzy_fastboot/fixtures.cpp | 10 ++--- fastboot/fuzzy_fastboot/main.cpp | 9 ++--- fastboot/usb.h | 3 +- fastboot/usb_linux.cpp | 10 ++++- fastboot/usb_osx.cpp | 12 ++++-- fastboot/usb_windows.cpp | 10 ++++- 10 files changed, 92 insertions(+), 77 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 71a228ea1053..fa21ab72fdcc 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -350,23 +350,22 @@ Result ParseNetworkSerial(const std::string& seria // // The returned Transport is a singleton, so multiple calls to this function will return the same // object, and the caller should not attempt to delete the returned Transport. -static Transport* open_device(const char* local_serial, bool wait_for_device = true, - bool announce = true) { +static std::unique_ptr open_device(const char* local_serial, + bool wait_for_device = true, + bool announce = true) { const Result network_serial = ParseNetworkSerial(local_serial); - Transport* transport = nullptr; + std::unique_ptr transport; while (true) { if (network_serial.ok()) { std::string error; if (network_serial->protocol == Socket::Protocol::kTcp) { - transport = tcp::Connect(network_serial->address, network_serial->port, &error) - .release(); + transport = tcp::Connect(network_serial->address, network_serial->port, &error); } else if (network_serial->protocol == Socket::Protocol::kUdp) { - transport = udp::Connect(network_serial->address, network_serial->port, &error) - .release(); + transport = udp::Connect(network_serial->address, network_serial->port, &error); } - if (transport == nullptr && announce) { + if (!transport && announce) { LOG(ERROR) << "error: " << error; } } else if (network_serial.error().code() == @@ -378,12 +377,12 @@ static Transport* open_device(const char* local_serial, bool wait_for_device = t Expect(network_serial); } - if (transport != nullptr) { + if (transport) { return transport; } if (!wait_for_device) { - return nullptr; + return transport; } if (announce) { @@ -394,9 +393,9 @@ static Transport* open_device(const char* local_serial, bool wait_for_device = t } } -static Transport* NetworkDeviceConnected(bool print = false) { - Transport* transport = nullptr; - Transport* result = nullptr; +static std::unique_ptr NetworkDeviceConnected(bool print = false) { + std::unique_ptr transport; + std::unique_ptr result; ConnectedDevicesStorage storage; std::set devices; @@ -409,11 +408,11 @@ static Transport* NetworkDeviceConnected(bool print = false) { transport = open_device(device.c_str(), false, false); if (print) { - PrintDevice(device.c_str(), transport == nullptr ? "offline" : "fastboot"); + PrintDevice(device.c_str(), transport ? "offline" : "fastboot"); } - if (transport != nullptr) { - result = transport; + if (transport) { + result = std::move(transport); } } @@ -431,21 +430,21 @@ static Transport* NetworkDeviceConnected(bool print = false) { // // The returned Transport is a singleton, so multiple calls to this function will return the same // object, and the caller should not attempt to delete the returned Transport. -static Transport* open_device() { +static std::unique_ptr open_device() { if (serial != nullptr) { return open_device(serial); } bool announce = true; - Transport* transport = nullptr; + std::unique_ptr transport; while (true) { transport = usb_open(match_fastboot(nullptr)); - if (transport != nullptr) { + if (transport) { return transport; } transport = NetworkDeviceConnected(); - if (transport != nullptr) { + if (transport) { return transport; } @@ -455,6 +454,8 @@ static Transport* open_device() { } std::this_thread::sleep_for(std::chrono::seconds(1)); } + + return transport; } static int Connect(int argc, char* argv[]) { @@ -466,8 +467,7 @@ static int Connect(int argc, char* argv[]) { const char* local_serial = *argv; Expect(ParseNetworkSerial(local_serial)); - const Transport* transport = open_device(local_serial, false); - if (transport == nullptr) { + if (!open_device(local_serial, false)) { return 1; } @@ -531,6 +531,7 @@ static void list_devices() { usb_open(list_devices_callback); NetworkDeviceConnected(/* print */ true); } + void syntax_error(const char* fmt, ...) { fprintf(stderr, "fastboot: usage: "); @@ -1547,9 +1548,7 @@ bool is_userspace_fastboot() { void reboot_to_userspace_fastboot() { fb->RebootTo("fastboot"); - - auto* old_transport = fb->set_transport(nullptr); - delete old_transport; + fb->set_transport(nullptr); // Give the current connection time to close. std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -2377,8 +2376,8 @@ int FastBootTool::Main(int argc, char* argv[]) { return show_help(); } - Transport* transport = open_device(); - if (transport == nullptr) { + std::unique_ptr transport = open_device(); + if (!transport) { return 1; } fastboot::DriverCallbacks driver_callbacks = { @@ -2388,7 +2387,7 @@ int FastBootTool::Main(int argc, char* argv[]) { .text = TextMessage, }; - fastboot::FastBootDriver fastboot_driver(transport, driver_callbacks, false); + fastboot::FastBootDriver fastboot_driver(std::move(transport), driver_callbacks, false); fb = &fastboot_driver; fp->fb = &fastboot_driver; @@ -2633,9 +2632,6 @@ int FastBootTool::Main(int argc, char* argv[]) { } fprintf(stderr, "Finished. Total time: %.3fs\n", (now() - start)); - auto* old_transport = fb->set_transport(nullptr); - delete old_transport; - return 0; } diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp index 9770ab25cfc1..e5ef66bafe90 100644 --- a/fastboot/fastboot_driver.cpp +++ b/fastboot/fastboot_driver.cpp @@ -58,9 +58,10 @@ using namespace android::storage_literals; namespace fastboot { /*************************** PUBLIC *******************************/ -FastBootDriver::FastBootDriver(Transport* transport, DriverCallbacks driver_callbacks, +FastBootDriver::FastBootDriver(std::unique_ptr transport, + DriverCallbacks driver_callbacks, bool no_checks) - : transport_(transport), + : transport_(std::move(transport)), prolog_(std::move(driver_callbacks.prolog)), epilog_(std::move(driver_callbacks.epilog)), info_(std::move(driver_callbacks.info)), @@ -627,9 +628,8 @@ int FastBootDriver::SparseWriteCallback(std::vector& tpbuf, const char* da return 0; } -Transport* FastBootDriver::set_transport(Transport* transport) { - std::swap(transport_, transport); - return transport; +void FastBootDriver::set_transport(std::unique_ptr transport) { + transport_ = std::move(transport); } } // End namespace fastboot diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h index 8774eadc6a6f..30298cb2072c 100644 --- a/fastboot/fastboot_driver.h +++ b/fastboot/fastboot_driver.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -63,7 +64,7 @@ class FastBootDriver : public IFastBootDriver { static constexpr uint32_t MAX_DOWNLOAD_SIZE = std::numeric_limits::max(); static constexpr size_t TRANSPORT_CHUNK_SIZE = 1024; - FastBootDriver(Transport* transport, DriverCallbacks driver_callbacks = {}, + FastBootDriver(std::unique_ptr transport, DriverCallbacks driver_callbacks = {}, bool no_checks = false); ~FastBootDriver(); @@ -124,9 +125,7 @@ class FastBootDriver : public IFastBootDriver { std::string Error(); RetCode WaitForDisconnect() override; - // Note: set_transport will return the previous transport. - Transport* set_transport(Transport* transport); - Transport* transport() const { return transport_; } + void set_transport(std::unique_ptr transport); RetCode RawCommand(const std::string& cmd, const std::string& message, std::string* response = nullptr, std::vector* info = nullptr, @@ -143,7 +142,7 @@ class FastBootDriver : public IFastBootDriver { std::string ErrnoStr(const std::string& msg); - Transport* transport_; + std::unique_ptr transport_; private: RetCode SendBuffer(android::base::borrowed_fd fd, size_t size); diff --git a/fastboot/fastboot_driver_test.cpp b/fastboot/fastboot_driver_test.cpp index 6f6cf8c49b04..d2033b0e2081 100644 --- a/fastboot/fastboot_driver_test.cpp +++ b/fastboot/fastboot_driver_test.cpp @@ -16,6 +16,7 @@ #include "fastboot_driver.h" +#include #include #include @@ -30,13 +31,14 @@ class DriverTest : public ::testing::Test { }; TEST_F(DriverTest, GetVar) { - MockTransport transport; - FastBootDriver driver(&transport); + std::unique_ptr transport_pointer = std::make_unique(); + MockTransport* transport = transport_pointer.get(); + FastBootDriver driver(std::move(transport_pointer)); - EXPECT_CALL(transport, Write(_, _)) + EXPECT_CALL(*transport, Write(_, _)) .With(AllArgs(RawData("getvar:version"))) .WillOnce(ReturnArg<1>()); - EXPECT_CALL(transport, Read(_, _)).WillOnce(Invoke(CopyData("OKAY0.4"))); + EXPECT_CALL(*transport, Read(_, _)).WillOnce(Invoke(CopyData("OKAY0.4"))); std::string output; ASSERT_EQ(driver.GetVar("version", &output), SUCCESS) << driver.Error(); @@ -44,14 +46,15 @@ TEST_F(DriverTest, GetVar) { } TEST_F(DriverTest, InfoMessage) { - MockTransport transport; - FastBootDriver driver(&transport); + std::unique_ptr transport_pointer = std::make_unique(); + MockTransport* transport = transport_pointer.get(); + FastBootDriver driver(std::move(transport_pointer)); - EXPECT_CALL(transport, Write(_, _)) + EXPECT_CALL(*transport, Write(_, _)) .With(AllArgs(RawData("oem dmesg"))) .WillOnce(ReturnArg<1>()); - EXPECT_CALL(transport, Read(_, _)).WillOnce(Invoke(CopyData("INFOthis is an info line"))); - EXPECT_CALL(transport, Read(_, _)).WillOnce(Invoke(CopyData("OKAY"))); + EXPECT_CALL(*transport, Read(_, _)).WillOnce(Invoke(CopyData("INFOthis is an info line"))); + EXPECT_CALL(*transport, Read(_, _)).WillOnce(Invoke(CopyData("OKAY"))); std::vector info; ASSERT_EQ(driver.RawCommand("oem dmesg", "", nullptr, &info), SUCCESS) << driver.Error(); @@ -60,28 +63,29 @@ TEST_F(DriverTest, InfoMessage) { } TEST_F(DriverTest, TextMessage) { - MockTransport transport; std::string text; + std::unique_ptr transport_pointer = std::make_unique(); + MockTransport* transport = transport_pointer.get(); DriverCallbacks callbacks{[](const std::string&) {}, [](int) {}, [](const std::string&) {}, [&text](const std::string& extra_text) { text += extra_text; }}; - FastBootDriver driver(&transport, callbacks); + FastBootDriver driver(std::move(transport_pointer), callbacks); - EXPECT_CALL(transport, Write(_, _)) + EXPECT_CALL(*transport, Write(_, _)) .With(AllArgs(RawData("oem trusty runtest trusty.hwaes.bench"))) .WillOnce(ReturnArg<1>()); - EXPECT_CALL(transport, Read(_, _)).WillOnce(Invoke(CopyData("TEXTthis is a text line"))); - EXPECT_CALL(transport, Read(_, _)) + EXPECT_CALL(*transport, Read(_, _)).WillOnce(Invoke(CopyData("TEXTthis is a text line"))); + EXPECT_CALL(*transport, Read(_, _)) .WillOnce(Invoke( CopyData("TEXT, albeit very long and split over multiple TEXT messages."))); - EXPECT_CALL(transport, Read(_, _)) + EXPECT_CALL(*transport, Read(_, _)) .WillOnce(Invoke(CopyData("TEXT Indeed we can do that now with a TEXT message whenever " "we feel like it."))); - EXPECT_CALL(transport, Read(_, _)) + EXPECT_CALL(*transport, Read(_, _)) .WillOnce(Invoke(CopyData("TEXT Isn't that truly super cool?"))); - EXPECT_CALL(transport, Read(_, _)).WillOnce(Invoke(CopyData("OKAY"))); + EXPECT_CALL(*transport, Read(_, _)).WillOnce(Invoke(CopyData("OKAY"))); std::vector info; ASSERT_EQ(driver.RawCommand("oem trusty runtest trusty.hwaes.bench", "", nullptr, &info), diff --git a/fastboot/fuzzy_fastboot/fixtures.cpp b/fastboot/fuzzy_fastboot/fixtures.cpp index 9b5e5f7bd2c2..94a53ed8c0c3 100644 --- a/fastboot/fuzzy_fastboot/fixtures.cpp +++ b/fastboot/fuzzy_fastboot/fixtures.cpp @@ -128,7 +128,7 @@ void FastBootTest::SetUp() { return MatchFastboot(info, device_serial); }; for (int i = 0; i < MAX_USB_TRIES && !transport; i++) { - std::unique_ptr usb(usb_open(matcher, USB_TIMEOUT)); + std::unique_ptr usb = usb_open(matcher, USB_TIMEOUT); if (usb) transport = std::unique_ptr( new TransportSniffer(std::move(usb), serial_port)); @@ -143,7 +143,7 @@ void FastBootTest::SetUp() { } else { ASSERT_EQ(device_path, cb_scratch); // The path can not change } - fb = std::unique_ptr(new FastBootDriver(transport.get(), {}, true)); + fb = std::unique_ptr(new FastBootDriver(std::move(transport), {}, true)); // No error checking since non-A/B devices may not support the command fb->GetVar("current-slot", &initial_slot); } @@ -200,7 +200,7 @@ void FastBootTest::ReconnectFastbootDevice() { if (IsFastbootOverTcp()) { ConnectTcpFastbootDevice(); device_path = cb_scratch; - fb = std::unique_ptr(new FastBootDriver(transport.get(), {}, true)); + fb = std::unique_ptr(new FastBootDriver(std::move(transport), {}, true)); return; } @@ -212,7 +212,7 @@ void FastBootTest::ReconnectFastbootDevice() { return MatchFastboot(info, device_serial); }; while (!transport) { - std::unique_ptr usb(usb_open(matcher, USB_TIMEOUT)); + std::unique_ptr usb = usb_open(matcher, USB_TIMEOUT); if (usb) { transport = std::unique_ptr( new TransportSniffer(std::move(usb), serial_port)); @@ -220,7 +220,7 @@ void FastBootTest::ReconnectFastbootDevice() { std::this_thread::sleep_for(1s); } device_path = cb_scratch; - fb = std::unique_ptr(new FastBootDriver(transport.get(), {}, true)); + fb = std::unique_ptr(new FastBootDriver(std::move(transport), {}, true)); } void FastBootTest::SetLockState(bool unlock, bool assert_change) { diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp index e6359374eb32..43aaec9d122a 100644 --- a/fastboot/fuzzy_fastboot/main.cpp +++ b/fastboot/fuzzy_fastboot/main.cpp @@ -166,16 +166,15 @@ TEST(USBFunctionality, USBConnect) { const auto matcher = [](usb_ifc_info* info) -> int { return FastBootTest::MatchFastboot(info, fastboot::FastBootTest::device_serial); }; - Transport* transport = nullptr; + std::unique_ptr transport; for (int i = 0; i < FastBootTest::MAX_USB_TRIES && !transport; i++) { transport = usb_open(matcher); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } - ASSERT_NE(transport, nullptr) << "Could not find the fastboot device after: " - << 10 * FastBootTest::MAX_USB_TRIES << "ms"; + ASSERT_NE(transport.get(), nullptr) << "Could not find the fastboot device after: " + << 10 * FastBootTest::MAX_USB_TRIES << "ms"; if (transport) { transport->Close(); - delete transport; } } @@ -1897,7 +1896,7 @@ int main(int argc, char** argv) { const auto matcher = [](usb_ifc_info* info) -> int { return fastboot::FastBootTest::MatchFastboot(info, fastboot::FastBootTest::device_serial); }; - Transport* transport = nullptr; + std::unique_ptr transport; while (!transport) { transport = usb_open(matcher); std::this_thread::sleep_for(std::chrono::milliseconds(10)); diff --git a/fastboot/usb.h b/fastboot/usb.h index 69581ab128d7..d85cb81868ec 100644 --- a/fastboot/usb.h +++ b/fastboot/usb.h @@ -29,6 +29,7 @@ #pragma once #include +#include #include "transport.h" @@ -66,4 +67,4 @@ class UsbTransport : public Transport { typedef std::function ifc_match_func; // 0 is non blocking -UsbTransport* usb_open(ifc_match_func callback, uint32_t timeout_ms = 0); +std::unique_ptr usb_open(ifc_match_func callback, uint32_t timeout_ms = 0); diff --git a/fastboot/usb_linux.cpp b/fastboot/usb_linux.cpp index 964488cc87b5..37bb304ea127 100644 --- a/fastboot/usb_linux.cpp +++ b/fastboot/usb_linux.cpp @@ -503,9 +503,15 @@ int LinuxUsbTransport::Reset() { return 0; } -UsbTransport* usb_open(ifc_match_func callback, uint32_t timeout_ms) { +std::unique_ptr usb_open(ifc_match_func callback, uint32_t timeout_ms) { + std::unique_ptr result; std::unique_ptr handle = find_usb_device("/sys/bus/usb/devices", callback); - return handle ? new LinuxUsbTransport(std::move(handle), timeout_ms) : nullptr; + + if (handle) { + result = std::make_unique(std::move(handle), timeout_ms); + } + + return result; } /* Wait for the system to notice the device is gone, so that a subsequent diff --git a/fastboot/usb_osx.cpp b/fastboot/usb_osx.cpp index 8b852f567a1f..28300b2e1808 100644 --- a/fastboot/usb_osx.cpp +++ b/fastboot/usb_osx.cpp @@ -469,16 +469,20 @@ static int init_usb(ifc_match_func callback, std::unique_ptr* handle /* * Definitions of this file's public functions. */ - -UsbTransport* usb_open(ifc_match_func callback, uint32_t timeout_ms) { +std::unique_ptr usb_open(ifc_match_func callback, uint32_t timeout_ms) { + std::unique_ptr result; std::unique_ptr handle; if (init_usb(callback, &handle) < 0) { /* Something went wrong initializing USB. */ - return nullptr; + return result; + } + + if (handle) { + result = std::make_unique(std::move(handle), timeout_ms); } - return new OsxUsbTransport(std::move(handle), timeout_ms); + return result; } OsxUsbTransport::~OsxUsbTransport() { diff --git a/fastboot/usb_windows.cpp b/fastboot/usb_windows.cpp index 67bf8a30bf24..56a6e7d0e70d 100644 --- a/fastboot/usb_windows.cpp +++ b/fastboot/usb_windows.cpp @@ -381,7 +381,13 @@ static std::unique_ptr find_usb_device(ifc_match_func callback) { return handle; } -UsbTransport* usb_open(ifc_match_func callback, uint32_t) { +std::unique_ptr usb_open(ifc_match_func callback, uint32_t) { + std::unique_ptr result; std::unique_ptr handle = find_usb_device(callback); - return handle ? new WindowsUsbTransport(std::move(handle)) : nullptr; + + if (handle) { + result = std::make_unique(std::move(handle)); + } + + return result; } From e474f21a45b5e2b8973ffd378b119bf378cd0282 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Chen Date: Mon, 4 Sep 2023 11:16:34 +0800 Subject: [PATCH 0352/1487] Check the ABI of libutils for vendor and product only It is not necessary to compare the dumps with the library installed in system partition. Test: m out/target/product/generic_x86_64/lsdump_paths.txt Bug: 280008249 Change-Id: I8fc39ad17d37cd43bf1d77ba23dde55d05dadce1 --- libutils/Android.bp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/libutils/Android.bp b/libutils/Android.bp index 162f0f44b73e..2c05fbc24cc5 100644 --- a/libutils/Android.bp +++ b/libutils/Android.bp @@ -185,10 +185,21 @@ cc_library { support_system_process: true, }, - header_abi_checker: { - // AFDO affects weak symbols. - diff_flags: ["-allow-adding-removing-weak-symbols"], - ref_dump_dirs: ["abi-dumps"], + target: { + product: { + header_abi_checker: { + // AFDO affects weak symbols. + diff_flags: ["-allow-adding-removing-weak-symbols"], + ref_dump_dirs: ["abi-dumps"], + }, + }, + vendor: { + header_abi_checker: { + // AFDO affects weak symbols. + diff_flags: ["-allow-adding-removing-weak-symbols"], + ref_dump_dirs: ["abi-dumps"], + }, + }, }, } From 671a2a551a8f40c7d54ff30b148fd79dc8de0053 Mon Sep 17 00:00:00 2001 From: Chun-Wei Wang Date: Wed, 30 Aug 2023 07:55:43 +0000 Subject: [PATCH 0353/1487] Add a fastboot command to show GSI status The command will be used by RMA tool to skip device wiping when it is already in GSI mode. This change also makes it easier to add more gsi commands in the future without needing to update the host side tool (fastboot). Bug: 298130522 Bug: 298138572 Test: 1. reboot into fastboot mode 2. fastboot gsi status Change-Id: Ic81f89a93b854f9ec70aebe2d209bfd1f98e3645 --- fastboot/device/commands.cpp | 11 +++++++++++ fastboot/fastboot.cpp | 12 +++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp index e929f42c2402..d60539332aea 100644 --- a/fastboot/device/commands.cpp +++ b/fastboot/device/commands.cpp @@ -661,6 +661,17 @@ bool GsiHandler(FastbootDevice* device, const std::vector& args) { if (!android::gsi::DisableGsi()) { return device->WriteStatus(FastbootResult::FAIL, strerror(errno)); } + } else if (args[1] == "status") { + std::string active_dsu; + if (!android::gsi::IsGsiRunning()) { + device->WriteInfo("Not running"); + } else if (!android::gsi::GetActiveDsu(&active_dsu)) { + return device->WriteFail(strerror(errno)); + } else { + device->WriteInfo("Running active DSU: " + active_dsu); + } + } else { + return device->WriteFail("Invalid arguments"); } return device->WriteStatus(FastbootResult::OKAY, "Success"); } diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 71a228ea1053..f76afba0bda7 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -2579,14 +2579,12 @@ int FastBootTool::Main(int argc, char* argv[]) { std::make_unique(fp.get(), partition, size, fp->slot_override); resize_task->Run(); } else if (command == "gsi") { - std::string arg = next_arg(&args); - if (arg == "wipe") { - fb->RawCommand("gsi:wipe", "wiping GSI"); - } else if (arg == "disable") { - fb->RawCommand("gsi:disable", "disabling GSI"); - } else { - syntax_error("expected 'wipe' or 'disable'"); + if (args.empty()) syntax_error("invalid gsi command"); + std::string cmd("gsi"); + while (!args.empty()) { + cmd += ":" + next_arg(&args); } + fb->RawCommand(cmd, ""); } else if (command == "wipe-super") { std::string image; if (args.empty()) { From e3bda36e0be2ad690ec48666d56eefcb26489378 Mon Sep 17 00:00:00 2001 From: Andrei Diea Date: Tue, 5 Sep 2023 19:29:13 +0000 Subject: [PATCH 0354/1487] debuggerd: add socksetopt to seccomp policy aosp/2734054 added socket timeouts for nonblocking liblog ops. seccomp policy was not updated so tests failed when unallowed socksetopt syscall was made. Bug: 298420226 Test: atest debuggerd_test Change-Id: Iace232ec8b94e5d316d344abc5d866fe314607e0 Signed-off-by: Andrei Diea --- debuggerd/seccomp_policy/crash_dump.arm.policy | 1 + debuggerd/seccomp_policy/crash_dump.arm64.policy | 1 + debuggerd/seccomp_policy/crash_dump.policy.def | 1 + debuggerd/seccomp_policy/crash_dump.riscv64.policy | 1 + debuggerd/seccomp_policy/crash_dump.x86.policy | 1 + debuggerd/seccomp_policy/crash_dump.x86_64.policy | 1 + 6 files changed, 6 insertions(+) diff --git a/debuggerd/seccomp_policy/crash_dump.arm.policy b/debuggerd/seccomp_policy/crash_dump.arm.policy index 8fd03c4273ce..a70ab203d257 100644 --- a/debuggerd/seccomp_policy/crash_dump.arm.policy +++ b/debuggerd/seccomp_policy/crash_dump.arm.policy @@ -20,6 +20,7 @@ getdents64: 1 faccessat: 1 recvmsg: 1 recvfrom: 1 +setsockopt: 1 sysinfo: 1 process_vm_readv: 1 tgkill: 1 diff --git a/debuggerd/seccomp_policy/crash_dump.arm64.policy b/debuggerd/seccomp_policy/crash_dump.arm64.policy index 8241f0ee443b..adf87380e4bf 100644 --- a/debuggerd/seccomp_policy/crash_dump.arm64.policy +++ b/debuggerd/seccomp_policy/crash_dump.arm64.policy @@ -19,6 +19,7 @@ getdents64: 1 faccessat: 1 recvmsg: 1 recvfrom: 1 +setsockopt: 1 sysinfo: 1 process_vm_readv: 1 tgkill: 1 diff --git a/debuggerd/seccomp_policy/crash_dump.policy.def b/debuggerd/seccomp_policy/crash_dump.policy.def index 0cb8e081dfff..972a575457b5 100644 --- a/debuggerd/seccomp_policy/crash_dump.policy.def +++ b/debuggerd/seccomp_policy/crash_dump.policy.def @@ -26,6 +26,7 @@ faccessat: 1 recvmsg: 1 recvfrom: 1 sysinfo: 1 +setsockopt: 1 process_vm_readv: 1 diff --git a/debuggerd/seccomp_policy/crash_dump.riscv64.policy b/debuggerd/seccomp_policy/crash_dump.riscv64.policy index 281e231b0135..94a56772a672 100644 --- a/debuggerd/seccomp_policy/crash_dump.riscv64.policy +++ b/debuggerd/seccomp_policy/crash_dump.riscv64.policy @@ -19,6 +19,7 @@ getdents64: 1 faccessat: 1 recvmsg: 1 recvfrom: 1 +setsockopt: 1 sysinfo: 1 process_vm_readv: 1 tgkill: 1 diff --git a/debuggerd/seccomp_policy/crash_dump.x86.policy b/debuggerd/seccomp_policy/crash_dump.x86.policy index 8fd03c4273ce..a70ab203d257 100644 --- a/debuggerd/seccomp_policy/crash_dump.x86.policy +++ b/debuggerd/seccomp_policy/crash_dump.x86.policy @@ -20,6 +20,7 @@ getdents64: 1 faccessat: 1 recvmsg: 1 recvfrom: 1 +setsockopt: 1 sysinfo: 1 process_vm_readv: 1 tgkill: 1 diff --git a/debuggerd/seccomp_policy/crash_dump.x86_64.policy b/debuggerd/seccomp_policy/crash_dump.x86_64.policy index 281e231b0135..94a56772a672 100644 --- a/debuggerd/seccomp_policy/crash_dump.x86_64.policy +++ b/debuggerd/seccomp_policy/crash_dump.x86_64.policy @@ -19,6 +19,7 @@ getdents64: 1 faccessat: 1 recvmsg: 1 recvfrom: 1 +setsockopt: 1 sysinfo: 1 process_vm_readv: 1 tgkill: 1 From f83c5c8fecf89d9315945368aa20350c2f235cc0 Mon Sep 17 00:00:00 2001 From: Keith Mok Date: Thu, 31 Aug 2023 00:31:35 +0000 Subject: [PATCH 0355/1487] Add seal if ashmem-dev is backed by memfd Need to seal the buffer size in align with ashmem if set to PROT_READ only to prevent untrusted remote process to shrink the buffer size and crash it. Bug: 294609150 Test: build Ignore-AOSP-First: Security Change-Id: I9288cf30b41e84ad8d3247c204e20482912bff69 --- libcutils/ashmem-dev.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp index 6a27f9a2004b..56d68759f348 100644 --- a/libcutils/ashmem-dev.cpp +++ b/libcutils/ashmem-dev.cpp @@ -349,6 +349,12 @@ static int memfd_create_region(const char* name, size_t size) { return -1; } + // forbid size changes to match ashmem behaviour + if (fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK) == -1) { + ALOGE("memfd_create(%s, %zd) F_ADD_SEALS failed: %m", name, size); + return -1; + } + if (debug_log) { ALOGE("memfd_create(%s, %zd) success. fd=%d\n", name, size, fd.get()); } @@ -400,14 +406,29 @@ int ashmem_create_region(const char *name, size_t size) } static int memfd_set_prot_region(int fd, int prot) { - /* Only proceed if an fd needs to be write-protected */ + int seals = fcntl(fd, F_GET_SEALS); + if (seals == -1) { + ALOGE("memfd_set_prot_region(%d, %d): F_GET_SEALS failed: %s\n", fd, prot, strerror(errno)); + return -1; + } + if (prot & PROT_WRITE) { + /* Now we want the buffer to be read-write, let's check if the buffer + * has been previously marked as read-only before, if so return error + */ + if (seals & F_SEAL_FUTURE_WRITE) { + ALOGE("memfd_set_prot_region(%d, %d): region is write protected\n", fd, prot); + errno = EINVAL; // inline with ashmem error code, if already in + // read-only mode + return -1; + } return 0; } - if (fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE) == -1) { - ALOGE("memfd_set_prot_region(%d, %d): F_SEAL_FUTURE_WRITE seal failed: %s\n", fd, prot, - strerror(errno)); + /* We would only allow read-only for any future file operations */ + if (fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE | F_SEAL_SEAL) == -1) { + ALOGE("memfd_set_prot_region(%d, %d): F_SEAL_FUTURE_WRITE | F_SEAL_SEAL seal failed: %s\n", + fd, prot, strerror(errno)); return -1; } From 214d62e3f79a80e1c8e1cd466f2b2412f56e2894 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Mon, 4 Sep 2023 00:47:19 -0700 Subject: [PATCH 0356/1487] create_snapshot: Create snapshot patch comparing two partition images This is a host based tool wherein it compares two Android images and generates snapshot patches which are similar to Android OTA format. There are few advantages: 1: All the computation of snapshot logic is pushed onto the host. 2: Each partition can have different compression algorithm. 3: All the libsnapshot_cow changes can be tested very quickly. Here is the test run. This compares two builds which are 24 hours apart. ``` create_snapshot --source=$ANDROID_PRODUCT_OUT/system.img --target=./images/system.img --compression="zstd" & create_snapshot --source=$ANDROID_PRODUCT_OUT/product.img --target=./images/product.img --compression="lz4" & create_snapshot --source=$ANDROID_PRODUCT_OUT/vendor.img --target=./images/vendor.img & create_snapshot --source=$ANDROID_PRODUCT_OUT/system_ext.img --target=./images/system_ext.img --compression="gz" & create_snapshot --source=$ANDROID_PRODUCT_OUT/vendor_dlkm.img --target=./images/vendor_dlkm.img & echo "Waiting for snapshot patch creation" wait $(jobs -p) echo "Snapshot patch creation completed" ``` ======================================== Waiting for snapshot patch creation Snapshot patch: vendor_dlkm.patch created successfully Snapshot patch: vendor.patch created successfully Snapshot patch: system_ext.patch created successfully Snapshot patch: product.patch created successfully Snapshot patch: system.patch created successfully Snapshot patch creation completed real 0m3.848s user 0m14.239s sys 0m8.045s ======================================== It takes ~4 seconds to generate the snapshot patches on the host. Snapshot patches are named as .patch. Bug: 299011882 Test: create_snapshot between two builds as mentioned above. Change-Id: Ic87dd3349a866b5626fa03f1f879f417a8116cc2 Signed-off-by: Akilesh Kailash --- fs_mgr/libsnapshot/Android.bp | 32 ++ .../libsnapshot_cow/create_cow.cpp | 359 ++++++++++++++++++ 2 files changed, 391 insertions(+) create mode 100644 fs_mgr/libsnapshot/libsnapshot_cow/create_cow.cpp diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index 04b5a021ad5f..b0f2b846d5ec 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -446,6 +446,38 @@ cc_binary { ], } +cc_binary { + name: "create_snapshot", + host_supported: true, + device_supported: false, + + srcs: ["libsnapshot_cow/create_cow.cpp"], + + cflags: [ + "-Wall", + "-Werror", + ], + + static_libs: [ + "liblog", + "libbase", + "libext4_utils", + "libsnapshot_cow", + "libcrypto", + "libbrotli", + "libz", + "liblz4", + "libzstd", + "libgflags", + ], + shared_libs: [ + ], + + header_libs: [ + "libstorage_literals_headers", + ], +} + python_library_host { name: "snapshot_proto_python", srcs: [ diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/create_cow.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/create_cow.cpp new file mode 100644 index 000000000000..4e07fe3b3e0b --- /dev/null +++ b/fs_mgr/libsnapshot/libsnapshot_cow/create_cow.cpp @@ -0,0 +1,359 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +DEFINE_string(source, "", "Source partition image"); +DEFINE_string(target, "", "Target partition image"); +DEFINE_string(compression, "lz4", + "Compression algorithm. Default is set to lz4. Available options: lz4, zstd, gz"); + +namespace android { +namespace snapshot { + +using namespace android::storage_literals; +using namespace android; +using android::base::unique_fd; + +using android::snapshot::CreateCowWriter; +using android::snapshot::ICowWriter; + +class CreateSnapshot { + public: + CreateSnapshot(const std::string& src_file, const std::string& target_file, + const std::string& patch_file, const std::string& compression); + bool CreateSnapshotPatch(); + + private: + /* source.img */ + std::string src_file_; + /* target.img */ + std::string target_file_; + /* snapshot-patch generated */ + std::string patch_file_; + + /* + * Active file which is being parsed by this instance. + * It will either be source.img or target.img. + */ + std::string parsing_file_; + bool create_snapshot_patch_ = false; + + const int kNumThreads = 6; + const size_t kBlockSizeToRead = 1_MiB; + + std::unordered_map source_block_hash_; + std::mutex source_block_hash_lock_; + + std::unique_ptr writer_; + std::mutex write_lock_; + + std::unique_ptr zblock_; + + std::string compression_ = "lz4"; + unique_fd fd_; + + const int BLOCK_SZ = 4_KiB; + void SHA256(const void* data, size_t length, uint8_t out[32]); + bool IsBlockAligned(uint64_t read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } + bool ReadBlocks(off_t offset, const int skip_blocks, const uint64_t dev_sz); + std::string ToHexString(const uint8_t* buf, size_t len); + + bool CreateSnapshotFile(); + bool FindSourceBlockHash(); + bool PrepareParse(std::string& parsing_file, const bool createSnapshot); + bool ParsePartition(); + bool WriteSnapshot(const void* buffer, uint64_t block, std::string& block_hash); +}; + +void CreateSnapshotLogger(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); + } +} + +CreateSnapshot::CreateSnapshot(const std::string& src_file, const std::string& target_file, + const std::string& patch_file, const std::string& compression) + : src_file_(src_file), target_file_(target_file), patch_file_(patch_file) { + if (!compression.empty()) { + compression_ = compression; + } +} + +bool CreateSnapshot::PrepareParse(std::string& parsing_file, const bool createSnapshot) { + parsing_file_ = parsing_file; + create_snapshot_patch_ = createSnapshot; + + if (createSnapshot) { + fd_.reset(open(patch_file_.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666)); + if (fd_ < 0) { + PLOG(ERROR) << "Failed to open the snapshot-patch file: " << patch_file_; + return false; + } + + zblock_ = std::make_unique(BLOCK_SZ); + std::memset(zblock_.get(), 0, BLOCK_SZ); + + CowOptions options; + options.compression = compression_; + options.num_compress_threads = 2; + options.batch_write = true; + options.cluster_ops = 600; + writer_ = CreateCowWriter(2, options, std::move(fd_)); + } + return true; +} + +/* + * Create per-block sha256 hash of source partition + */ +bool CreateSnapshot::FindSourceBlockHash() { + if (!PrepareParse(src_file_, false)) { + return false; + } + return ParsePartition(); +} + +/* + * Create snapshot file by comparing sha256 per block + * of target.img with the constructed per-block sha256 hash + * of source partition. + */ +bool CreateSnapshot::CreateSnapshotFile() { + if (!PrepareParse(target_file_, true)) { + return false; + } + return ParsePartition(); +} + +/* + * Creates snapshot patch file by comparing source.img and target.img + */ +bool CreateSnapshot::CreateSnapshotPatch() { + if (!FindSourceBlockHash()) { + return false; + } + return CreateSnapshotFile(); +} + +void CreateSnapshot::SHA256(const void* data, size_t length, uint8_t out[32]) { + SHA256_CTX c; + SHA256_Init(&c); + SHA256_Update(&c, data, length); + SHA256_Final(out, &c); +} + +std::string CreateSnapshot::ToHexString(const uint8_t* buf, size_t len) { + char lookup[] = "0123456789abcdef"; + std::string out(len * 2 + 1, '\0'); + char* outp = out.data(); + for (; len > 0; len--, buf++) { + *outp++ = (char)lookup[*buf >> 4]; + *outp++ = (char)lookup[*buf & 0xf]; + } + return out; +} + +bool CreateSnapshot::WriteSnapshot(const void* buffer, uint64_t block, std::string& block_hash) { + if (std::memcmp(zblock_.get(), buffer, BLOCK_SZ) == 0) { + std::lock_guard lock(write_lock_); + return writer_->AddZeroBlocks(block, 1); + } + + auto iter = source_block_hash_.find(block_hash); + if (iter != source_block_hash_.end()) { + std::lock_guard lock(write_lock_); + return writer_->AddCopy(block, iter->second, 1); + } + std::lock_guard lock(write_lock_); + return writer_->AddRawBlocks(block, buffer, BLOCK_SZ); +} + +bool CreateSnapshot::ReadBlocks(off_t offset, const int skip_blocks, const uint64_t dev_sz) { + unique_fd fd(TEMP_FAILURE_RETRY(open(parsing_file_.c_str(), O_RDONLY))); + if (fd < 0) { + LOG(ERROR) << "open failed: " << parsing_file_; + return false; + } + + loff_t file_offset = offset; + const uint64_t read_sz = kBlockSizeToRead; + std::unique_ptr buffer = std::make_unique(read_sz); + + while (true) { + size_t to_read = std::min((dev_sz - file_offset), read_sz); + + if (!android::base::ReadFullyAtOffset(fd.get(), buffer.get(), to_read, file_offset)) { + LOG(ERROR) << "Failed to read block from block device: " << parsing_file_ + << " at offset: " << file_offset << " read-size: " << to_read + << " block-size: " << dev_sz; + return false; + } + + if (!IsBlockAligned(to_read)) { + LOG(ERROR) << "unable to parse the un-aligned request: " << to_read; + return false; + } + + size_t num_blocks = to_read / BLOCK_SZ; + uint64_t buffer_offset = 0; + off_t foffset = file_offset; + + while (num_blocks) { + const void* bufptr = (char*)buffer.get() + buffer_offset; + uint64_t blkindex = foffset / BLOCK_SZ; + + uint8_t checksum[32]; + SHA256(bufptr, BLOCK_SZ, checksum); + std::string hash = ToHexString(checksum, sizeof(checksum)); + + if (create_snapshot_patch_ && !WriteSnapshot(bufptr, blkindex, hash)) { + LOG(ERROR) << "WriteSnapshot failed for block: " << blkindex; + return false; + } else { + std::lock_guard lock(source_block_hash_lock_); + { + if (source_block_hash_.count(hash) == 0) { + source_block_hash_[hash] = blkindex; + } + } + } + buffer_offset += BLOCK_SZ; + foffset += BLOCK_SZ; + num_blocks -= 1; + } + + file_offset += (skip_blocks * kBlockSizeToRead); + if (file_offset >= dev_sz) { + break; + } + } + + return true; +} + +bool CreateSnapshot::ParsePartition() { + unique_fd fd(TEMP_FAILURE_RETRY(open(parsing_file_.c_str(), O_RDONLY))); + if (fd < 0) { + LOG(ERROR) << "open failed: " << parsing_file_; + return false; + } + + uint64_t dev_sz = lseek(fd.get(), 0, SEEK_END); + if (!dev_sz) { + LOG(ERROR) << "Could not determine block device size: " << parsing_file_; + return false; + } + + if (!IsBlockAligned(dev_sz)) { + LOG(ERROR) << "dev_sz: " << dev_sz << " is not block aligned"; + return false; + } + + int num_threads = kNumThreads; + + std::vector> threads; + off_t start_offset = 0; + const int skip_blocks = num_threads; + + while (num_threads) { + threads.emplace_back(std::async(std::launch::async, &CreateSnapshot::ReadBlocks, this, + start_offset, skip_blocks, dev_sz)); + start_offset += kBlockSizeToRead; + num_threads -= 1; + if (start_offset >= dev_sz) { + break; + } + } + + bool ret = true; + for (auto& t : threads) { + ret = t.get() && ret; + } + + if (ret && create_snapshot_patch_ && !writer_->Finalize()) { + LOG(ERROR) << "Finzalize failed"; + return false; + } + + return ret; +} + +} // namespace snapshot +} // namespace android + +constexpr char kUsage[] = R"( +NAME + create_snapshot - Create snapshot patches by comparing two partition images + +SYNOPSIS + create_snapshot --source= --target= --compression=" Source partition image + target.img -> Target partition image + compressoin -> compression algorithm. Default set to lz4. Supported types are gz, lz4, zstd. + +EXAMPLES + + $ create_snapshot $SOURCE_BUILD/system.img $TARGET_BUILD/system.img + $ create_snapshot $SOURCE_BUILD/product.img $TARGET_BUILD/product.img --compression="zstd" + +)"; + +int main(int argc, char* argv[]) { + android::base::InitLogging(argv, &android::snapshot::CreateSnapshotLogger); + ::gflags::SetUsageMessage(kUsage); + ::gflags::ParseCommandLineFlags(&argc, &argv, true); + + if (FLAGS_source.empty() || FLAGS_target.empty()) { + LOG(INFO) << kUsage; + return 0; + } + + std::string fname = android::base::Basename(FLAGS_target.c_str()); + auto parts = android::base::Split(fname, "."); + std::string snapshotfile = parts[0] + ".patch"; + android::snapshot::CreateSnapshot snapshot(FLAGS_source, FLAGS_target, snapshotfile, + FLAGS_compression); + + if (!snapshot.CreateSnapshotPatch()) { + LOG(ERROR) << "Snapshot creation failed"; + return -1; + } + + LOG(INFO) << "Snapshot patch: " << snapshotfile << " created successfully"; + return 0; +} From 50f03fd58e4cfd75cbdde1d779893f66485e4a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=C3=A9baud=20Weksteen?= Date: Wed, 6 Sep 2023 10:52:49 +1000 Subject: [PATCH 0357/1487] Revert "Use Apex sepolicy if it's available" This reverts commit baeece6d0c0ff72f667318ec365e5281955c8f42. Test: boot aosp_cf_x86_64_phone-userdebug Bug: 297794885 Change-Id: I0515bc30eba42589c407deb587684b4da011aead --- init/Android.bp | 3 - init/property_service.cpp | 4 - init/selinux.cpp | 247 +++----------------------------------- 3 files changed, 16 insertions(+), 238 deletions(-) diff --git a/init/Android.bp b/init/Android.bp index d4852d6483be..4c25ad7b7adc 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -174,7 +174,6 @@ libinit_cc_defaults { "libprotobuf-cpp-lite", "libpropertyinfoserializer", "libpropertyinfoparser", - "libsigningutils", "libsnapshot_cow", "libsnapshot_init", "libxml2", @@ -183,7 +182,6 @@ libinit_cc_defaults { ], shared_libs: [ "libbase", - "libcrypto", "libcutils", "libdl", "libext4_utils", @@ -199,7 +197,6 @@ libinit_cc_defaults { "libselinux", "libunwindstack", "libutils", - "libziparchive", ], header_libs: ["bionic_libc_platform_headers"], bootstrap: true, diff --git a/init/property_service.cpp b/init/property_service.cpp index f5de17d82bf1..2064fae8f14c 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -1247,9 +1247,6 @@ void CreateSerializedPropertyInfo() { // Don't check for failure here, since we don't always have all of these partitions. // E.g. In case of recovery, the vendor partition will not have mounted and we // still need the system / platform properties to function. - if (access("/dev/selinux/apex_property_contexts", R_OK) != -1) { - LoadPropertyInfoFromFile("/dev/selinux/apex_property_contexts", &property_infos); - } if (access("/system_ext/etc/selinux/system_ext_property_contexts", R_OK) != -1) { LoadPropertyInfoFromFile("/system_ext/etc/selinux/system_ext_property_contexts", &property_infos); @@ -1273,7 +1270,6 @@ void CreateSerializedPropertyInfo() { LoadPropertyInfoFromFile("/vendor_property_contexts", &property_infos); LoadPropertyInfoFromFile("/product_property_contexts", &property_infos); LoadPropertyInfoFromFile("/odm_property_contexts", &property_infos); - LoadPropertyInfoFromFile("/dev/selinux/apex_property_contexts", &property_infos); } auto serialized_contexts = std::string(); diff --git a/init/selinux.cpp b/init/selinux.cpp index ac102eb4e4ce..9095b854eb18 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -26,29 +26,26 @@ // The monolithic policy variant is for legacy non-treble devices that contain a single SEPolicy // file located at /sepolicy and is directly loaded into the kernel SELinux subsystem. -// The split policy is for supporting treble devices and updateable apexes. It splits the SEPolicy -// across files on /system/etc/selinux (the 'plat' portion of the policy), /vendor/etc/selinux -// (the 'vendor' portion of the policy), /system_ext/etc/selinux, /product/etc/selinux, -// /odm/etc/selinux, and /dev/selinux (the apex portion of policy). This is necessary to allow -// images to be updated independently of the vendor image, while maintaining contributions from -// multiple partitions in the SEPolicy. This is especially important for VTS testing, where the -// SEPolicy on the Google System Image may not be identical to the system image shipped on a -// vendor's device. +// The split policy is for supporting treble devices. It splits the SEPolicy across files on +// /system/etc/selinux (the 'plat' portion of the policy) and /vendor/etc/selinux (the 'vendor' +// portion of the policy). This is necessary to allow the system image to be updated independently +// of the vendor image, while maintaining contributions from both partitions in the SEPolicy. This +// is especially important for VTS testing, where the SEPolicy on the Google System Image may not be +// identical to the system image shipped on a vendor's device. // The split SEPolicy is loaded as described below: // 1) There is a precompiled SEPolicy located at either /vendor/etc/selinux/precompiled_sepolicy or // /odm/etc/selinux/precompiled_sepolicy if odm parition is present. Stored along with this file -// are the sha256 hashes of the parts of the SEPolicy on /system, /system_ext, /product, and apex -// that were used to compile this precompiled policy. The system partition contains a similar -// sha256 of the parts of the SEPolicy that it currently contains. Symmetrically, system_ext, -// product, and apex contain sha256 hashes of their SEPolicy. Init loads this +// are the sha256 hashes of the parts of the SEPolicy on /system, /system_ext and /product that +// were used to compile this precompiled policy. The system partition contains a similar sha256 +// of the parts of the SEPolicy that it currently contains. Symmetrically, system_ext and +// product paritition contain sha256 hashes of their SEPolicy. The init loads this // precompiled_sepolicy directly if and only if the hashes along with the precompiled SEPolicy on -// /vendor or /odm match the hashes for system, system_ext, product, and apex SEPolicy, -// respectively. -// 2) If these hashes do not match, then either /system or /system_ext /product, or apex (or some of -// them) have been updated out of sync with /vendor (or /odm if it is present) and the init needs -// to compile the SEPolicy. /system contains the SEPolicy compiler, secilc, and it is used by -// the OpenSplitPolicy() function below to compile the SEPolicy to a temp directory and load it. +// /vendor or /odm match the hashes for system, system_ext and product SEPolicy, respectively. +// 2) If these hashes do not match, then either /system or /system_ext or /product (or some of them) +// have been updated out of sync with /vendor (or /odm if it is present) and the init needs to +// compile the SEPolicy. /system contains the SEPolicy compiler, secilc, and it is used by the +// OpenSplitPolicy() function below to compile the SEPolicy to a temp directory and load it. // That function contains even more documentation with the specific implementation details of how // the SEPolicy is compiled if needed. @@ -61,15 +58,12 @@ #include #include #include -#include -#include #include #include #include #include #include -#include #include #include #include @@ -77,7 +71,6 @@ #include #include #include -#include #include "block_dev_initializer.h" #include "debug_ramdisk.h" @@ -245,7 +238,6 @@ Result FindPrecompiledSplitPolicy() { precompiled_sepolicy + ".system_ext_sepolicy_and_mapping.sha256"}, {"/product/etc/selinux/product_sepolicy_and_mapping.sha256", precompiled_sepolicy + ".product_sepolicy_and_mapping.sha256"}, - {"/dev/selinux/apex_sepolicy.sha256", precompiled_sepolicy + ".apex_sepolicy.sha256"}, }; for (const auto& [actual_id_path, precompiled_id_path] : sepolicy_hashes) { @@ -324,7 +316,7 @@ bool OpenSplitPolicy(PolicyFile* policy_file) { // * vendor -- policy needed due to logic contained in the vendor image, // * mapping -- mapping policy which helps preserve forward-compatibility of non-platform policy // with newer versions of platform policy. - // * (optional) policy needed due to logic on product, system_ext, odm, or apex. + // * (optional) policy needed due to logic on product, system_ext, or odm images. // secilc is invoked to compile the above three policy files into a single monolithic policy // file. This file is then loaded into the kernel. @@ -420,12 +412,6 @@ bool OpenSplitPolicy(PolicyFile* policy_file) { if (access(odm_policy_cil_file.c_str(), F_OK) == -1) { odm_policy_cil_file.clear(); } - - // apex_sepolicy.cil is default but optional. - std::string apex_policy_cil_file("/dev/selinux/apex_sepolicy.cil"); - if (access(apex_policy_cil_file.c_str(), F_OK) == -1) { - apex_policy_cil_file.clear(); - } const std::string version_as_string = std::to_string(SEPOLICY_VERSION); // clang-format off @@ -468,9 +454,6 @@ bool OpenSplitPolicy(PolicyFile* policy_file) { if (!odm_policy_cil_file.empty()) { compile_args.push_back(odm_policy_cil_file.c_str()); } - if (!apex_policy_cil_file.empty()) { - compile_args.push_back(apex_policy_cil_file.c_str()); - } compile_args.push_back(nullptr); if (!ForkExecveAndWaitForCompletion(compile_args[0], (char**)compile_args.data())) { @@ -497,194 +480,6 @@ bool OpenMonolithicPolicy(PolicyFile* policy_file) { return true; } -constexpr const char* kSigningCertRelease = - "/system/etc/selinux/com.android.sepolicy.cert-release.der"; -const std::string kSepolicyApexMetadataDir = "/metadata/sepolicy/"; -const std::string kSepolicyApexSystemDir = "/system/etc/selinux/apex/"; -const std::string kSepolicyZip = "SEPolicy.zip"; -const std::string kSepolicySignature = "SEPolicy.zip.sig"; - -const std::string kTmpfsDir = "/dev/selinux/"; - -// Files that are deleted after policy is compiled/loaded. -const std::vector kApexSepolicyTmp{"apex_sepolicy.cil", "apex_sepolicy.sha256"}; -// Files that need to persist because they are used by userspace processes. -const std::vector kApexSepolicy{"apex_file_contexts", "apex_property_contexts", - "apex_service_contexts", "apex_seapp_contexts", - "apex_test"}; - -Result CreateTmpfsDir() { - mode_t mode = 0744; - struct stat stat_data; - if (stat(kTmpfsDir.c_str(), &stat_data) != 0) { - if (errno != ENOENT) { - return ErrnoError() << "Could not stat " << kTmpfsDir; - } - if (mkdir(kTmpfsDir.c_str(), mode) != 0) { - return ErrnoError() << "Could not mkdir " << kTmpfsDir; - } - } else { - if (!S_ISDIR(stat_data.st_mode)) { - return Error() << kTmpfsDir << " exists and is not a directory."; - } - LOG(WARNING) << "Directory " << kTmpfsDir << " already exists"; - } - - // Need to manually call chmod because mkdir will create a folder with - // permissions mode & ~umask. - if (chmod(kTmpfsDir.c_str(), mode) != 0) { - return ErrnoError() << "Could not chmod " << kTmpfsDir; - } - - return {}; -} - -Result PutFileInTmpfs(ZipArchiveHandle archive, const std::string& fileName) { - ZipEntry entry; - std::string dstPath = kTmpfsDir + fileName; - - int ret = FindEntry(archive, fileName, &entry); - if (ret != 0) { - // All files are optional. If a file doesn't exist, return without error. - return {}; - } - - unique_fd fd(TEMP_FAILURE_RETRY( - open(dstPath.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRUSR | S_IWUSR))); - if (fd == -1) { - return ErrnoError() << "Failed to open " << dstPath; - } - - ret = ExtractEntryToFile(archive, &entry, fd.get()); - if (ret != 0) { - return Error() << "Failed to extract entry \"" << fileName << "\" (" - << entry.uncompressed_length << " bytes) to \"" << dstPath - << "\": " << ErrorCodeString(ret); - } - - return {}; -} - -Result GetPolicyFromApex(const std::string& dir) { - LOG(INFO) << "Loading APEX Sepolicy from " << dir + kSepolicyZip; - unique_fd fd(open((dir + kSepolicyZip).c_str(), O_RDONLY | O_BINARY | O_CLOEXEC)); - if (fd < 0) { - return ErrnoError() << "Failed to open package " << dir + kSepolicyZip; - } - - ZipArchiveHandle handle; - int ret = OpenArchiveFd(fd.get(), (dir + kSepolicyZip).c_str(), &handle, - /*assume_ownership=*/false); - if (ret < 0) { - return Error() << "Failed to open package " << dir + kSepolicyZip << ": " - << ErrorCodeString(ret); - } - - auto handle_guard = android::base::make_scope_guard([&handle] { CloseArchive(handle); }); - - auto create = CreateTmpfsDir(); - if (!create.ok()) { - return create.error(); - } - - for (const auto& file : kApexSepolicy) { - auto extract = PutFileInTmpfs(handle, file); - if (!extract.ok()) { - return extract.error(); - } - } - for (const auto& file : kApexSepolicyTmp) { - auto extract = PutFileInTmpfs(handle, file); - if (!extract.ok()) { - return extract.error(); - } - } - return {}; -} - -Result SepolicyCheckSignature(const std::string& dir) { - std::string signature; - if (!android::base::ReadFileToString(dir + kSepolicySignature, &signature)) { - return ErrnoError() << "Failed to read " << kSepolicySignature; - } - - std::fstream sepolicyZip(dir + kSepolicyZip, std::ios::in | std::ios::binary); - if (!sepolicyZip) { - return Error() << "Failed to open " << kSepolicyZip; - } - sepolicyZip.seekg(0); - std::string sepolicyStr((std::istreambuf_iterator(sepolicyZip)), - std::istreambuf_iterator()); - - auto releaseKey = extractPublicKeyFromX509(kSigningCertRelease); - if (!releaseKey.ok()) { - return releaseKey.error(); - } - - return verifySignature(sepolicyStr, signature, *releaseKey); -} - -Result SepolicyVerify(const std::string& dir) { - auto sepolicySignature = SepolicyCheckSignature(dir); - if (!sepolicySignature.ok()) { - return Error() << "Apex SEPolicy failed signature check"; - } - return {}; -} - -void CleanupApexSepolicy() { - for (const auto& file : kApexSepolicyTmp) { - std::string path = kTmpfsDir + file; - unlink(path.c_str()); - } -} - -// Updatable sepolicy is shipped within an zip within an APEX. Because -// it needs to be available before Apexes are mounted, apexd copies -// the zip from the APEX and stores it in /metadata/sepolicy. If there is -// no updatable sepolicy in /metadata/sepolicy, then the updatable policy is -// loaded from /system/etc/selinux/apex. Init performs the following -// steps on boot: -// -// 1. Validates the zip by checking its signature against a public key that is -// stored in /system/etc/selinux. -// 2. Extracts files from zip and stores them in /dev/selinux. -// 3. Checks if the apex_sepolicy.sha256 matches the sha256 of precompiled_sepolicy. -// if so, the precompiled sepolicy is used. Otherwise, an on-device compile of the policy -// is used. This is the same flow as on-device compilation of policy for Treble. -// 4. Cleans up files in /dev/selinux which are no longer needed. -// 5. Restorecons the remaining files in /dev/selinux. -// 6. Sets selinux into enforcing mode and continues normal booting. -// -void PrepareApexSepolicy() { - // If apex sepolicy zip exists in /metadata/sepolicy, use that, otherwise use version on - // /system. If neither exists, do nothing. - std::string dir; - if (access((kSepolicyApexMetadataDir + kSepolicyZip).c_str(), F_OK) == 0) { - dir = kSepolicyApexMetadataDir; - } else if (access((kSepolicyApexSystemDir + kSepolicyZip).c_str(), F_OK) == 0) { - dir = kSepolicyApexSystemDir; - } else { - LOG(INFO) << "APEX Sepolicy not found"; - return; - } - - auto sepolicyVerify = SepolicyVerify(dir); - if (!sepolicyVerify.ok()) { - LOG(INFO) << "Error: " << sepolicyVerify.error(); - // If signature verification fails, fall back to version on /system. - // This file doesn't need to be verified because it lives on the system partition which - // is signed and protected by verified boot. - dir = kSepolicyApexSystemDir; - } - - auto apex = GetPolicyFromApex(dir); - if (!apex.ok()) { - // TODO(b/199914227) Make failure fatal. For now continue booting with non-apex sepolicy. - LOG(ERROR) << apex.error(); - } -} - void ReadPolicy(std::string* policy) { PolicyFile policy_file; @@ -961,12 +756,9 @@ void LoadSelinuxPolicyAndroid() { LOG(INFO) << "Opening SELinux policy"; - PrepareApexSepolicy(); - // Read the policy before potentially killing snapuserd. std::string policy; ReadPolicy(&policy); - CleanupApexSepolicy(); auto snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded(); if (snapuserd_helper) { @@ -982,13 +774,6 @@ void LoadSelinuxPolicyAndroid() { snapuserd_helper->FinishTransition(); snapuserd_helper = nullptr; } - - // This restorecon is intentionally done before SelinuxSetEnforcement because the permissions - // needed to transition files from tmpfs to *_contexts_file context should not be granted to - // any process after selinux is set into enforcing mode. - if (selinux_android_restorecon("/dev/selinux/", SELINUX_ANDROID_RESTORECON_RECURSE) == -1) { - PLOG(FATAL) << "restorecon failed of /dev/selinux failed"; - } } int SetupSelinux(char** argv) { From e433fde7d21d01d0d671a6bd24b5e15aa577e0e0 Mon Sep 17 00:00:00 2001 From: Chun-Wei Wang Date: Wed, 30 Aug 2023 07:55:43 +0000 Subject: [PATCH 0358/1487] Add a fastboot command to show GSI status The command will be used by RMA tool to skip device wiping when it is already in GSI mode. This change also makes it easier to add more gsi commands in the future without needing to update the host side tool (fastboot). (Cherry-picked from aosp/2735077) Bug: 298533290 Bug: 298138572 Test: 1. reboot into fastboot mode 2. fastboot gsi status Merged-In: Ic81f89a93b854f9ec70aebe2d209bfd1f98e3645 Change-Id: Ic81f89a93b854f9ec70aebe2d209bfd1f98e3645 --- fastboot/device/commands.cpp | 11 +++++++++++ fastboot/fastboot.cpp | 12 +++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp index e929f42c2402..d60539332aea 100644 --- a/fastboot/device/commands.cpp +++ b/fastboot/device/commands.cpp @@ -661,6 +661,17 @@ bool GsiHandler(FastbootDevice* device, const std::vector& args) { if (!android::gsi::DisableGsi()) { return device->WriteStatus(FastbootResult::FAIL, strerror(errno)); } + } else if (args[1] == "status") { + std::string active_dsu; + if (!android::gsi::IsGsiRunning()) { + device->WriteInfo("Not running"); + } else if (!android::gsi::GetActiveDsu(&active_dsu)) { + return device->WriteFail(strerror(errno)); + } else { + device->WriteInfo("Running active DSU: " + active_dsu); + } + } else { + return device->WriteFail("Invalid arguments"); } return device->WriteStatus(FastbootResult::OKAY, "Success"); } diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index cdcd0363a2fc..037916ea4418 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -2565,14 +2565,12 @@ int FastBootTool::Main(int argc, char* argv[]) { std::make_unique(fp.get(), partition, size, fp->slot_override); resize_task->Run(); } else if (command == "gsi") { - std::string arg = next_arg(&args); - if (arg == "wipe") { - fb->RawCommand("gsi:wipe", "wiping GSI"); - } else if (arg == "disable") { - fb->RawCommand("gsi:disable", "disabling GSI"); - } else { - syntax_error("expected 'wipe' or 'disable'"); + if (args.empty()) syntax_error("invalid gsi command"); + std::string cmd("gsi"); + while (!args.empty()) { + cmd += ":" + next_arg(&args); } + fb->RawCommand(cmd, ""); } else if (command == "wipe-super") { std::string image; if (args.empty()) { From 9ccb84a8bac43271055786d26da54dca4b58121e Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Mon, 4 Sep 2023 16:19:05 -0700 Subject: [PATCH 0359/1487] snapshotctl: Create and write pre-created snapshots Extend snapshotctl binary on the device to create and apply pre-created snapshots. snapshotctl map-snapshots 1: snapshotctl creates the block device based on the size of the snapshot patches. 2: snapshotctl will copy the data to the block device. unmap and delete snapshots will cleanup. No change in libsnapshot library except with minor refactoring. This patch doesn't yet prepare the device to reboot from these snapshots. On Pixel 6 Pro, applying pre-created snapshots for all partitions takes ~3 seconds wherein the delta between two builds are 24 hours apart. Bug: 299011882 Test: snapshotctl map-snapshots /data/test-snapshots/ snapshotctl unmap-snapshots snapshotctl delete-snapshots Change-Id: I98a0fbd9cf7234c2188bad85cdd092ded8997710 Signed-off-by: Akilesh Kailash --- .../include/libsnapshot/snapshot.h | 1 + fs_mgr/libsnapshot/snapshotctl.cpp | 301 +++++++++++++++++- 2 files changed, 300 insertions(+), 2 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h index c056a19f83a1..6bc8b9b5a013 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h @@ -441,6 +441,7 @@ class SnapshotManager final : public ISnapshotManager { friend class FlashAfterUpdateTest; friend class LockTestConsumer; friend class SnapshotFuzzEnv; + friend class MapSnapshots; friend struct AutoDeleteCowImage; friend struct AutoDeleteSnapshot; friend struct PartitionCowCreator; diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp index 38eb719fd277..1323b0bc8a64 100644 --- a/fs_mgr/libsnapshot/snapshotctl.cpp +++ b/fs_mgr/libsnapshot/snapshotctl.cpp @@ -17,14 +17,25 @@ #include #include +#include +#include +#include #include #include #include +#include #include #include #include +#include +#include +#include +#include +#include +#include + #include #include #include @@ -33,6 +44,8 @@ #include #include +#include "partition_cow_creator.h" + #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG #include #endif @@ -56,13 +69,179 @@ int Usage() { " merge\n" " Deprecated.\n" " map\n" - " Map all partitions at /dev/block/mapper\n"; + " Map all partitions at /dev/block/mapper\n" + " map-snapshots \n" + " Map all snapshots based on patches present in the directory\n" + " unmap-snapshots\n" + " Unmap all pre-created snapshots\n" + " delete-snapshots\n" + " Delete all pre-created snapshots\n"; return EX_USAGE; } namespace android { namespace snapshot { +class MapSnapshots { + public: + MapSnapshots(std::string path = ""); + bool CreateSnapshotDevice(std::string& partition_name, std::string& patch); + bool InitiateThreadedSnapshotWrite(std::string& pname, std::string& snapshot_patch); + bool WaitForSnapshotWritesToComplete(); + bool UnmapCowImagePath(std::string& name); + bool DeleteCowImage(std::string& name); + + private: + std::optional GetCowImagePath(std::string& name); + bool WriteSnapshotPatch(std::string cow_device, std::string patch); + std::unique_ptr lock_; + std::unique_ptr sm_; + std::vector> threads_; + std::string snapshot_dir_path_; +}; + +MapSnapshots::MapSnapshots(std::string path) { + sm_ = SnapshotManager::New(); + if (!sm_) { + std::cout << "Failed to create snapshotmanager"; + exit(1); + } + snapshot_dir_path_ = path + "/"; + lock_ = sm_->LockExclusive(); +} + +bool MapSnapshots::CreateSnapshotDevice(std::string& partition_name, std::string& patchfile) { + std::string parsing_file = snapshot_dir_path_ + patchfile; + + android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(parsing_file.c_str(), O_RDONLY))); + if (fd < 0) { + LOG(ERROR) << "Failed to open file: " << parsing_file; + return false; + } + + uint64_t dev_sz = lseek(fd.get(), 0, SEEK_END); + if (!dev_sz) { + LOG(ERROR) << "Could not determine block device size: " << parsing_file; + return false; + } + + const int block_sz = 4_KiB; + dev_sz += block_sz - 1; + dev_sz &= ~(block_sz - 1); + + SnapshotStatus status; + status.set_name(partition_name); + status.set_cow_file_size(dev_sz); + status.set_cow_partition_size(0); + + PartitionCowCreator cow_creator; + cow_creator.using_snapuserd = true; + + if (!sm_->CreateSnapshot(lock_.get(), &cow_creator, &status)) { + LOG(ERROR) << "CreateSnapshot failed"; + return false; + } + + if (!sm_->CreateCowImage(lock_.get(), partition_name)) { + LOG(ERROR) << "CreateCowImage failed"; + return false; + } + + return true; +} + +std::optional MapSnapshots::GetCowImagePath(std::string& name) { + auto cow_dev = sm_->MapCowImage(name, 5s); + if (!cow_dev.has_value()) { + LOG(ERROR) << "Failed to get COW device path"; + return std::nullopt; + } + + LOG(INFO) << "COW Device path: " << cow_dev.value(); + return cow_dev; +} + +bool MapSnapshots::WriteSnapshotPatch(std::string cow_device, std::string patch) { + std::string patch_file = snapshot_dir_path_ + patch; + + android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(patch_file.c_str(), O_RDONLY))); + if (fd < 0) { + LOG(ERROR) << "Failed to open file: " << patch_file; + return false; + } + + uint64_t dev_sz = lseek(fd.get(), 0, SEEK_END); + if (!dev_sz) { + std::cout << "Could not determine block device size: " << patch_file; + return false; + } + + android::base::unique_fd cfd(TEMP_FAILURE_RETRY(open(cow_device.c_str(), O_RDWR))); + if (cfd < 0) { + LOG(ERROR) << "Failed to open file: " << cow_device; + return false; + } + + const uint64_t read_sz = 1_MiB; + std::unique_ptr buffer = std::make_unique(read_sz); + off_t file_offset = 0; + + while (true) { + size_t to_read = std::min((dev_sz - file_offset), read_sz); + if (!android::base::ReadFullyAtOffset(fd.get(), buffer.get(), to_read, file_offset)) { + PLOG(ERROR) << "ReadFullyAtOffset failed"; + return false; + } + + if (!android::base::WriteFullyAtOffset(cfd, buffer.get(), to_read, file_offset)) { + PLOG(ERROR) << "WriteFullyAtOffset failed"; + return false; + } + file_offset += to_read; + if (file_offset >= dev_sz) { + break; + } + } + fsync(cfd.get()); + return true; +} + +bool MapSnapshots::InitiateThreadedSnapshotWrite(std::string& pname, std::string& snapshot_patch) { + auto path = GetCowImagePath(pname); + if (!path.has_value()) { + return false; + } + threads_.emplace_back(std::async(std::launch::async, &MapSnapshots::WriteSnapshotPatch, this, + path.value(), snapshot_patch)); + return true; +} + +bool MapSnapshots::WaitForSnapshotWritesToComplete() { + bool ret = true; + for (auto& t : threads_) { + ret = t.get() && ret; + } + + if (ret) { + LOG(INFO) << "Pre-created snapshots successfully copied"; + } else { + LOG(ERROR) << "Snapshot copy failed"; + } + return ret; +} + +bool MapSnapshots::UnmapCowImagePath(std::string& name) { + return sm_->UnmapCowImage(name); +} + +bool MapSnapshots::DeleteCowImage(std::string& name) { + if (!sm_->DeleteSnapshot(lock_.get(), name)) { + LOG(ERROR) << "Delete snapshot failed"; + return false; + } + return true; +} + bool DumpCmdHandler(int /*argc*/, char** argv) { android::base::InitLogging(argv, &android::base::StderrLogger); return SnapshotManager::New()->Dump(std::cout); @@ -85,6 +264,121 @@ bool MergeCmdHandler(int /*argc*/, char** argv) { return false; } +bool GetVerityPartitions(std::vector& partitions) { + auto& dm = android::dm::DeviceMapper::Instance(); + auto dm_block_devices = dm.FindDmPartitions(); + if (dm_block_devices.empty()) { + LOG(ERROR) << "No dm-enabled block device is found."; + return false; + } + + for (auto& block_device : dm_block_devices) { + std::string dm_block_name = block_device.first; + std::string slot_suffix = fs_mgr_get_slot_suffix(); + std::string partition = dm_block_name + slot_suffix; + partitions.push_back(partition); + } + return true; +} + +bool UnMapPrecreatedSnapshots(int, char**) { + // Make sure we are root. + if (::getuid() != 0) { + LOG(ERROR) << "Not running as root. Try \"adb root\" first."; + return EXIT_FAILURE; + } + + std::vector partitions; + if (!GetVerityPartitions(partitions)) { + return false; + } + + MapSnapshots snapshot; + for (auto partition : partitions) { + if (!snapshot.UnmapCowImagePath(partition)) { + LOG(ERROR) << "UnmapCowImagePath failed: " << partition; + } + } + return true; +} + +bool DeletePrecreatedSnapshots(int, char**) { + // Make sure we are root. + if (::getuid() != 0) { + LOG(ERROR) << "Not running as root. Try \"adb root\" first."; + return EXIT_FAILURE; + } + + std::vector partitions; + if (!GetVerityPartitions(partitions)) { + return false; + } + + MapSnapshots snapshot; + for (auto partition : partitions) { + if (!snapshot.DeleteCowImage(partition)) { + LOG(ERROR) << "DeleteCowImage failed: " << partition; + } + } + return true; +} + +bool MapPrecreatedSnapshots(int argc, char** argv) { + android::base::InitLogging(argv, &android::base::StderrLogger); + + // Make sure we are root. + if (::getuid() != 0) { + LOG(ERROR) << "Not running as root. Try \"adb root\" first."; + return EXIT_FAILURE; + } + + if (argc < 3) { + std::cerr << " map-snapshots " + " Map all snapshots based on patches present in the directory\n"; + return false; + } + + std::string path = std::string(argv[2]); + std::vector patchfiles; + + for (const auto& entry : std::filesystem::directory_iterator(path)) { + if (android::base::EndsWith(entry.path().generic_string(), ".patch")) { + patchfiles.push_back(android::base::Basename(entry.path().generic_string())); + } + } + auto& dm = android::dm::DeviceMapper::Instance(); + auto dm_block_devices = dm.FindDmPartitions(); + if (dm_block_devices.empty()) { + LOG(ERROR) << "No dm-enabled block device is found."; + return false; + } + + std::vector> partitions; + for (auto& patchfile : patchfiles) { + auto npos = patchfile.rfind(".patch"); + auto dm_block_name = patchfile.substr(0, npos); + if (dm_block_devices.find(dm_block_name) != dm_block_devices.end()) { + std::string slot_suffix = fs_mgr_get_slot_suffix(); + std::string partition = dm_block_name + slot_suffix; + partitions.push_back(std::make_pair(partition, patchfile)); + } + } + + MapSnapshots cow(path); + for (auto& pair : partitions) { + if (!cow.CreateSnapshotDevice(pair.first, pair.second)) { + LOG(ERROR) << "CreateSnapshotDevice failed for: " << pair.first; + return false; + } + if (!cow.InitiateThreadedSnapshotWrite(pair.first, pair.second)) { + LOG(ERROR) << "InitiateThreadedSnapshotWrite failed for: " << pair.first; + return false; + } + } + + return cow.WaitForSnapshotWritesToComplete(); +} + #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG bool CreateTestUpdate(SnapshotManager* sm) { chromeos_update_engine::DeltaArchiveManifest manifest; @@ -137,8 +431,8 @@ bool CreateTestUpdate(SnapshotManager* sm) { .block_device = fs_mgr_get_super_partition_name(target_slot_number), .metadata_slot = {target_slot_number}, .partition_name = system_target_name, - .partition_opener = &opener, .timeout_ms = 10s, + .partition_opener = &opener, }; auto writer = sm->OpenSnapshotWriter(clpp, std::nullopt); if (!writer) { @@ -211,6 +505,9 @@ static std::map> kCmdMap = { {"test-blank-ota", TestOtaHandler}, #endif {"unmap", UnmapCmdHandler}, + {"map-snapshots", MapPrecreatedSnapshots}, + {"unmap-snapshots", UnMapPrecreatedSnapshots}, + {"delete-snapshots", DeletePrecreatedSnapshots}, // clang-format on }; From bf72b25a07eeb24f4467d397dfeb2d94265f95b6 Mon Sep 17 00:00:00 2001 From: Julien Desprez Date: Wed, 6 Sep 2023 11:10:03 -0700 Subject: [PATCH 0360/1487] Export create_snapshot to sdk targets Similar to fastboot binaries. This will ease the automation to use this tool Test: presubmit Bug: 290951369 Change-Id: I5c879acc7cdecbafebfa074ef76034403cb0cd72 --- fs_mgr/libsnapshot/Android.bp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index b0f2b846d5ec..abdff1a429db 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -476,6 +476,14 @@ cc_binary { header_libs: [ "libstorage_literals_headers", ], + + dist: { + targets: [ + "sdk", + "sdk-repo-platform-tools", + "sdk_repo", + ], + }, } python_library_host { From e72b3ad20409ed6e31d376c497089cdc4c076eb5 Mon Sep 17 00:00:00 2001 From: Chun-Wei Wang Date: Thu, 7 Sep 2023 09:53:11 +0800 Subject: [PATCH 0361/1487] Disallow fastboot to modify locked DSU This enhances the security requirement by only allowing the owner app to change a locked DSU. Bug: 277691885 Bug: 296985785 Test: 1. ensure device is OEM locked 2. adb shell am start-activity \ -n com.android.dynsystem/com.android.dynsystem.VerificationActivity \ -a android.os.image.action.START_INSTALL \ --el KEY_USERDATA_SIZE 2147483648 \ --es KEY_DSU_SLOT foo.lock 3. adb reboot fastboot 4. `fastboot gsi disable|wipe` should be blocked Change-Id: I1a0cb8a074412468d16043ddf4101fbb76490115 --- fastboot/device/commands.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp index d60539332aea..6de598f6934d 100644 --- a/fastboot/device/commands.cpp +++ b/fastboot/device/commands.cpp @@ -639,6 +639,12 @@ bool UpdateSuperHandler(FastbootDevice* device, const std::vector& return UpdateSuper(device, args[1], wipe); } +static bool IsLockedDsu() { + std::string active_dsu; + android::gsi::GetActiveDsu(&active_dsu); + return android::base::EndsWith(active_dsu, ".lock"); +} + bool GsiHandler(FastbootDevice* device, const std::vector& args) { if (args.size() != 2) { return device->WriteFail("Invalid arguments"); @@ -653,6 +659,11 @@ bool GsiHandler(FastbootDevice* device, const std::vector& args) { return device->WriteStatus(FastbootResult::FAIL, "No GSI is installed"); } + if ((args[1] == "wipe" || args[1] == "disable") && GetDeviceLockStatus() && IsLockedDsu()) { + // Block commands that modify the states of locked DSU + return device->WriteFail("Command not available on locked DSU/devices"); + } + if (args[1] == "wipe") { if (!android::gsi::UninstallGsi()) { return device->WriteStatus(FastbootResult::FAIL, strerror(errno)); From a4d34c5715ca554edfc67471ece5b52142a85d29 Mon Sep 17 00:00:00 2001 From: Marvin Ramin Date: Thu, 7 Sep 2023 08:14:26 +0000 Subject: [PATCH 0362/1487] Revert "Export create_snapshot to sdk targets" This reverts commit bf72b25a07eeb24f4467d397dfeb2d94265f95b6. Reason for revert: DroidMonitor: Culprit for b/299411079 Change-Id: I9d46abcbcc81d43fde23d4431b6757d3520d4b2c --- fs_mgr/libsnapshot/Android.bp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index abdff1a429db..b0f2b846d5ec 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -476,14 +476,6 @@ cc_binary { header_libs: [ "libstorage_literals_headers", ], - - dist: { - targets: [ - "sdk", - "sdk-repo-platform-tools", - "sdk_repo", - ], - }, } python_library_host { From 670f983f45906849ed64ed6ac4387a1207862a55 Mon Sep 17 00:00:00 2001 From: Julien Desprez Date: Thu, 7 Sep 2023 09:38:38 -0700 Subject: [PATCH 0363/1487] Reland exporting create_snapshot Previous attempt: aosp/2743815 Disabled on windows & mac. Test: presubmit, (previously failed build: https://android-build.googleplex.com/builds/abtd/run/L06100000962955289?referrer=email now passing) Bug: 290951369 Change-Id: I3d8084c13d843ea5919e3b50a0513faf386ccfed --- fs_mgr/libsnapshot/Android.bp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index b0f2b846d5ec..0131f732e6fa 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -476,6 +476,22 @@ cc_binary { header_libs: [ "libstorage_literals_headers", ], + + dist: { + targets: [ + "sdk", + "sdk-repo-platform-tools", + "sdk_repo", + ], + }, + target: { + darwin: { + enabled: false, + }, + windows: { + enabled: false, + }, + }, } python_library_host { From a8e259db663e6308d6d9fcfd8db95f84346f2c68 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 7 Sep 2023 18:52:11 +0000 Subject: [PATCH 0364/1487] Remove stray newline from err() call. err() does this itself, and includes strerror() too. Test: treehugger Change-Id: I0e844f9cc3992e80a302b2f3ca1084b165582a9b --- toolbox/getevent.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/toolbox/getevent.c b/toolbox/getevent.c index e2c77c37fb91..f65bb20b5806 100644 --- a/toolbox/getevent.c +++ b/toolbox/getevent.c @@ -111,8 +111,7 @@ static int print_possible_events(int fd, int print_flags) break; bits_size = res + 16; bits = realloc(bits, bits_size * 2); - if(bits == NULL) - err(1, "failed to allocate buffer of size %d\n", (int)bits_size); + if (bits == NULL) err(1, "failed to allocate buffer of size %zd", bits_size); } res2 = 0; switch(i) { From b9dc1c2991de9ca87bdbf00c413b7f2bb4477fe2 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Tue, 22 Aug 2023 20:45:21 +0000 Subject: [PATCH 0365/1487] Drop all path-related methods from android::String8 Move them to androidfw and aapt, the last users. Bug: 295394788 Test: m checkbuild Change-Id: I7268b88d11bf221f93efed06cfd1ee65449a2421 --- libutils/String8.cpp | 136 ------------------ libutils/String8_fuzz.cpp | 24 ---- .../arm64/source-based/libutils.so.lsdump | 105 +------------- .../arm_arm64/source-based/libutils.so.lsdump | 105 +------------- libutils/include/utils/String8.h | 74 +--------- 5 files changed, 4 insertions(+), 440 deletions(-) diff --git a/libutils/String8.cpp b/libutils/String8.cpp index 2b72847e52bd..a2cfc088084b 100644 --- a/libutils/String8.cpp +++ b/libutils/String8.cpp @@ -430,31 +430,6 @@ void String8::toLower() // --------------------------------------------------------------------------- // Path functions -static void setPathName(String8& s, const char* name) { - size_t len = strlen(name); - char* buf = s.lockBuffer(len); - - memcpy(buf, name, len); - - // remove trailing path separator, if present - if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--; - buf[len] = '\0'; - - s.unlockBuffer(len); -} - -String8 String8::getPathLeaf(void) const -{ - const char* cp; - const char*const buf = mString; - - cp = strrchr(buf, OS_PATH_SEPARATOR); - if (cp == nullptr) - return String8(*this); - else - return String8(cp+1); -} - String8 String8::getPathDir(void) const { const char* cp; @@ -467,115 +442,4 @@ String8 String8::getPathDir(void) const return String8(str, cp - str); } -String8 String8::walkPath(String8* outRemains) const -{ - const char* cp; - const char*const str = mString; - const char* buf = str; - - cp = strchr(buf, OS_PATH_SEPARATOR); - if (cp == buf) { - // don't include a leading '/'. - buf = buf+1; - cp = strchr(buf, OS_PATH_SEPARATOR); - } - - if (cp == nullptr) { - String8 res = buf != str ? String8(buf) : *this; - if (outRemains) *outRemains = String8(""); - return res; - } - - String8 res(buf, cp-buf); - if (outRemains) *outRemains = String8(cp+1); - return res; -} - -/* - * Helper function for finding the start of an extension in a pathname. - * - * Returns a pointer inside mString, or NULL if no extension was found. - */ -char* String8::find_extension(void) const -{ - const char* lastSlash; - const char* lastDot; - const char* const str = mString; - - // only look at the filename - lastSlash = strrchr(str, OS_PATH_SEPARATOR); - if (lastSlash == nullptr) - lastSlash = str; - else - lastSlash++; - - // find the last dot - lastDot = strrchr(lastSlash, '.'); - if (lastDot == nullptr) - return nullptr; - - // looks good, ship it - return const_cast(lastDot); -} - -String8 String8::getPathExtension(void) const -{ - char* ext; - - ext = find_extension(); - if (ext != nullptr) - return String8(ext); - else - return String8(""); -} - -String8 String8::getBasePath(void) const -{ - char* ext; - const char* const str = mString; - - ext = find_extension(); - if (ext == nullptr) - return String8(*this); - else - return String8(str, ext - str); -} - -String8& String8::appendPath(const char* name) -{ - // TODO: The test below will fail for Win32 paths. Fix later or ignore. - if (name[0] != OS_PATH_SEPARATOR) { - if (*name == '\0') { - // nothing to do - return *this; - } - - size_t len = length(); - if (len == 0) { - // no existing filename, just use the new one - setPathName(*this, name); - return *this; - } - - // make room for oldPath + '/' + newPath - int newlen = strlen(name); - - char* buf = lockBuffer(len+1+newlen); - - // insert a '/' if needed - if (buf[len-1] != OS_PATH_SEPARATOR) - buf[len++] = OS_PATH_SEPARATOR; - - memcpy(buf+len, name, newlen+1); - len += newlen; - - unlockBuffer(len); - - return *this; - } else { - setPathName(*this, name); - return *this; - } -} - }; // namespace android diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp index 6f7a54f9f310..cbce0505891e 100644 --- a/libutils/String8_fuzz.cpp +++ b/libutils/String8_fuzz.cpp @@ -68,30 +68,6 @@ std::vectorConsumeIntegralInRange(0, str1->size()); str1->find(str2->c_str(), start_index); }, - - // Path handling - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - str1->getBasePath(); - }, - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - str1->getPathExtension(); - }, - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - str1->getPathLeaf(); - }, - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - str1->getPathDir(); - }, - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - std::shared_ptr path_out_str = - std::make_shared(); - str1->walkPath(path_out_str.get()); - path_out_str->clear(); - }, - [](FuzzedDataProvider* dataProvider, android::String8* str1, - android::String8*) -> void { - str1->appendPath(dataProvider->ConsumeBytesWithTerminator(5).data()); - }, }; void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend) { diff --git a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump index 46baddecde7b..55e1e275fc58 100644 --- a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump +++ b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump @@ -703,9 +703,6 @@ { "name" : "_ZN7android7RefBaseD2Ev" }, - { - "name" : "_ZN7android7String810appendPathEPKc" - }, { "name" : "_ZN7android7String810lockBufferEm" }, @@ -1144,27 +1141,12 @@ { "name" : "_ZNK7android7String810getPathDirEv" }, - { - "name" : "_ZNK7android7String811getBasePathEv" - }, - { - "name" : "_ZNK7android7String811getPathLeafEv" - }, - { - "name" : "_ZNK7android7String814find_extensionEv" - }, - { - "name" : "_ZNK7android7String816getPathExtensionEv" - }, { "name" : "_ZNK7android7String84findEPKcm" }, { "name" : "_ZNK7android7String86lengthEv" }, - { - "name" : "_ZNK7android7String88walkPathEPS0_" - }, { "name" : "_ZNK7android8String1610startsWithEPKDs" }, @@ -6808,22 +6790,6 @@ "return_type" : "_ZTIv", "source_file" : "system/core/libutils/include/utils/RefBase.h" }, - { - "function_name" : "android::String8::appendPath", - "linker_set_key" : "_ZN7android7String810appendPathEPKc", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPN7android7String8E" - }, - { - "referenced_type" : "_ZTIPKc" - } - ], - "return_type" : "_ZTIRN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String8::lockBuffer", "linker_set_key" : "_ZN7android7String810lockBufferEm", @@ -9104,6 +9070,7 @@ "source_file" : "system/core/libutils/include/utils/RefBase.h" }, { + "access" : "private", "function_name" : "android::String8::getPathDir", "linker_set_key" : "_ZNK7android7String810getPathDirEv", "parameters" : @@ -9116,59 +9083,6 @@ "return_type" : "_ZTIN7android7String8E", "source_file" : "system/core/libutils/include/utils/String8.h" }, - { - "function_name" : "android::String8::getBasePath", - "linker_set_key" : "_ZNK7android7String811getBasePathEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, - { - "function_name" : "android::String8::getPathLeaf", - "linker_set_key" : "_ZNK7android7String811getPathLeafEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, - { - "access" : "private", - "function_name" : "android::String8::find_extension", - "linker_set_key" : "_ZNK7android7String814find_extensionEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIPc", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, - { - "function_name" : "android::String8::getPathExtension", - "linker_set_key" : "_ZNK7android7String816getPathExtensionEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String8::find", "linker_set_key" : "_ZNK7android7String84findEPKcm", @@ -9202,23 +9116,6 @@ "return_type" : "_ZTIm", "source_file" : "system/core/libutils/include/utils/String8.h" }, - { - "function_name" : "android::String8::walkPath", - "linker_set_key" : "_ZNK7android7String88walkPathEPS0_", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - }, - { - "default_arg" : true, - "referenced_type" : "_ZTIPN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String16::startsWith", "linker_set_key" : "_ZNK7android8String1610startsWithEPKDs", diff --git a/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump b/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump index 219c76665bb9..c14469890758 100644 --- a/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump +++ b/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump @@ -703,9 +703,6 @@ { "name" : "_ZN7android7RefBaseD2Ev" }, - { - "name" : "_ZN7android7String810appendPathEPKc" - }, { "name" : "_ZN7android7String810lockBufferEj" }, @@ -1144,27 +1141,12 @@ { "name" : "_ZNK7android7String810getPathDirEv" }, - { - "name" : "_ZNK7android7String811getBasePathEv" - }, - { - "name" : "_ZNK7android7String811getPathLeafEv" - }, - { - "name" : "_ZNK7android7String814find_extensionEv" - }, - { - "name" : "_ZNK7android7String816getPathExtensionEv" - }, { "name" : "_ZNK7android7String84findEPKcj" }, { "name" : "_ZNK7android7String86lengthEv" }, - { - "name" : "_ZNK7android7String88walkPathEPS0_" - }, { "name" : "_ZNK7android8String1610startsWithEPKDs" }, @@ -6804,22 +6786,6 @@ "return_type" : "_ZTIv", "source_file" : "system/core/libutils/include/utils/RefBase.h" }, - { - "function_name" : "android::String8::appendPath", - "linker_set_key" : "_ZN7android7String810appendPathEPKc", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPN7android7String8E" - }, - { - "referenced_type" : "_ZTIPKc" - } - ], - "return_type" : "_ZTIRN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String8::lockBuffer", "linker_set_key" : "_ZN7android7String810lockBufferEj", @@ -9100,6 +9066,7 @@ "source_file" : "system/core/libutils/include/utils/RefBase.h" }, { + "access" : "private", "function_name" : "android::String8::getPathDir", "linker_set_key" : "_ZNK7android7String810getPathDirEv", "parameters" : @@ -9112,59 +9079,6 @@ "return_type" : "_ZTIN7android7String8E", "source_file" : "system/core/libutils/include/utils/String8.h" }, - { - "function_name" : "android::String8::getBasePath", - "linker_set_key" : "_ZNK7android7String811getBasePathEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, - { - "function_name" : "android::String8::getPathLeaf", - "linker_set_key" : "_ZNK7android7String811getPathLeafEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, - { - "access" : "private", - "function_name" : "android::String8::find_extension", - "linker_set_key" : "_ZNK7android7String814find_extensionEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIPc", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, - { - "function_name" : "android::String8::getPathExtension", - "linker_set_key" : "_ZNK7android7String816getPathExtensionEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String8::find", "linker_set_key" : "_ZNK7android7String84findEPKcj", @@ -9198,23 +9112,6 @@ "return_type" : "_ZTIj", "source_file" : "system/core/libutils/include/utils/String8.h" }, - { - "function_name" : "android::String8::walkPath", - "linker_set_key" : "_ZNK7android7String88walkPathEPS0_", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - }, - { - "default_arg" : true, - "referenced_type" : "_ZTIPN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String16::startsWith", "linker_set_key" : "_ZNK7android8String1610startsWithEPKDs", diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h index ea25c6aa3947..9cef9f67854f 100644 --- a/libutils/include/utils/String8.h +++ b/libutils/include/utils/String8.h @@ -130,80 +130,10 @@ class String8 void toLower(); - - /* - * These methods operate on the string as if it were a path name. - */ - - /* - * Get just the filename component. - * - * "/tmp/foo/bar.c" --> "bar.c" - */ - String8 getPathLeaf(void) const; - - /* - * Remove the last (file name) component, leaving just the directory - * name. - * - * "/tmp/foo/bar.c" --> "/tmp/foo" - * "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX - * "bar.c" --> "" - */ - String8 getPathDir(void) const; - - /* - * Retrieve the front (root dir) component. Optionally also return the - * remaining components. - * - * "/tmp/foo/bar.c" --> "tmp" (remain = "foo/bar.c") - * "/tmp" --> "tmp" (remain = "") - * "bar.c" --> "bar.c" (remain = "") - */ - String8 walkPath(String8* outRemains = nullptr) const; - - /* - * Return the filename extension. This is the last '.' and any number - * of characters that follow it. The '.' is included in case we - * decide to expand our definition of what constitutes an extension. - * - * "/tmp/foo/bar.c" --> ".c" - * "/tmp" --> "" - * "/tmp/foo.bar/baz" --> "" - * "foo.jpeg" --> ".jpeg" - * "foo." --> "" - */ - String8 getPathExtension(void) const; - - /* - * Return the path without the extension. Rules for what constitutes - * an extension are described in the comment for getPathExtension(). - * - * "/tmp/foo/bar.c" --> "/tmp/foo/bar" - */ - String8 getBasePath(void) const; - - /* - * Add a component to the pathname. We guarantee that there is - * exactly one path separator between the old path and the new. - * If there is no existing name, we just copy the new name in. - * - * If leaf is a fully qualified path (i.e. starts with '/', it - * replaces whatever was there before. - */ - String8& appendPath(const char* leaf); - String8& appendPath(const String8& leaf) { return appendPath(leaf.c_str()); } - - /* - * Like appendPath(), but does not affect this string. Returns a new one instead. - */ - String8 appendPathCopy(const char* leaf) const - { String8 p(*this); p.appendPath(leaf); return p; } - String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.c_str()); } - private: + String8 getPathDir(void) const; + status_t real_append(const char* other, size_t numChars); - char* find_extension(void) const; const char* mString; }; From bcbc93f83d48b3f9b2ca3972764bed011983432c Mon Sep 17 00:00:00 2001 From: Chun-Wei Wang Date: Thu, 7 Sep 2023 09:53:11 +0800 Subject: [PATCH 0366/1487] Disallow fastboot to modify locked DSU This enhances the security requirement by only allowing the owner app to change a locked DSU. (Cherry-picked from aosp/2744993) Bug: 277691885 Bug: 296985785 Test: 1. ensure device is OEM locked 2. adb shell am start-activity \ -n com.android.dynsystem/com.android.dynsystem.VerificationActivity \ -a android.os.image.action.START_INSTALL \ --el KEY_USERDATA_SIZE 2147483648 \ --es KEY_DSU_SLOT foo.lock 3. adb reboot fastboot 4. `fastboot gsi disable|wipe` should be blocked Merged-In: I1a0cb8a074412468d16043ddf4101fbb76490115 Change-Id: I1a0cb8a074412468d16043ddf4101fbb76490115 --- fastboot/device/commands.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp index d60539332aea..6de598f6934d 100644 --- a/fastboot/device/commands.cpp +++ b/fastboot/device/commands.cpp @@ -639,6 +639,12 @@ bool UpdateSuperHandler(FastbootDevice* device, const std::vector& return UpdateSuper(device, args[1], wipe); } +static bool IsLockedDsu() { + std::string active_dsu; + android::gsi::GetActiveDsu(&active_dsu); + return android::base::EndsWith(active_dsu, ".lock"); +} + bool GsiHandler(FastbootDevice* device, const std::vector& args) { if (args.size() != 2) { return device->WriteFail("Invalid arguments"); @@ -653,6 +659,11 @@ bool GsiHandler(FastbootDevice* device, const std::vector& args) { return device->WriteStatus(FastbootResult::FAIL, "No GSI is installed"); } + if ((args[1] == "wipe" || args[1] == "disable") && GetDeviceLockStatus() && IsLockedDsu()) { + // Block commands that modify the states of locked DSU + return device->WriteFail("Command not available on locked DSU/devices"); + } + if (args[1] == "wipe") { if (!android::gsi::UninstallGsi()) { return device->WriteStatus(FastbootResult::FAIL, strerror(errno)); From 32f69204046c24c15ff2d2bac7122cbfd5896596 Mon Sep 17 00:00:00 2001 From: Hongguang Chen Date: Thu, 7 Sep 2023 21:15:00 -0700 Subject: [PATCH 0367/1487] Only restart media.tuner when it's running Fix: 287520719 Test: Kill system_server on TV device w/o tuner. media.tuner is not restarted. Change-Id: I13006f16746a12c33960feca1288aa17ef2ed9c9 --- rootdir/init.zygote32.rc | 2 +- rootdir/init.zygote64.rc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc index 2f0ec8a17d4c..442bd153f5db 100644 --- a/rootdir/init.zygote32.rc +++ b/rootdir/init.zygote32.rc @@ -13,7 +13,7 @@ service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-sys onrestart restart audioserver onrestart restart cameraserver onrestart restart media - onrestart restart media.tuner + onrestart restart --only-if-running media.tuner onrestart restart netd onrestart restart wificond task_profiles ProcessCapacityHigh diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc index 74a64c80f465..342212123de5 100644 --- a/rootdir/init.zygote64.rc +++ b/rootdir/init.zygote64.rc @@ -13,7 +13,7 @@ service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-s onrestart restart audioserver onrestart restart cameraserver onrestart restart media - onrestart restart media.tuner + onrestart restart --only-if-running media.tuner onrestart restart netd onrestart restart wificond task_profiles ProcessCapacityHigh MaxPerformance From 3a60e825126bbcfebecd57a728a1a87cacc5b497 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 5 Jun 2023 15:00:30 -0700 Subject: [PATCH 0368/1487] Move ENOSPC tests to libfiemap. These tests are still giving us trouble. Move them to libfiemap, which (1) is closer to the source of implementation, and (2) allows us to re-use the temporary filesystem code. This won't perturb the state of the actual device. The new test creates a 64MB ext4 or f2fs mount point as a sandbox, which should be much safer. Bug: 285197715 Bug: 298346574 Bug: 299142557 Test: fiemap_writer_test Merged-In: I33502d49613be4f269a80e5c632514fc56a0246a Ignore-AOSP-First: cherry-pick Change-Id: Iedb7c32a594c3b1fca2904f3441029aaed7edf2a --- fs_mgr/libfiemap/Android.bp | 3 + fs_mgr/libfiemap/fiemap_writer_test.cpp | 118 ++++++++++++------ fs_mgr/libsnapshot/snapshot_test.cpp | 70 ----------- .../storage_literals/storage_literals.h | 6 + 4 files changed, 87 insertions(+), 110 deletions(-) diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp index 5deba659dd56..ddda648d8e88 100644 --- a/fs_mgr/libfiemap/Android.bp +++ b/fs_mgr/libfiemap/Android.bp @@ -93,6 +93,9 @@ cc_test { test_options: { min_shipping_api_level: 29, }, + header_libs: [ + "libstorage_literals_headers", + ], require_root: true, } diff --git a/fs_mgr/libfiemap/fiemap_writer_test.cpp b/fs_mgr/libfiemap/fiemap_writer_test.cpp index c65481b78d36..bd97a78ae8f7 100644 --- a/fs_mgr/libfiemap/fiemap_writer_test.cpp +++ b/fs_mgr/libfiemap/fiemap_writer_test.cpp @@ -22,21 +22,25 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include #include +#include #include #include #include #include #include +#include #include "utility.h" @@ -46,6 +50,7 @@ namespace fiemap { using namespace std; using namespace std::string_literals; using namespace android::fiemap; +using namespace android::storage_literals; using unique_fd = android::base::unique_fd; using LoopDevice = android::dm::LoopDevice; @@ -427,90 +432,123 @@ TEST_F(SplitFiemapTest, WritePastEnd) { ASSERT_FALSE(ptr->Write(buffer.get(), kSize)); } -class VerifyBlockWritesExt4 : public ::testing::Test { +// Get max file size and free space. +std::pair GetBigFileLimit(const std::string& mount_point) { + struct statvfs fs; + if (statvfs(mount_point.c_str(), &fs) < 0) { + PLOG(ERROR) << "statfs failed"; + return {0, 0}; + } + + auto fs_limit = static_cast(fs.f_blocks) * (fs.f_bsize - 1); + auto fs_free = static_cast(fs.f_bfree) * fs.f_bsize; + + LOG(INFO) << "Big file limit: " << fs_limit << ", free space: " << fs_free; + + return {fs_limit, fs_free}; +} + +class FsTest : public ::testing::Test { + protected: // 2GB Filesystem and 4k block size by default static constexpr uint64_t block_size = 4096; - static constexpr uint64_t fs_size = 2147483648; + static constexpr uint64_t fs_size = 64 * 1024 * 1024; + + void SetUp() { + android::fs_mgr::Fstab fstab; + ASSERT_TRUE(android::fs_mgr::ReadFstabFromFile("/proc/mounts", &fstab)); + + ASSERT_EQ(access(tmpdir_.path, F_OK), 0); + fs_path_ = tmpdir_.path + "/fs_image"s; + mntpoint_ = tmpdir_.path + "/mnt_point"s; + + auto entry = android::fs_mgr::GetEntryForMountPoint(&fstab, "/data"); + ASSERT_NE(entry, nullptr); + if (entry->fs_type == "ext4") { + SetUpExt4(); + } else if (entry->fs_type == "f2fs") { + SetUpF2fs(); + } else { + FAIL() << "Unrecognized fs_type: " << entry->fs_type; + } + } - protected: - void SetUp() override { - fs_path = std::string(getenv("TMPDIR")) + "/ext4_2G.img"; + void SetUpExt4() { uint64_t count = fs_size / block_size; std::string dd_cmd = ::android::base::StringPrintf("/system/bin/dd if=/dev/zero of=%s bs=%" PRIu64 " count=%" PRIu64 " > /dev/null 2>&1", - fs_path.c_str(), block_size, count); + fs_path_.c_str(), block_size, count); std::string mkfs_cmd = - ::android::base::StringPrintf("/system/bin/mkfs.ext4 -q %s", fs_path.c_str()); + ::android::base::StringPrintf("/system/bin/mkfs.ext4 -q %s", fs_path_.c_str()); // create mount point - mntpoint = std::string(getenv("TMPDIR")) + "/fiemap_mnt"; - ASSERT_EQ(mkdir(mntpoint.c_str(), S_IRWXU), 0); + ASSERT_EQ(mkdir(mntpoint_.c_str(), S_IRWXU), 0); // create file for the file system int ret = system(dd_cmd.c_str()); ASSERT_EQ(ret, 0); // Get and attach a loop device to the filesystem we created - LoopDevice loop_dev(fs_path, 10s); + LoopDevice loop_dev(fs_path_, 10s); ASSERT_TRUE(loop_dev.valid()); // create file system ret = system(mkfs_cmd.c_str()); ASSERT_EQ(ret, 0); // mount the file system - ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint.c_str(), "ext4", 0, nullptr), 0); - } - - void TearDown() override { - umount(mntpoint.c_str()); - rmdir(mntpoint.c_str()); - unlink(fs_path.c_str()); + ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint_.c_str(), "ext4", 0, nullptr), 0); } - std::string mntpoint; - std::string fs_path; -}; - -class VerifyBlockWritesF2fs : public ::testing::Test { - // 2GB Filesystem and 4k block size by default - static constexpr uint64_t block_size = 4096; - static constexpr uint64_t fs_size = 2147483648; - - protected: - void SetUp() override { - fs_path = std::string(getenv("TMPDIR")) + "/f2fs_2G.img"; + void SetUpF2fs() { uint64_t count = fs_size / block_size; std::string dd_cmd = ::android::base::StringPrintf("/system/bin/dd if=/dev/zero of=%s bs=%" PRIu64 " count=%" PRIu64 " > /dev/null 2>&1", - fs_path.c_str(), block_size, count); + fs_path_.c_str(), block_size, count); std::string mkfs_cmd = - ::android::base::StringPrintf("/system/bin/make_f2fs -q %s", fs_path.c_str()); + ::android::base::StringPrintf("/system/bin/make_f2fs -q %s", fs_path_.c_str()); // create mount point - mntpoint = std::string(getenv("TMPDIR")) + "/fiemap_mnt"; - ASSERT_EQ(mkdir(mntpoint.c_str(), S_IRWXU), 0); + ASSERT_EQ(mkdir(mntpoint_.c_str(), S_IRWXU), 0); // create file for the file system int ret = system(dd_cmd.c_str()); ASSERT_EQ(ret, 0); // Get and attach a loop device to the filesystem we created - LoopDevice loop_dev(fs_path, 10s); + LoopDevice loop_dev(fs_path_, 10s); ASSERT_TRUE(loop_dev.valid()); // create file system ret = system(mkfs_cmd.c_str()); ASSERT_EQ(ret, 0); // mount the file system - ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint.c_str(), "f2fs", 0, nullptr), 0); + ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint_.c_str(), "f2fs", 0, nullptr), 0); } void TearDown() override { - umount(mntpoint.c_str()); - rmdir(mntpoint.c_str()); - unlink(fs_path.c_str()); + umount(mntpoint_.c_str()); + rmdir(mntpoint_.c_str()); + unlink(fs_path_.c_str()); } - std::string mntpoint; - std::string fs_path; + TemporaryDir tmpdir_; + std::string mntpoint_; + std::string fs_path_; }; +TEST_F(FsTest, LowSpaceError) { + auto limits = GetBigFileLimit(mntpoint_); + ASSERT_GE(limits.first, 0); + + FiemapUniquePtr ptr; + + auto test_file = mntpoint_ + "/big_file"; + auto status = FiemapWriter::Open(test_file, limits.first, &ptr); + ASSERT_FALSE(status.is_ok()); + ASSERT_EQ(status.error_code(), FiemapStatus::ErrorCode::NO_SPACE); + + // Also test for EFBIG. + status = FiemapWriter::Open(test_file, 16_TiB, &ptr); + ASSERT_FALSE(status.is_ok()); + ASSERT_NE(status.error_code(), FiemapStatus::ErrorCode::NO_SPACE); +} + bool DetermineBlockSize() { struct statfs s; if (statfs(gTestDir.c_str(), &s)) { diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index 460d49db2a8b..ce75a54167bf 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -2312,32 +2312,6 @@ TEST_F(SnapshotUpdateTest, Overflow) { << "FinishedSnapshotWrites should detect overflow of CoW device."; } -TEST_F(SnapshotUpdateTest, LowSpace) { - static constexpr auto kMaxFree = 10_MiB; - auto userdata = std::make_unique(); - ASSERT_TRUE(userdata->Init(kMaxFree)); - - // Grow all partitions to 10_MiB, total 30_MiB. This requires 30 MiB of CoW space. After - // using the empty space in super (< 1 MiB), it uses 30 MiB of /userdata space. - constexpr uint64_t partition_size = 10_MiB; - SetSize(sys_, partition_size); - SetSize(vnd_, partition_size); - SetSize(prd_, partition_size); - sys_->set_estimate_cow_size(partition_size); - vnd_->set_estimate_cow_size(partition_size); - prd_->set_estimate_cow_size(partition_size); - - AddOperationForPartitions(); - - // Execute the update. - ASSERT_TRUE(sm->BeginUpdate()); - auto res = sm->CreateUpdateSnapshots(manifest_); - ASSERT_FALSE(res); - ASSERT_EQ(Return::ErrorCode::NO_SPACE, res.error_code()); - ASSERT_GE(res.required_size(), 14_MiB); - ASSERT_LT(res.required_size(), 40_MiB); -} - TEST_F(SnapshotUpdateTest, AddPartition) { group_->add_partition_names("dlkm"); @@ -2699,50 +2673,6 @@ INSTANTIATE_TEST_SUITE_P(Snapshot, FlashAfterUpdateTest, Combine(Values(0, 1), B "Merge"s; }); -class ImageManagerTest : public SnapshotTest { - protected: - void SetUp() override { - SKIP_IF_NON_VIRTUAL_AB(); - SnapshotTest::SetUp(); - } - void TearDown() override { - RETURN_IF_NON_VIRTUAL_AB(); - CleanUp(); - } - void CleanUp() { - if (!image_manager_) { - return; - } - EXPECT_TRUE(!image_manager_->BackingImageExists(kImageName) || - image_manager_->DeleteBackingImage(kImageName)); - } - - static constexpr const char* kImageName = "my_image"; -}; - -TEST_F(ImageManagerTest, CreateImageNoSpace) { - bool at_least_one_failure = false; - for (uint64_t size = 1_MiB; size <= 512_MiB; size *= 2) { - auto userdata = std::make_unique(); - ASSERT_TRUE(userdata->Init(size)); - - uint64_t to_allocate = userdata->free_space() + userdata->bsize(); - - auto res = image_manager_->CreateBackingImage(kImageName, to_allocate, - IImageManager::CREATE_IMAGE_DEFAULT); - if (!res) { - at_least_one_failure = true; - } else { - ASSERT_EQ(res.error_code(), FiemapStatus::ErrorCode::NO_SPACE) << res.string(); - } - - CleanUp(); - } - - ASSERT_TRUE(at_least_one_failure) - << "We should have failed to allocate at least one over-sized image"; -} - bool Mkdir(const std::string& path) { if (mkdir(path.c_str(), 0700) && errno != EEXIST) { std::cerr << "Could not mkdir " << path << ": " << strerror(errno) << std::endl; diff --git a/fs_mgr/libstorage_literals/storage_literals/storage_literals.h b/fs_mgr/libstorage_literals/storage_literals/storage_literals.h index ac0dfbdb7004..bbeabd5c987b 100644 --- a/fs_mgr/libstorage_literals/storage_literals/storage_literals.h +++ b/fs_mgr/libstorage_literals/storage_literals/storage_literals.h @@ -37,6 +37,7 @@ using B = Size<0>; using KiB = Size<10>; using MiB = Size<20>; using GiB = Size<30>; +using TiB = Size<40>; constexpr B operator""_B(unsigned long long v) { // NOLINT return B{v}; @@ -54,6 +55,10 @@ constexpr GiB operator""_GiB(unsigned long long v) { // NOLINT return GiB{v}; } +constexpr TiB operator""_TiB(unsigned long long v) { // NOLINT + return TiB{v}; +} + template constexpr Dest size_cast(Src src) { if (Src::power < Dest::power) { @@ -69,6 +74,7 @@ static_assert(1_B == 1); static_assert(1_KiB == 1 << 10); static_assert(1_MiB == 1 << 20); static_assert(1_GiB == 1 << 30); +static_assert(1_TiB == 1ULL << 40); static_assert(size_cast(1_B).count() == 0); static_assert(size_cast(1024_B).count() == 1); static_assert(size_cast(1_MiB).count() == 1024); From adaf33026a32e336dd727cb4d03e9cd656c2869c Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 8 Sep 2023 09:51:24 -0700 Subject: [PATCH 0369/1487] Drop String8::std_string This method was preserved under assumption it would be baked into many prebuilts, but since it's inline, there should be no linkage to libutils - thus, should be safe to remove anyway. Bug: 35363681 Bug: 295394788 Test: treehugger Change-Id: I59964935600e9e786424136177bfc8a70bebec67 --- libutils/include/utils/String16.h | 8 -------- libutils/include/utils/String8.h | 9 --------- 2 files changed, 17 deletions(-) diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h index b48b90765612..ec2a3241c49c 100644 --- a/libutils/include/utils/String16.h +++ b/libutils/include/utils/String16.h @@ -56,9 +56,6 @@ class String16 inline const char16_t* c_str() const; inline const char16_t* string() const; -private: - static inline std::string std_string(const String16& str); -public: size_t size() const; inline bool empty() const; @@ -249,11 +246,6 @@ inline const char16_t* String16::string() const return mString; } -inline std::string String16::std_string(const String16& str) -{ - return std::string(String8(str).c_str()); -} - inline bool String16::empty() const { return length() == 0; diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h index 9cef9f67854f..764b92a18f8a 100644 --- a/libutils/include/utils/String8.h +++ b/libutils/include/utils/String8.h @@ -58,10 +58,6 @@ class String8 inline const char* c_str() const; inline const char* string() const; -private: - static inline std::string std_string(const String8& str); -public: - inline size_t size() const; inline size_t bytes() const; inline bool empty() const; @@ -169,11 +165,6 @@ inline const char* String8::string() const return mString; } -inline std::string String8::std_string(const String8& str) -{ - return std::string(str.c_str()); -} - inline size_t String8::size() const { return length(); From cff2e40d19113fa7ed57fedae072ad605cef1be7 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 8 Sep 2023 17:08:39 +0000 Subject: [PATCH 0370/1487] Revert "Drop all path-related methods from android::String8" This reverts commit b9dc1c2991de9ca87bdbf00c413b7f2bb4477fe2. Reason for revert: http://b/299624573 Change-Id: I0d5993295df65ec31c180b6b5a76fbe939891f45 --- libutils/String8.cpp | 136 ++++++++++++++++++ libutils/String8_fuzz.cpp | 24 ++++ .../arm64/source-based/libutils.so.lsdump | 105 +++++++++++++- .../arm_arm64/source-based/libutils.so.lsdump | 105 +++++++++++++- libutils/include/utils/String8.h | 74 +++++++++- 5 files changed, 440 insertions(+), 4 deletions(-) diff --git a/libutils/String8.cpp b/libutils/String8.cpp index a2cfc088084b..2b72847e52bd 100644 --- a/libutils/String8.cpp +++ b/libutils/String8.cpp @@ -430,6 +430,31 @@ void String8::toLower() // --------------------------------------------------------------------------- // Path functions +static void setPathName(String8& s, const char* name) { + size_t len = strlen(name); + char* buf = s.lockBuffer(len); + + memcpy(buf, name, len); + + // remove trailing path separator, if present + if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--; + buf[len] = '\0'; + + s.unlockBuffer(len); +} + +String8 String8::getPathLeaf(void) const +{ + const char* cp; + const char*const buf = mString; + + cp = strrchr(buf, OS_PATH_SEPARATOR); + if (cp == nullptr) + return String8(*this); + else + return String8(cp+1); +} + String8 String8::getPathDir(void) const { const char* cp; @@ -442,4 +467,115 @@ String8 String8::getPathDir(void) const return String8(str, cp - str); } +String8 String8::walkPath(String8* outRemains) const +{ + const char* cp; + const char*const str = mString; + const char* buf = str; + + cp = strchr(buf, OS_PATH_SEPARATOR); + if (cp == buf) { + // don't include a leading '/'. + buf = buf+1; + cp = strchr(buf, OS_PATH_SEPARATOR); + } + + if (cp == nullptr) { + String8 res = buf != str ? String8(buf) : *this; + if (outRemains) *outRemains = String8(""); + return res; + } + + String8 res(buf, cp-buf); + if (outRemains) *outRemains = String8(cp+1); + return res; +} + +/* + * Helper function for finding the start of an extension in a pathname. + * + * Returns a pointer inside mString, or NULL if no extension was found. + */ +char* String8::find_extension(void) const +{ + const char* lastSlash; + const char* lastDot; + const char* const str = mString; + + // only look at the filename + lastSlash = strrchr(str, OS_PATH_SEPARATOR); + if (lastSlash == nullptr) + lastSlash = str; + else + lastSlash++; + + // find the last dot + lastDot = strrchr(lastSlash, '.'); + if (lastDot == nullptr) + return nullptr; + + // looks good, ship it + return const_cast(lastDot); +} + +String8 String8::getPathExtension(void) const +{ + char* ext; + + ext = find_extension(); + if (ext != nullptr) + return String8(ext); + else + return String8(""); +} + +String8 String8::getBasePath(void) const +{ + char* ext; + const char* const str = mString; + + ext = find_extension(); + if (ext == nullptr) + return String8(*this); + else + return String8(str, ext - str); +} + +String8& String8::appendPath(const char* name) +{ + // TODO: The test below will fail for Win32 paths. Fix later or ignore. + if (name[0] != OS_PATH_SEPARATOR) { + if (*name == '\0') { + // nothing to do + return *this; + } + + size_t len = length(); + if (len == 0) { + // no existing filename, just use the new one + setPathName(*this, name); + return *this; + } + + // make room for oldPath + '/' + newPath + int newlen = strlen(name); + + char* buf = lockBuffer(len+1+newlen); + + // insert a '/' if needed + if (buf[len-1] != OS_PATH_SEPARATOR) + buf[len++] = OS_PATH_SEPARATOR; + + memcpy(buf+len, name, newlen+1); + len += newlen; + + unlockBuffer(len); + + return *this; + } else { + setPathName(*this, name); + return *this; + } +} + }; // namespace android diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp index cbce0505891e..6f7a54f9f310 100644 --- a/libutils/String8_fuzz.cpp +++ b/libutils/String8_fuzz.cpp @@ -68,6 +68,30 @@ std::vectorConsumeIntegralInRange(0, str1->size()); str1->find(str2->c_str(), start_index); }, + + // Path handling + [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { + str1->getBasePath(); + }, + [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { + str1->getPathExtension(); + }, + [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { + str1->getPathLeaf(); + }, + [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { + str1->getPathDir(); + }, + [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { + std::shared_ptr path_out_str = + std::make_shared(); + str1->walkPath(path_out_str.get()); + path_out_str->clear(); + }, + [](FuzzedDataProvider* dataProvider, android::String8* str1, + android::String8*) -> void { + str1->appendPath(dataProvider->ConsumeBytesWithTerminator(5).data()); + }, }; void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend) { diff --git a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump index 55e1e275fc58..46baddecde7b 100644 --- a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump +++ b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump @@ -703,6 +703,9 @@ { "name" : "_ZN7android7RefBaseD2Ev" }, + { + "name" : "_ZN7android7String810appendPathEPKc" + }, { "name" : "_ZN7android7String810lockBufferEm" }, @@ -1141,12 +1144,27 @@ { "name" : "_ZNK7android7String810getPathDirEv" }, + { + "name" : "_ZNK7android7String811getBasePathEv" + }, + { + "name" : "_ZNK7android7String811getPathLeafEv" + }, + { + "name" : "_ZNK7android7String814find_extensionEv" + }, + { + "name" : "_ZNK7android7String816getPathExtensionEv" + }, { "name" : "_ZNK7android7String84findEPKcm" }, { "name" : "_ZNK7android7String86lengthEv" }, + { + "name" : "_ZNK7android7String88walkPathEPS0_" + }, { "name" : "_ZNK7android8String1610startsWithEPKDs" }, @@ -6790,6 +6808,22 @@ "return_type" : "_ZTIv", "source_file" : "system/core/libutils/include/utils/RefBase.h" }, + { + "function_name" : "android::String8::appendPath", + "linker_set_key" : "_ZN7android7String810appendPathEPKc", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPN7android7String8E" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIRN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, { "function_name" : "android::String8::lockBuffer", "linker_set_key" : "_ZN7android7String810lockBufferEm", @@ -9070,7 +9104,6 @@ "source_file" : "system/core/libutils/include/utils/RefBase.h" }, { - "access" : "private", "function_name" : "android::String8::getPathDir", "linker_set_key" : "_ZNK7android7String810getPathDirEv", "parameters" : @@ -9083,6 +9116,59 @@ "return_type" : "_ZTIN7android7String8E", "source_file" : "system/core/libutils/include/utils/String8.h" }, + { + "function_name" : "android::String8::getBasePath", + "linker_set_key" : "_ZNK7android7String811getBasePathEv", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + } + ], + "return_type" : "_ZTIN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, + { + "function_name" : "android::String8::getPathLeaf", + "linker_set_key" : "_ZNK7android7String811getPathLeafEv", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + } + ], + "return_type" : "_ZTIN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, + { + "access" : "private", + "function_name" : "android::String8::find_extension", + "linker_set_key" : "_ZNK7android7String814find_extensionEv", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + } + ], + "return_type" : "_ZTIPc", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, + { + "function_name" : "android::String8::getPathExtension", + "linker_set_key" : "_ZNK7android7String816getPathExtensionEv", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + } + ], + "return_type" : "_ZTIN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, { "function_name" : "android::String8::find", "linker_set_key" : "_ZNK7android7String84findEPKcm", @@ -9116,6 +9202,23 @@ "return_type" : "_ZTIm", "source_file" : "system/core/libutils/include/utils/String8.h" }, + { + "function_name" : "android::String8::walkPath", + "linker_set_key" : "_ZNK7android7String88walkPathEPS0_", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + }, + { + "default_arg" : true, + "referenced_type" : "_ZTIPN7android7String8E" + } + ], + "return_type" : "_ZTIN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, { "function_name" : "android::String16::startsWith", "linker_set_key" : "_ZNK7android8String1610startsWithEPKDs", diff --git a/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump b/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump index c14469890758..219c76665bb9 100644 --- a/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump +++ b/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump @@ -703,6 +703,9 @@ { "name" : "_ZN7android7RefBaseD2Ev" }, + { + "name" : "_ZN7android7String810appendPathEPKc" + }, { "name" : "_ZN7android7String810lockBufferEj" }, @@ -1141,12 +1144,27 @@ { "name" : "_ZNK7android7String810getPathDirEv" }, + { + "name" : "_ZNK7android7String811getBasePathEv" + }, + { + "name" : "_ZNK7android7String811getPathLeafEv" + }, + { + "name" : "_ZNK7android7String814find_extensionEv" + }, + { + "name" : "_ZNK7android7String816getPathExtensionEv" + }, { "name" : "_ZNK7android7String84findEPKcj" }, { "name" : "_ZNK7android7String86lengthEv" }, + { + "name" : "_ZNK7android7String88walkPathEPS0_" + }, { "name" : "_ZNK7android8String1610startsWithEPKDs" }, @@ -6786,6 +6804,22 @@ "return_type" : "_ZTIv", "source_file" : "system/core/libutils/include/utils/RefBase.h" }, + { + "function_name" : "android::String8::appendPath", + "linker_set_key" : "_ZN7android7String810appendPathEPKc", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPN7android7String8E" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIRN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, { "function_name" : "android::String8::lockBuffer", "linker_set_key" : "_ZN7android7String810lockBufferEj", @@ -9066,7 +9100,6 @@ "source_file" : "system/core/libutils/include/utils/RefBase.h" }, { - "access" : "private", "function_name" : "android::String8::getPathDir", "linker_set_key" : "_ZNK7android7String810getPathDirEv", "parameters" : @@ -9079,6 +9112,59 @@ "return_type" : "_ZTIN7android7String8E", "source_file" : "system/core/libutils/include/utils/String8.h" }, + { + "function_name" : "android::String8::getBasePath", + "linker_set_key" : "_ZNK7android7String811getBasePathEv", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + } + ], + "return_type" : "_ZTIN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, + { + "function_name" : "android::String8::getPathLeaf", + "linker_set_key" : "_ZNK7android7String811getPathLeafEv", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + } + ], + "return_type" : "_ZTIN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, + { + "access" : "private", + "function_name" : "android::String8::find_extension", + "linker_set_key" : "_ZNK7android7String814find_extensionEv", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + } + ], + "return_type" : "_ZTIPc", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, + { + "function_name" : "android::String8::getPathExtension", + "linker_set_key" : "_ZNK7android7String816getPathExtensionEv", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + } + ], + "return_type" : "_ZTIN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, { "function_name" : "android::String8::find", "linker_set_key" : "_ZNK7android7String84findEPKcj", @@ -9112,6 +9198,23 @@ "return_type" : "_ZTIj", "source_file" : "system/core/libutils/include/utils/String8.h" }, + { + "function_name" : "android::String8::walkPath", + "linker_set_key" : "_ZNK7android7String88walkPathEPS0_", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + }, + { + "default_arg" : true, + "referenced_type" : "_ZTIPN7android7String8E" + } + ], + "return_type" : "_ZTIN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, { "function_name" : "android::String16::startsWith", "linker_set_key" : "_ZNK7android8String1610startsWithEPKDs", diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h index 9cef9f67854f..ea25c6aa3947 100644 --- a/libutils/include/utils/String8.h +++ b/libutils/include/utils/String8.h @@ -130,10 +130,80 @@ class String8 void toLower(); -private: - String8 getPathDir(void) const; + /* + * These methods operate on the string as if it were a path name. + */ + + /* + * Get just the filename component. + * + * "/tmp/foo/bar.c" --> "bar.c" + */ + String8 getPathLeaf(void) const; + + /* + * Remove the last (file name) component, leaving just the directory + * name. + * + * "/tmp/foo/bar.c" --> "/tmp/foo" + * "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX + * "bar.c" --> "" + */ + String8 getPathDir(void) const; + + /* + * Retrieve the front (root dir) component. Optionally also return the + * remaining components. + * + * "/tmp/foo/bar.c" --> "tmp" (remain = "foo/bar.c") + * "/tmp" --> "tmp" (remain = "") + * "bar.c" --> "bar.c" (remain = "") + */ + String8 walkPath(String8* outRemains = nullptr) const; + + /* + * Return the filename extension. This is the last '.' and any number + * of characters that follow it. The '.' is included in case we + * decide to expand our definition of what constitutes an extension. + * + * "/tmp/foo/bar.c" --> ".c" + * "/tmp" --> "" + * "/tmp/foo.bar/baz" --> "" + * "foo.jpeg" --> ".jpeg" + * "foo." --> "" + */ + String8 getPathExtension(void) const; + + /* + * Return the path without the extension. Rules for what constitutes + * an extension are described in the comment for getPathExtension(). + * + * "/tmp/foo/bar.c" --> "/tmp/foo/bar" + */ + String8 getBasePath(void) const; + + /* + * Add a component to the pathname. We guarantee that there is + * exactly one path separator between the old path and the new. + * If there is no existing name, we just copy the new name in. + * + * If leaf is a fully qualified path (i.e. starts with '/', it + * replaces whatever was there before. + */ + String8& appendPath(const char* leaf); + String8& appendPath(const String8& leaf) { return appendPath(leaf.c_str()); } + + /* + * Like appendPath(), but does not affect this string. Returns a new one instead. + */ + String8 appendPathCopy(const char* leaf) const + { String8 p(*this); p.appendPath(leaf); return p; } + String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.c_str()); } + +private: status_t real_append(const char* other, size_t numChars); + char* find_extension(void) const; const char* mString; }; From 4b6a7c3940bc6d5e89e15179d8d49600e6dd4857 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 8 Sep 2023 17:11:39 +0000 Subject: [PATCH 0371/1487] Revert "Revert "Drop all path-related methods from android::String8"" This reverts commit cff2e40d19113fa7ed57fedae072ad605cef1be7. Reason for revert: Attempt re-submit Change-Id: I8802b519e4ae3046858b854815ba580c7a6b965d --- libutils/String8.cpp | 108 +----------------- libutils/String8_fuzz.cpp | 24 ---- .../arm64/source-based/libutils.so.lsdump | 88 +------------- .../arm_arm64/source-based/libutils.so.lsdump | 88 +------------- libutils/include/utils/String8.h | 75 +----------- 5 files changed, 8 insertions(+), 375 deletions(-) diff --git a/libutils/String8.cpp b/libutils/String8.cpp index 2b72847e52bd..4301f0ea3a77 100644 --- a/libutils/String8.cpp +++ b/libutils/String8.cpp @@ -430,31 +430,6 @@ void String8::toLower() // --------------------------------------------------------------------------- // Path functions -static void setPathName(String8& s, const char* name) { - size_t len = strlen(name); - char* buf = s.lockBuffer(len); - - memcpy(buf, name, len); - - // remove trailing path separator, if present - if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--; - buf[len] = '\0'; - - s.unlockBuffer(len); -} - -String8 String8::getPathLeaf(void) const -{ - const char* cp; - const char*const buf = mString; - - cp = strrchr(buf, OS_PATH_SEPARATOR); - if (cp == nullptr) - return String8(*this); - else - return String8(cp+1); -} - String8 String8::getPathDir(void) const { const char* cp; @@ -467,40 +442,14 @@ String8 String8::getPathDir(void) const return String8(str, cp - str); } -String8 String8::walkPath(String8* outRemains) const -{ - const char* cp; - const char*const str = mString; - const char* buf = str; - - cp = strchr(buf, OS_PATH_SEPARATOR); - if (cp == buf) { - // don't include a leading '/'. - buf = buf+1; - cp = strchr(buf, OS_PATH_SEPARATOR); - } - - if (cp == nullptr) { - String8 res = buf != str ? String8(buf) : *this; - if (outRemains) *outRemains = String8(""); - return res; - } - - String8 res(buf, cp-buf); - if (outRemains) *outRemains = String8(cp+1); - return res; -} - /* * Helper function for finding the start of an extension in a pathname. * * Returns a pointer inside mString, or NULL if no extension was found. */ -char* String8::find_extension(void) const -{ +static const char* find_extension(const char* str) { const char* lastSlash; const char* lastDot; - const char* const str = mString; // only look at the filename lastSlash = strrchr(str, OS_PATH_SEPARATOR); @@ -515,67 +464,16 @@ char* String8::find_extension(void) const return nullptr; // looks good, ship it - return const_cast(lastDot); + return lastDot; } String8 String8::getPathExtension(void) const { - char* ext; - - ext = find_extension(); + auto ext = find_extension(mString); if (ext != nullptr) return String8(ext); else return String8(""); } -String8 String8::getBasePath(void) const -{ - char* ext; - const char* const str = mString; - - ext = find_extension(); - if (ext == nullptr) - return String8(*this); - else - return String8(str, ext - str); -} - -String8& String8::appendPath(const char* name) -{ - // TODO: The test below will fail for Win32 paths. Fix later or ignore. - if (name[0] != OS_PATH_SEPARATOR) { - if (*name == '\0') { - // nothing to do - return *this; - } - - size_t len = length(); - if (len == 0) { - // no existing filename, just use the new one - setPathName(*this, name); - return *this; - } - - // make room for oldPath + '/' + newPath - int newlen = strlen(name); - - char* buf = lockBuffer(len+1+newlen); - - // insert a '/' if needed - if (buf[len-1] != OS_PATH_SEPARATOR) - buf[len++] = OS_PATH_SEPARATOR; - - memcpy(buf+len, name, newlen+1); - len += newlen; - - unlockBuffer(len); - - return *this; - } else { - setPathName(*this, name); - return *this; - } -} - }; // namespace android diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp index 6f7a54f9f310..cbce0505891e 100644 --- a/libutils/String8_fuzz.cpp +++ b/libutils/String8_fuzz.cpp @@ -68,30 +68,6 @@ std::vectorConsumeIntegralInRange(0, str1->size()); str1->find(str2->c_str(), start_index); }, - - // Path handling - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - str1->getBasePath(); - }, - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - str1->getPathExtension(); - }, - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - str1->getPathLeaf(); - }, - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - str1->getPathDir(); - }, - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - std::shared_ptr path_out_str = - std::make_shared(); - str1->walkPath(path_out_str.get()); - path_out_str->clear(); - }, - [](FuzzedDataProvider* dataProvider, android::String8* str1, - android::String8*) -> void { - str1->appendPath(dataProvider->ConsumeBytesWithTerminator(5).data()); - }, }; void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend) { diff --git a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump index 46baddecde7b..8881b44eb181 100644 --- a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump +++ b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump @@ -703,9 +703,6 @@ { "name" : "_ZN7android7RefBaseD2Ev" }, - { - "name" : "_ZN7android7String810appendPathEPKc" - }, { "name" : "_ZN7android7String810lockBufferEm" }, @@ -1144,15 +1141,6 @@ { "name" : "_ZNK7android7String810getPathDirEv" }, - { - "name" : "_ZNK7android7String811getBasePathEv" - }, - { - "name" : "_ZNK7android7String811getPathLeafEv" - }, - { - "name" : "_ZNK7android7String814find_extensionEv" - }, { "name" : "_ZNK7android7String816getPathExtensionEv" }, @@ -1162,9 +1150,6 @@ { "name" : "_ZNK7android7String86lengthEv" }, - { - "name" : "_ZNK7android7String88walkPathEPS0_" - }, { "name" : "_ZNK7android8String1610startsWithEPKDs" }, @@ -6808,22 +6793,6 @@ "return_type" : "_ZTIv", "source_file" : "system/core/libutils/include/utils/RefBase.h" }, - { - "function_name" : "android::String8::appendPath", - "linker_set_key" : "_ZN7android7String810appendPathEPKc", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPN7android7String8E" - }, - { - "referenced_type" : "_ZTIPKc" - } - ], - "return_type" : "_ZTIRN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String8::lockBuffer", "linker_set_key" : "_ZN7android7String810lockBufferEm", @@ -9104,6 +9073,7 @@ "source_file" : "system/core/libutils/include/utils/RefBase.h" }, { + "access" : "private", "function_name" : "android::String8::getPathDir", "linker_set_key" : "_ZNK7android7String810getPathDirEv", "parameters" : @@ -9116,47 +9086,8 @@ "return_type" : "_ZTIN7android7String8E", "source_file" : "system/core/libutils/include/utils/String8.h" }, - { - "function_name" : "android::String8::getBasePath", - "linker_set_key" : "_ZNK7android7String811getBasePathEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, - { - "function_name" : "android::String8::getPathLeaf", - "linker_set_key" : "_ZNK7android7String811getPathLeafEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "access" : "private", - "function_name" : "android::String8::find_extension", - "linker_set_key" : "_ZNK7android7String814find_extensionEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIPc", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, - { "function_name" : "android::String8::getPathExtension", "linker_set_key" : "_ZNK7android7String816getPathExtensionEv", "parameters" : @@ -9202,23 +9133,6 @@ "return_type" : "_ZTIm", "source_file" : "system/core/libutils/include/utils/String8.h" }, - { - "function_name" : "android::String8::walkPath", - "linker_set_key" : "_ZNK7android7String88walkPathEPS0_", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - }, - { - "default_arg" : true, - "referenced_type" : "_ZTIPN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String16::startsWith", "linker_set_key" : "_ZNK7android8String1610startsWithEPKDs", diff --git a/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump b/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump index 219c76665bb9..e8236ea5b6af 100644 --- a/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump +++ b/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump @@ -703,9 +703,6 @@ { "name" : "_ZN7android7RefBaseD2Ev" }, - { - "name" : "_ZN7android7String810appendPathEPKc" - }, { "name" : "_ZN7android7String810lockBufferEj" }, @@ -1144,15 +1141,6 @@ { "name" : "_ZNK7android7String810getPathDirEv" }, - { - "name" : "_ZNK7android7String811getBasePathEv" - }, - { - "name" : "_ZNK7android7String811getPathLeafEv" - }, - { - "name" : "_ZNK7android7String814find_extensionEv" - }, { "name" : "_ZNK7android7String816getPathExtensionEv" }, @@ -1162,9 +1150,6 @@ { "name" : "_ZNK7android7String86lengthEv" }, - { - "name" : "_ZNK7android7String88walkPathEPS0_" - }, { "name" : "_ZNK7android8String1610startsWithEPKDs" }, @@ -6804,22 +6789,6 @@ "return_type" : "_ZTIv", "source_file" : "system/core/libutils/include/utils/RefBase.h" }, - { - "function_name" : "android::String8::appendPath", - "linker_set_key" : "_ZN7android7String810appendPathEPKc", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPN7android7String8E" - }, - { - "referenced_type" : "_ZTIPKc" - } - ], - "return_type" : "_ZTIRN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String8::lockBuffer", "linker_set_key" : "_ZN7android7String810lockBufferEj", @@ -9100,6 +9069,7 @@ "source_file" : "system/core/libutils/include/utils/RefBase.h" }, { + "access" : "private", "function_name" : "android::String8::getPathDir", "linker_set_key" : "_ZNK7android7String810getPathDirEv", "parameters" : @@ -9112,47 +9082,8 @@ "return_type" : "_ZTIN7android7String8E", "source_file" : "system/core/libutils/include/utils/String8.h" }, - { - "function_name" : "android::String8::getBasePath", - "linker_set_key" : "_ZNK7android7String811getBasePathEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, - { - "function_name" : "android::String8::getPathLeaf", - "linker_set_key" : "_ZNK7android7String811getPathLeafEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "access" : "private", - "function_name" : "android::String8::find_extension", - "linker_set_key" : "_ZNK7android7String814find_extensionEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIPc", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, - { "function_name" : "android::String8::getPathExtension", "linker_set_key" : "_ZNK7android7String816getPathExtensionEv", "parameters" : @@ -9198,23 +9129,6 @@ "return_type" : "_ZTIj", "source_file" : "system/core/libutils/include/utils/String8.h" }, - { - "function_name" : "android::String8::walkPath", - "linker_set_key" : "_ZNK7android7String88walkPathEPS0_", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - }, - { - "default_arg" : true, - "referenced_type" : "_ZTIPN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String16::startsWith", "linker_set_key" : "_ZNK7android8String1610startsWithEPKDs", diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h index ea25c6aa3947..fbb0a0ae32ae 100644 --- a/libutils/include/utils/String8.h +++ b/libutils/include/utils/String8.h @@ -130,80 +130,11 @@ class String8 void toLower(); - - /* - * These methods operate on the string as if it were a path name. - */ - - /* - * Get just the filename component. - * - * "/tmp/foo/bar.c" --> "bar.c" - */ - String8 getPathLeaf(void) const; - - /* - * Remove the last (file name) component, leaving just the directory - * name. - * - * "/tmp/foo/bar.c" --> "/tmp/foo" - * "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX - * "bar.c" --> "" - */ - String8 getPathDir(void) const; - - /* - * Retrieve the front (root dir) component. Optionally also return the - * remaining components. - * - * "/tmp/foo/bar.c" --> "tmp" (remain = "foo/bar.c") - * "/tmp" --> "tmp" (remain = "") - * "bar.c" --> "bar.c" (remain = "") - */ - String8 walkPath(String8* outRemains = nullptr) const; - - /* - * Return the filename extension. This is the last '.' and any number - * of characters that follow it. The '.' is included in case we - * decide to expand our definition of what constitutes an extension. - * - * "/tmp/foo/bar.c" --> ".c" - * "/tmp" --> "" - * "/tmp/foo.bar/baz" --> "" - * "foo.jpeg" --> ".jpeg" - * "foo." --> "" - */ - String8 getPathExtension(void) const; - - /* - * Return the path without the extension. Rules for what constitutes - * an extension are described in the comment for getPathExtension(). - * - * "/tmp/foo/bar.c" --> "/tmp/foo/bar" - */ - String8 getBasePath(void) const; - - /* - * Add a component to the pathname. We guarantee that there is - * exactly one path separator between the old path and the new. - * If there is no existing name, we just copy the new name in. - * - * If leaf is a fully qualified path (i.e. starts with '/', it - * replaces whatever was there before. - */ - String8& appendPath(const char* leaf); - String8& appendPath(const String8& leaf) { return appendPath(leaf.c_str()); } - - /* - * Like appendPath(), but does not affect this string. Returns a new one instead. - */ - String8 appendPathCopy(const char* leaf) const - { String8 p(*this); p.appendPath(leaf); return p; } - String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.c_str()); } - private: + String8 getPathDir(void) const; + String8 getPathExtension(void) const; + status_t real_append(const char* other, size_t numChars); - char* find_extension(void) const; const char* mString; }; From bcae6b5e608278bad272a278f9ffd273fb465609 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Fri, 8 Sep 2023 17:01:15 -0700 Subject: [PATCH 0372/1487] libsnapshot_cow: Prepare device to boot from pre-created snapshots Two new API's have been added: 1: BootFromSnapshotsWithoutSlotSwitch: This will create a new marker which indicates first-stage init to mount the partitions off snapshots. We need this marker as during boot, there are couple of places during mounting snapshots wherein the marker is used. However, there is no change in the existing I/O path related to OTA. 2: PrepareDeviceToBootWithoutSnapshot: This will delete the marker so that subsequent reboot will not have the partitions mounted without the snapshots. VTS tests covers both these API's. Additionally, when these markers are present, new OTA's cannot be installed. All these are covered in VTS tests. =========================================================== snapshotctl: General flow to apply and revert pre-created snapshots 1: To install the pre-created snapshots: $snapshotctl map-snapshots Now the device is ready to boot from snapshots. 2: After device reboots, partitions are mounted off the snapshots. There is no snapshot-merge. 3: In order to go back to previous build: $snapshotctl revert-snapshots Now the device is ready to boot from base build. 4: After device reboots back to previous build, all the snapshot states and COW images are removed. ============================================ Additional commands: To delete the pre-created snapshots: $snapshotctl delete-snapshots ====================================== Tested it on Pixel 6 Pro between two builds which are ~24 hours apart. 1: Creating snapshots on a linux-host - ~4-6 seconds 2: Applying pre-created snapshots - ~10-15 seconds (includes intermediate transfer of patches to the device). This depends on the size of snapshot patches. 3: Device reboot - ~12-14 seconds. Bug: 299011882 Test: 1: Apply pre-created snapshots 2: Reboot device: Verify new build 3: Apply OTA when partitions are mounted of snapshots and verify OTA fails. 3: Revert-snapshot and reboot. 4: Verify device goes back to base build. Full OTA on Pixel. vts_libsnapshot_test Change-Id: I36a72d973d8f70ae49773ebd45dd996fac22a4e3 Signed-off-by: Akilesh Kailash --- .../include/libsnapshot/snapshot.h | 18 ++- fs_mgr/libsnapshot/snapshot.cpp | 122 ++++++++++++++++-- fs_mgr/libsnapshot/snapshot_test.cpp | 50 +++++++ fs_mgr/libsnapshot/snapshotctl.cpp | 92 +++++++++---- 4 files changed, 250 insertions(+), 32 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h index 6bc8b9b5a013..e7b0020ead86 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h @@ -73,6 +73,9 @@ class ISnapshotMergeStats; class SnapshotMergeStats; class SnapshotStatus; +using std::chrono::duration_cast; +using namespace std::chrono_literals; + static constexpr const std::string_view kCowGroupName = "cow"; static constexpr char kVirtualAbCompressionProp[] = "ro.virtual_ab.compression.enabled"; @@ -424,6 +427,7 @@ class SnapshotManager final : public ISnapshotManager { FRIEND_TEST(SnapshotTest, MergeFailureCode); FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot); FRIEND_TEST(SnapshotTest, UpdateBootControlHal); + FRIEND_TEST(SnapshotTest, BootSnapshotWithoutSlotSwitch); FRIEND_TEST(SnapshotUpdateTest, AddPartition); FRIEND_TEST(SnapshotUpdateTest, ConsistencyCheckResume); FRIEND_TEST(SnapshotUpdateTest, DaemonTransition); @@ -436,6 +440,7 @@ class SnapshotManager final : public ISnapshotManager { FRIEND_TEST(SnapshotUpdateTest, QueryStatusError); FRIEND_TEST(SnapshotUpdateTest, SnapshotStatusFileWithoutCow); FRIEND_TEST(SnapshotUpdateTest, SpaceSwapUpdate); + FRIEND_TEST(SnapshotUpdateTest, MapAllSnapshotsWithoutSlotSwitch); friend class SnapshotTest; friend class SnapshotUpdateTest; friend class FlashAfterUpdateTest; @@ -456,7 +461,7 @@ class SnapshotManager final : public ISnapshotManager { bool EnsureImageManager(); // Ensure we're connected to snapuserd. - bool EnsureSnapuserdConnected(); + bool EnsureSnapuserdConnected(std::chrono::milliseconds timeout_ms = 10s); // Helpers for first-stage init. const std::unique_ptr& device() const { return device_; } @@ -549,6 +554,16 @@ class SnapshotManager final : public ISnapshotManager { // Unmap and remove all known snapshots. bool RemoveAllSnapshots(LockedFile* lock); + // Boot device off snapshots without slot switch + bool BootFromSnapshotsWithoutSlotSwitch(); + + // Remove kBootSnapshotsWithoutSlotSwitch so that device can boot + // without snapshots on the current slot + bool PrepareDeviceToBootWithoutSnapshot(); + + // Is the kBootSnapshotsWithoutSlotSwitch present + bool IsSnapshotWithoutSlotSwitch(); + // List the known snapshot names. bool ListSnapshots(LockedFile* lock, std::vector* snapshots, const std::string& suffix = ""); @@ -663,6 +678,7 @@ class SnapshotManager final : public ISnapshotManager { std::string GetRollbackIndicatorPath(); std::string GetForwardMergeIndicatorPath(); std::string GetOldPartitionMetadataPath(); + std::string GetBootSnapshotsWithoutSlotSwitchPath(); const LpMetadata* ReadOldPartitionMetadata(LockedFile* lock); diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index 51389a0dbf27..4743a42a4b23 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -83,6 +83,8 @@ using std::chrono::duration_cast; using namespace std::chrono_literals; using namespace std::string_literals; +static constexpr char kBootSnapshotsWithoutSlotSwitch[] = + "/metadata/ota/snapshot-boot-without-slot-switch"; static constexpr char kBootIndicatorPath[] = "/metadata/ota/snapshot-boot"; static constexpr char kRollbackIndicatorPath[] = "/metadata/ota/rollback-indicator"; static constexpr auto kUpdateStateCheckInterval = 2s; @@ -217,6 +219,12 @@ bool SnapshotManager::TryCancelUpdate(bool* needs_merge) { auto file = LockExclusive(); if (!file) return false; + if (IsSnapshotWithoutSlotSwitch()) { + LOG(ERROR) << "Cannot cancel the snapshots as partitions are mounted off the snapshots on " + "current slot."; + return false; + } + UpdateState state = ReadUpdateState(file.get()); if (state == UpdateState::None) { RemoveInvalidSnapshots(file.get()); @@ -299,10 +307,9 @@ bool SnapshotManager::RemoveAllUpdateState(LockedFile* lock, const std::function // - For ForwardMerge, FinishedSnapshotWrites asserts that the existence of the indicator // matches the incoming update. std::vector files = { - GetSnapshotBootIndicatorPath(), - GetRollbackIndicatorPath(), - GetForwardMergeIndicatorPath(), - GetOldPartitionMetadataPath(), + GetSnapshotBootIndicatorPath(), GetRollbackIndicatorPath(), + GetForwardMergeIndicatorPath(), GetOldPartitionMetadataPath(), + GetBootSnapshotsWithoutSlotSwitchPath(), }; for (const auto& file : files) { RemoveFileIfExists(file); @@ -483,6 +490,32 @@ bool SnapshotManager::MapDmUserCow(LockedFile* lock, const std::string& name, LOG(ERROR) << "Failed to retrieve base_sectors from Snapuserd"; return false; } + } else if (IsSnapshotWithoutSlotSwitch()) { + // When snapshots are on current slot, we determine the size + // of block device based on the number of COW operations. We cannot + // use base device as it will be from older image. + size_t num_ops = 0; + uint64_t dev_sz = 0; + unique_fd fd(open(cow_file.c_str(), O_RDONLY | O_CLOEXEC)); + if (fd < 0) { + PLOG(ERROR) << "Failed to open " << cow_file; + return false; + } + + CowReader reader; + if (!reader.Parse(std::move(fd))) { + LOG(ERROR) << "Failed to parse cow " << cow_file; + return false; + } + + const auto& header = reader.GetHeader(); + if (header.prefix.major_version > 2) { + LOG(ERROR) << "COW format not supported"; + return false; + } + num_ops = reader.get_num_total_data_ops(); + dev_sz = (num_ops * header.block_size); + base_sectors = dev_sz >> 9; } else { // For userspace snapshots, the size of the base device is taken as the // size of the dm-user block device. Since there is no pseudo mapping @@ -1479,6 +1512,10 @@ MergeFailureCode SnapshotManager::MergeSecondPhaseSnapshots(LockedFile* lock) { return result; } +std::string SnapshotManager::GetBootSnapshotsWithoutSlotSwitchPath() { + return metadata_dir_ + "/" + android::base::Basename(kBootSnapshotsWithoutSlotSwitch); +} + std::string SnapshotManager::GetSnapshotBootIndicatorPath() { return metadata_dir_ + "/" + android::base::Basename(kBootIndicatorPath); } @@ -2120,6 +2157,10 @@ UpdateState SnapshotManager::GetUpdateState(double* progress) { return state; } +bool SnapshotManager::IsSnapshotWithoutSlotSwitch() { + return (access(GetBootSnapshotsWithoutSlotSwitchPath().c_str(), F_OK) == 0); +} + bool SnapshotManager::UpdateUsesCompression() { auto lock = LockShared(); if (!lock) return false; @@ -2212,6 +2253,13 @@ std::string SnapshotManager::GetGlobalRollbackIndicatorPath() { } bool SnapshotManager::NeedSnapshotsInFirstStageMount() { + if (IsSnapshotWithoutSlotSwitch()) { + if (GetCurrentSlot() != Slot::Source) { + LOG(ERROR) << "Snapshots marked to boot without slot switch; but slot is wrong"; + return false; + } + return true; + } // If we fail to read, we'll wind up using CreateLogicalPartitions, which // will create devices that look like the old slot, except with extra // content at the end of each device. This will confuse dm-verity, and @@ -2347,7 +2395,8 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock, // completed, live_snapshot_status is set to nullopt. std::optional live_snapshot_status; do { - if (!(params.partition->attributes & LP_PARTITION_ATTR_UPDATED)) { + if (!IsSnapshotWithoutSlotSwitch() && + !(params.partition->attributes & LP_PARTITION_ATTR_UPDATED)) { LOG(INFO) << "Detected re-flashing of partition, will skip snapshot: " << params.GetPartitionName(); break; @@ -2703,7 +2752,7 @@ bool SnapshotManager::UnmapUserspaceSnapshotDevice(LockedFile* lock, // to unmap; hence, we can't be deleting the device // as the table would be mounted off partitions and will fail. if (snapshot_status.state() != SnapshotState::MERGE_COMPLETED) { - if (!DeleteDeviceIfExists(dm_user_name)) { + if (!DeleteDeviceIfExists(dm_user_name, 4000ms)) { LOG(ERROR) << "Cannot unmap " << dm_user_name; return false; } @@ -3098,7 +3147,7 @@ bool SnapshotManager::EnsureImageManager() { return true; } -bool SnapshotManager::EnsureSnapuserdConnected() { +bool SnapshotManager::EnsureSnapuserdConnected(std::chrono::milliseconds timeout_ms) { if (snapuserd_client_) { return true; } @@ -3107,7 +3156,7 @@ bool SnapshotManager::EnsureSnapuserdConnected() { return false; } - snapuserd_client_ = SnapuserdClient::Connect(kSnapuserdSocket, 10s); + snapuserd_client_ = SnapuserdClient::Connect(kSnapuserdSocket, timeout_ms); if (!snapuserd_client_) { LOG(ERROR) << "Unable to connect to snapuserd"; return false; @@ -4372,13 +4421,70 @@ std::string SnapshotManager::ReadSourceBuildFingerprint() { bool SnapshotManager::IsUserspaceSnapshotUpdateInProgress() { auto slot = GetCurrentSlot(); if (slot == Slot::Target) { + // Merge in-progress if (IsSnapuserdRequired()) { return true; } } + // Let's check more deeper to see if snapshots are mounted + auto lock = LockExclusive(); + if (!lock) { + return false; + } + + std::vector snapshots; + if (!ListSnapshots(lock.get(), &snapshots)) { + return false; + } + + for (const auto& snapshot : snapshots) { + // Active snapshot and daemon is alive + if (IsSnapshotDevice(snapshot) && EnsureSnapuserdConnected(2s)) { + return true; + } + } + return false; } +bool SnapshotManager::BootFromSnapshotsWithoutSlotSwitch() { + auto lock = LockExclusive(); + if (!lock) return false; + + auto contents = device_->GetSlotSuffix(); + // This is the indicator which tells first-stage init + // to boot from snapshots even though there was no slot-switch + auto boot_file = GetBootSnapshotsWithoutSlotSwitchPath(); + if (!WriteStringToFileAtomic(contents, boot_file)) { + PLOG(ERROR) << "write failed: " << boot_file; + return false; + } + + SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock.get()); + update_status.set_state(UpdateState::Initiated); + update_status.set_userspace_snapshots(true); + update_status.set_using_snapuserd(true); + if (!WriteSnapshotUpdateStatus(lock.get(), update_status)) { + return false; + } + return true; +} + +bool SnapshotManager::PrepareDeviceToBootWithoutSnapshot() { + auto lock = LockExclusive(); + if (!lock) return false; + + android::base::RemoveFileIfExists(GetSnapshotBootIndicatorPath()); + android::base::RemoveFileIfExists(GetBootSnapshotsWithoutSlotSwitchPath()); + + SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock.get()); + update_status.set_state(UpdateState::Cancelled); + if (!WriteSnapshotUpdateStatus(lock.get(), update_status)) { + return false; + } + return true; +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index 3b6d26aa11ff..e506110b61a7 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -2559,6 +2559,56 @@ TEST_F(SnapshotUpdateTest, DaemonTransition) { } } +TEST_F(SnapshotUpdateTest, MapAllSnapshotsWithoutSlotSwitch) { + MountMetadata(); + AddOperationForPartitions(); + // Execute the update. + ASSERT_TRUE(sm->BeginUpdate()); + ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_)); + + if (!sm->UpdateUsesUserSnapshots()) { + GTEST_SKIP() << "Test does not apply as UserSnapshots aren't enabled."; + } + + ASSERT_TRUE(WriteSnapshots()); + ASSERT_TRUE(sm->FinishedSnapshotWrites(false)); + + if (ShouldSkipLegacyMerging()) { + GTEST_SKIP() << "Skipping legacy merge test"; + } + // Mark the indicator + ASSERT_TRUE(sm->BootFromSnapshotsWithoutSlotSwitch()); + + ASSERT_TRUE(sm->EnsureSnapuserdConnected()); + sm->set_use_first_stage_snapuserd(true); + + ASSERT_TRUE(sm->NeedSnapshotsInFirstStageMount()); + + // Map snapshots + ASSERT_TRUE(sm->MapAllSnapshots(10s)); + + // New updates should fail + ASSERT_FALSE(sm->BeginUpdate()); + + // Snapshots cannot be cancelled + ASSERT_FALSE(sm->CancelUpdate()); + + // Merge cannot start + ASSERT_FALSE(sm->InitiateMerge()); + + // Read bytes back and verify they match the cache. + ASSERT_TRUE(IsPartitionUnchanged("sys_b")); + + // Remove the indicators + ASSERT_TRUE(sm->PrepareDeviceToBootWithoutSnapshot()); + + // Ensure snapshots are still mounted + ASSERT_TRUE(sm->IsUserspaceSnapshotUpdateInProgress()); + + // Cleanup snapshots + ASSERT_TRUE(sm->UnmapAllSnapshots()); +} + TEST_F(SnapshotUpdateTest, MapAllSnapshots) { AddOperationForPartitions(); // Execute the update. diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp index 1323b0bc8a64..ebaca2dbe92a 100644 --- a/fs_mgr/libsnapshot/snapshotctl.cpp +++ b/fs_mgr/libsnapshot/snapshotctl.cpp @@ -75,7 +75,11 @@ int Usage() { " unmap-snapshots\n" " Unmap all pre-created snapshots\n" " delete-snapshots\n" - " Delete all pre-created snapshots\n"; + " Delete all pre-created snapshots\n" + " revert-snapshots\n" + " Prepares devices to boot without snapshots on next boot.\n" + " This does not delete the snapshot. It only removes the indicators\n" + " so that first stage init will not mount from snapshots.\n"; return EX_USAGE; } @@ -87,9 +91,11 @@ class MapSnapshots { MapSnapshots(std::string path = ""); bool CreateSnapshotDevice(std::string& partition_name, std::string& patch); bool InitiateThreadedSnapshotWrite(std::string& pname, std::string& snapshot_patch); - bool WaitForSnapshotWritesToComplete(); + bool FinishSnapshotWrites(); bool UnmapCowImagePath(std::string& name); - bool DeleteCowImage(std::string& name); + bool DeleteSnapshots(); + bool CleanupSnapshot() { return sm_->PrepareDeviceToBootWithoutSnapshot(); } + bool BeginUpdate(); private: std::optional GetCowImagePath(std::string& name); @@ -107,7 +113,24 @@ MapSnapshots::MapSnapshots(std::string path) { exit(1); } snapshot_dir_path_ = path + "/"; +} + +bool MapSnapshots::BeginUpdate() { lock_ = sm_->LockExclusive(); + std::vector snapshots; + sm_->ListSnapshots(lock_.get(), &snapshots); + if (!snapshots.empty()) { + // Snapshots are already present. + return true; + } + + lock_ = nullptr; + if (!sm_->BeginUpdate()) { + LOG(ERROR) << "BeginUpdate failed"; + return false; + } + lock_ = sm_->LockExclusive(); + return true; } bool MapSnapshots::CreateSnapshotDevice(std::string& partition_name, std::string& patchfile) { @@ -130,6 +153,9 @@ bool MapSnapshots::CreateSnapshotDevice(std::string& partition_name, std::string dev_sz &= ~(block_sz - 1); SnapshotStatus status; + status.set_state(SnapshotState::CREATED); + status.set_using_snapuserd(true); + status.set_old_partition_size(0); status.set_name(partition_name); status.set_cow_file_size(dev_sz); status.set_cow_partition_size(0); @@ -216,27 +242,33 @@ bool MapSnapshots::InitiateThreadedSnapshotWrite(std::string& pname, std::string return true; } -bool MapSnapshots::WaitForSnapshotWritesToComplete() { +bool MapSnapshots::FinishSnapshotWrites() { bool ret = true; for (auto& t : threads_) { ret = t.get() && ret; } + lock_ = nullptr; if (ret) { LOG(INFO) << "Pre-created snapshots successfully copied"; - } else { - LOG(ERROR) << "Snapshot copy failed"; + if (!sm_->FinishedSnapshotWrites(false)) { + return false; + } + return sm_->BootFromSnapshotsWithoutSlotSwitch(); } - return ret; + + LOG(ERROR) << "Snapshot copy failed"; + return false; } bool MapSnapshots::UnmapCowImagePath(std::string& name) { return sm_->UnmapCowImage(name); } -bool MapSnapshots::DeleteCowImage(std::string& name) { - if (!sm_->DeleteSnapshot(lock_.get(), name)) { - LOG(ERROR) << "Delete snapshot failed"; +bool MapSnapshots::DeleteSnapshots() { + lock_ = sm_->LockExclusive(); + if (!sm_->RemoveAllUpdateState(lock_.get())) { + LOG(ERROR) << "Remove All Update State failed"; return false; } return true; @@ -281,7 +313,8 @@ bool GetVerityPartitions(std::vector& partitions) { return true; } -bool UnMapPrecreatedSnapshots(int, char**) { +bool UnMapPrecreatedSnapshots(int, char** argv) { + android::base::InitLogging(argv, &android::base::KernelLogger); // Make sure we are root. if (::getuid() != 0) { LOG(ERROR) << "Not running as root. Try \"adb root\" first."; @@ -302,29 +335,36 @@ bool UnMapPrecreatedSnapshots(int, char**) { return true; } -bool DeletePrecreatedSnapshots(int, char**) { +bool RemovePrecreatedSnapshots(int, char** argv) { + android::base::InitLogging(argv, &android::base::KernelLogger); // Make sure we are root. if (::getuid() != 0) { LOG(ERROR) << "Not running as root. Try \"adb root\" first."; - return EXIT_FAILURE; - } - - std::vector partitions; - if (!GetVerityPartitions(partitions)) { return false; } MapSnapshots snapshot; - for (auto partition : partitions) { - if (!snapshot.DeleteCowImage(partition)) { - LOG(ERROR) << "DeleteCowImage failed: " << partition; - } + if (!snapshot.CleanupSnapshot()) { + LOG(ERROR) << "CleanupSnapshot failed"; + return false; } return true; } +bool DeletePrecreatedSnapshots(int, char** argv) { + android::base::InitLogging(argv, &android::base::KernelLogger); + // Make sure we are root. + if (::getuid() != 0) { + LOG(ERROR) << "Not running as root. Try \"adb root\" first."; + return EXIT_FAILURE; + } + + MapSnapshots snapshot; + return snapshot.DeleteSnapshots(); +} + bool MapPrecreatedSnapshots(int argc, char** argv) { - android::base::InitLogging(argv, &android::base::StderrLogger); + android::base::InitLogging(argv, &android::base::KernelLogger); // Make sure we are root. if (::getuid() != 0) { @@ -365,6 +405,11 @@ bool MapPrecreatedSnapshots(int argc, char** argv) { } MapSnapshots cow(path); + if (!cow.BeginUpdate()) { + LOG(ERROR) << "BeginUpdate failed"; + return false; + } + for (auto& pair : partitions) { if (!cow.CreateSnapshotDevice(pair.first, pair.second)) { LOG(ERROR) << "CreateSnapshotDevice failed for: " << pair.first; @@ -376,7 +421,7 @@ bool MapPrecreatedSnapshots(int argc, char** argv) { } } - return cow.WaitForSnapshotWritesToComplete(); + return cow.FinishSnapshotWrites(); } #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG @@ -508,6 +553,7 @@ static std::map> kCmdMap = { {"map-snapshots", MapPrecreatedSnapshots}, {"unmap-snapshots", UnMapPrecreatedSnapshots}, {"delete-snapshots", DeletePrecreatedSnapshots}, + {"revert-snapshots", RemovePrecreatedSnapshots}, // clang-format on }; From 141255f30c35372bba80bfff9ac164f34e38784b Mon Sep 17 00:00:00 2001 From: Rhed Jao Date: Mon, 11 Sep 2023 02:05:58 +0000 Subject: [PATCH 0373/1487] Revert "Revert "Revert "Drop all path-related methods from android::String8""" This reverts commit 4b6a7c3940bc6d5e89e15179d8d49600e6dd4857. Reason for revert: b/299695302, b/299694769 Change-Id: I89c6719d23446f2f9ce24e5b75d321538b580431 --- libutils/String8.cpp | 108 +++++++++++++++++- libutils/String8_fuzz.cpp | 24 ++++ .../arm64/source-based/libutils.so.lsdump | 88 +++++++++++++- .../arm_arm64/source-based/libutils.so.lsdump | 88 +++++++++++++- libutils/include/utils/String8.h | 75 +++++++++++- 5 files changed, 375 insertions(+), 8 deletions(-) diff --git a/libutils/String8.cpp b/libutils/String8.cpp index 4301f0ea3a77..2b72847e52bd 100644 --- a/libutils/String8.cpp +++ b/libutils/String8.cpp @@ -430,6 +430,31 @@ void String8::toLower() // --------------------------------------------------------------------------- // Path functions +static void setPathName(String8& s, const char* name) { + size_t len = strlen(name); + char* buf = s.lockBuffer(len); + + memcpy(buf, name, len); + + // remove trailing path separator, if present + if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--; + buf[len] = '\0'; + + s.unlockBuffer(len); +} + +String8 String8::getPathLeaf(void) const +{ + const char* cp; + const char*const buf = mString; + + cp = strrchr(buf, OS_PATH_SEPARATOR); + if (cp == nullptr) + return String8(*this); + else + return String8(cp+1); +} + String8 String8::getPathDir(void) const { const char* cp; @@ -442,14 +467,40 @@ String8 String8::getPathDir(void) const return String8(str, cp - str); } +String8 String8::walkPath(String8* outRemains) const +{ + const char* cp; + const char*const str = mString; + const char* buf = str; + + cp = strchr(buf, OS_PATH_SEPARATOR); + if (cp == buf) { + // don't include a leading '/'. + buf = buf+1; + cp = strchr(buf, OS_PATH_SEPARATOR); + } + + if (cp == nullptr) { + String8 res = buf != str ? String8(buf) : *this; + if (outRemains) *outRemains = String8(""); + return res; + } + + String8 res(buf, cp-buf); + if (outRemains) *outRemains = String8(cp+1); + return res; +} + /* * Helper function for finding the start of an extension in a pathname. * * Returns a pointer inside mString, or NULL if no extension was found. */ -static const char* find_extension(const char* str) { +char* String8::find_extension(void) const +{ const char* lastSlash; const char* lastDot; + const char* const str = mString; // only look at the filename lastSlash = strrchr(str, OS_PATH_SEPARATOR); @@ -464,16 +515,67 @@ static const char* find_extension(const char* str) { return nullptr; // looks good, ship it - return lastDot; + return const_cast(lastDot); } String8 String8::getPathExtension(void) const { - auto ext = find_extension(mString); + char* ext; + + ext = find_extension(); if (ext != nullptr) return String8(ext); else return String8(""); } +String8 String8::getBasePath(void) const +{ + char* ext; + const char* const str = mString; + + ext = find_extension(); + if (ext == nullptr) + return String8(*this); + else + return String8(str, ext - str); +} + +String8& String8::appendPath(const char* name) +{ + // TODO: The test below will fail for Win32 paths. Fix later or ignore. + if (name[0] != OS_PATH_SEPARATOR) { + if (*name == '\0') { + // nothing to do + return *this; + } + + size_t len = length(); + if (len == 0) { + // no existing filename, just use the new one + setPathName(*this, name); + return *this; + } + + // make room for oldPath + '/' + newPath + int newlen = strlen(name); + + char* buf = lockBuffer(len+1+newlen); + + // insert a '/' if needed + if (buf[len-1] != OS_PATH_SEPARATOR) + buf[len++] = OS_PATH_SEPARATOR; + + memcpy(buf+len, name, newlen+1); + len += newlen; + + unlockBuffer(len); + + return *this; + } else { + setPathName(*this, name); + return *this; + } +} + }; // namespace android diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp index cbce0505891e..6f7a54f9f310 100644 --- a/libutils/String8_fuzz.cpp +++ b/libutils/String8_fuzz.cpp @@ -68,6 +68,30 @@ std::vectorConsumeIntegralInRange(0, str1->size()); str1->find(str2->c_str(), start_index); }, + + // Path handling + [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { + str1->getBasePath(); + }, + [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { + str1->getPathExtension(); + }, + [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { + str1->getPathLeaf(); + }, + [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { + str1->getPathDir(); + }, + [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { + std::shared_ptr path_out_str = + std::make_shared(); + str1->walkPath(path_out_str.get()); + path_out_str->clear(); + }, + [](FuzzedDataProvider* dataProvider, android::String8* str1, + android::String8*) -> void { + str1->appendPath(dataProvider->ConsumeBytesWithTerminator(5).data()); + }, }; void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend) { diff --git a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump index 8881b44eb181..46baddecde7b 100644 --- a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump +++ b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump @@ -703,6 +703,9 @@ { "name" : "_ZN7android7RefBaseD2Ev" }, + { + "name" : "_ZN7android7String810appendPathEPKc" + }, { "name" : "_ZN7android7String810lockBufferEm" }, @@ -1141,6 +1144,15 @@ { "name" : "_ZNK7android7String810getPathDirEv" }, + { + "name" : "_ZNK7android7String811getBasePathEv" + }, + { + "name" : "_ZNK7android7String811getPathLeafEv" + }, + { + "name" : "_ZNK7android7String814find_extensionEv" + }, { "name" : "_ZNK7android7String816getPathExtensionEv" }, @@ -1150,6 +1162,9 @@ { "name" : "_ZNK7android7String86lengthEv" }, + { + "name" : "_ZNK7android7String88walkPathEPS0_" + }, { "name" : "_ZNK7android8String1610startsWithEPKDs" }, @@ -6793,6 +6808,22 @@ "return_type" : "_ZTIv", "source_file" : "system/core/libutils/include/utils/RefBase.h" }, + { + "function_name" : "android::String8::appendPath", + "linker_set_key" : "_ZN7android7String810appendPathEPKc", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPN7android7String8E" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIRN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, { "function_name" : "android::String8::lockBuffer", "linker_set_key" : "_ZN7android7String810lockBufferEm", @@ -9073,7 +9104,6 @@ "source_file" : "system/core/libutils/include/utils/RefBase.h" }, { - "access" : "private", "function_name" : "android::String8::getPathDir", "linker_set_key" : "_ZNK7android7String810getPathDirEv", "parameters" : @@ -9086,8 +9116,47 @@ "return_type" : "_ZTIN7android7String8E", "source_file" : "system/core/libutils/include/utils/String8.h" }, + { + "function_name" : "android::String8::getBasePath", + "linker_set_key" : "_ZNK7android7String811getBasePathEv", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + } + ], + "return_type" : "_ZTIN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, + { + "function_name" : "android::String8::getPathLeaf", + "linker_set_key" : "_ZNK7android7String811getPathLeafEv", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + } + ], + "return_type" : "_ZTIN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, { "access" : "private", + "function_name" : "android::String8::find_extension", + "linker_set_key" : "_ZNK7android7String814find_extensionEv", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + } + ], + "return_type" : "_ZTIPc", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, + { "function_name" : "android::String8::getPathExtension", "linker_set_key" : "_ZNK7android7String816getPathExtensionEv", "parameters" : @@ -9133,6 +9202,23 @@ "return_type" : "_ZTIm", "source_file" : "system/core/libutils/include/utils/String8.h" }, + { + "function_name" : "android::String8::walkPath", + "linker_set_key" : "_ZNK7android7String88walkPathEPS0_", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + }, + { + "default_arg" : true, + "referenced_type" : "_ZTIPN7android7String8E" + } + ], + "return_type" : "_ZTIN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, { "function_name" : "android::String16::startsWith", "linker_set_key" : "_ZNK7android8String1610startsWithEPKDs", diff --git a/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump b/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump index e8236ea5b6af..219c76665bb9 100644 --- a/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump +++ b/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump @@ -703,6 +703,9 @@ { "name" : "_ZN7android7RefBaseD2Ev" }, + { + "name" : "_ZN7android7String810appendPathEPKc" + }, { "name" : "_ZN7android7String810lockBufferEj" }, @@ -1141,6 +1144,15 @@ { "name" : "_ZNK7android7String810getPathDirEv" }, + { + "name" : "_ZNK7android7String811getBasePathEv" + }, + { + "name" : "_ZNK7android7String811getPathLeafEv" + }, + { + "name" : "_ZNK7android7String814find_extensionEv" + }, { "name" : "_ZNK7android7String816getPathExtensionEv" }, @@ -1150,6 +1162,9 @@ { "name" : "_ZNK7android7String86lengthEv" }, + { + "name" : "_ZNK7android7String88walkPathEPS0_" + }, { "name" : "_ZNK7android8String1610startsWithEPKDs" }, @@ -6789,6 +6804,22 @@ "return_type" : "_ZTIv", "source_file" : "system/core/libutils/include/utils/RefBase.h" }, + { + "function_name" : "android::String8::appendPath", + "linker_set_key" : "_ZN7android7String810appendPathEPKc", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPN7android7String8E" + }, + { + "referenced_type" : "_ZTIPKc" + } + ], + "return_type" : "_ZTIRN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, { "function_name" : "android::String8::lockBuffer", "linker_set_key" : "_ZN7android7String810lockBufferEj", @@ -9069,7 +9100,6 @@ "source_file" : "system/core/libutils/include/utils/RefBase.h" }, { - "access" : "private", "function_name" : "android::String8::getPathDir", "linker_set_key" : "_ZNK7android7String810getPathDirEv", "parameters" : @@ -9082,8 +9112,47 @@ "return_type" : "_ZTIN7android7String8E", "source_file" : "system/core/libutils/include/utils/String8.h" }, + { + "function_name" : "android::String8::getBasePath", + "linker_set_key" : "_ZNK7android7String811getBasePathEv", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + } + ], + "return_type" : "_ZTIN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, + { + "function_name" : "android::String8::getPathLeaf", + "linker_set_key" : "_ZNK7android7String811getPathLeafEv", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + } + ], + "return_type" : "_ZTIN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, { "access" : "private", + "function_name" : "android::String8::find_extension", + "linker_set_key" : "_ZNK7android7String814find_extensionEv", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + } + ], + "return_type" : "_ZTIPc", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, + { "function_name" : "android::String8::getPathExtension", "linker_set_key" : "_ZNK7android7String816getPathExtensionEv", "parameters" : @@ -9129,6 +9198,23 @@ "return_type" : "_ZTIj", "source_file" : "system/core/libutils/include/utils/String8.h" }, + { + "function_name" : "android::String8::walkPath", + "linker_set_key" : "_ZNK7android7String88walkPathEPS0_", + "parameters" : + [ + { + "is_this_ptr" : true, + "referenced_type" : "_ZTIPKN7android7String8E" + }, + { + "default_arg" : true, + "referenced_type" : "_ZTIPN7android7String8E" + } + ], + "return_type" : "_ZTIN7android7String8E", + "source_file" : "system/core/libutils/include/utils/String8.h" + }, { "function_name" : "android::String16::startsWith", "linker_set_key" : "_ZNK7android8String1610startsWithEPKDs", diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h index fbb0a0ae32ae..ea25c6aa3947 100644 --- a/libutils/include/utils/String8.h +++ b/libutils/include/utils/String8.h @@ -130,11 +130,80 @@ class String8 void toLower(); -private: - String8 getPathDir(void) const; - String8 getPathExtension(void) const; + /* + * These methods operate on the string as if it were a path name. + */ + + /* + * Get just the filename component. + * + * "/tmp/foo/bar.c" --> "bar.c" + */ + String8 getPathLeaf(void) const; + + /* + * Remove the last (file name) component, leaving just the directory + * name. + * + * "/tmp/foo/bar.c" --> "/tmp/foo" + * "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX + * "bar.c" --> "" + */ + String8 getPathDir(void) const; + + /* + * Retrieve the front (root dir) component. Optionally also return the + * remaining components. + * + * "/tmp/foo/bar.c" --> "tmp" (remain = "foo/bar.c") + * "/tmp" --> "tmp" (remain = "") + * "bar.c" --> "bar.c" (remain = "") + */ + String8 walkPath(String8* outRemains = nullptr) const; + + /* + * Return the filename extension. This is the last '.' and any number + * of characters that follow it. The '.' is included in case we + * decide to expand our definition of what constitutes an extension. + * + * "/tmp/foo/bar.c" --> ".c" + * "/tmp" --> "" + * "/tmp/foo.bar/baz" --> "" + * "foo.jpeg" --> ".jpeg" + * "foo." --> "" + */ + String8 getPathExtension(void) const; + + /* + * Return the path without the extension. Rules for what constitutes + * an extension are described in the comment for getPathExtension(). + * + * "/tmp/foo/bar.c" --> "/tmp/foo/bar" + */ + String8 getBasePath(void) const; + + /* + * Add a component to the pathname. We guarantee that there is + * exactly one path separator between the old path and the new. + * If there is no existing name, we just copy the new name in. + * + * If leaf is a fully qualified path (i.e. starts with '/', it + * replaces whatever was there before. + */ + String8& appendPath(const char* leaf); + String8& appendPath(const String8& leaf) { return appendPath(leaf.c_str()); } + + /* + * Like appendPath(), but does not affect this string. Returns a new one instead. + */ + String8 appendPathCopy(const char* leaf) const + { String8 p(*this); p.appendPath(leaf); return p; } + String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.c_str()); } + +private: status_t real_append(const char* other, size_t numChars); + char* find_extension(void) const; const char* mString; }; From a1853516ff0dc78b677eeafa792cdfa9e5d9a2ee Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Mon, 11 Sep 2023 17:45:16 +0000 Subject: [PATCH 0374/1487] Revert "Revert "Revert "Revert "Drop all path-related methods from android::String8"""" This reverts commit 141255f30c35372bba80bfff9ac164f34e38784b. Reason for revert: Attempt re-submit again Change-Id: I0e568fdf8f7a141ee3c5d54f68530ff478a47439 --- libutils/String8.cpp | 108 +----------------- libutils/String8_fuzz.cpp | 24 ---- .../arm64/source-based/libutils.so.lsdump | 88 +------------- .../arm_arm64/source-based/libutils.so.lsdump | 88 +------------- libutils/include/utils/String8.h | 75 +----------- 5 files changed, 8 insertions(+), 375 deletions(-) diff --git a/libutils/String8.cpp b/libutils/String8.cpp index 2b72847e52bd..4301f0ea3a77 100644 --- a/libutils/String8.cpp +++ b/libutils/String8.cpp @@ -430,31 +430,6 @@ void String8::toLower() // --------------------------------------------------------------------------- // Path functions -static void setPathName(String8& s, const char* name) { - size_t len = strlen(name); - char* buf = s.lockBuffer(len); - - memcpy(buf, name, len); - - // remove trailing path separator, if present - if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--; - buf[len] = '\0'; - - s.unlockBuffer(len); -} - -String8 String8::getPathLeaf(void) const -{ - const char* cp; - const char*const buf = mString; - - cp = strrchr(buf, OS_PATH_SEPARATOR); - if (cp == nullptr) - return String8(*this); - else - return String8(cp+1); -} - String8 String8::getPathDir(void) const { const char* cp; @@ -467,40 +442,14 @@ String8 String8::getPathDir(void) const return String8(str, cp - str); } -String8 String8::walkPath(String8* outRemains) const -{ - const char* cp; - const char*const str = mString; - const char* buf = str; - - cp = strchr(buf, OS_PATH_SEPARATOR); - if (cp == buf) { - // don't include a leading '/'. - buf = buf+1; - cp = strchr(buf, OS_PATH_SEPARATOR); - } - - if (cp == nullptr) { - String8 res = buf != str ? String8(buf) : *this; - if (outRemains) *outRemains = String8(""); - return res; - } - - String8 res(buf, cp-buf); - if (outRemains) *outRemains = String8(cp+1); - return res; -} - /* * Helper function for finding the start of an extension in a pathname. * * Returns a pointer inside mString, or NULL if no extension was found. */ -char* String8::find_extension(void) const -{ +static const char* find_extension(const char* str) { const char* lastSlash; const char* lastDot; - const char* const str = mString; // only look at the filename lastSlash = strrchr(str, OS_PATH_SEPARATOR); @@ -515,67 +464,16 @@ char* String8::find_extension(void) const return nullptr; // looks good, ship it - return const_cast(lastDot); + return lastDot; } String8 String8::getPathExtension(void) const { - char* ext; - - ext = find_extension(); + auto ext = find_extension(mString); if (ext != nullptr) return String8(ext); else return String8(""); } -String8 String8::getBasePath(void) const -{ - char* ext; - const char* const str = mString; - - ext = find_extension(); - if (ext == nullptr) - return String8(*this); - else - return String8(str, ext - str); -} - -String8& String8::appendPath(const char* name) -{ - // TODO: The test below will fail for Win32 paths. Fix later or ignore. - if (name[0] != OS_PATH_SEPARATOR) { - if (*name == '\0') { - // nothing to do - return *this; - } - - size_t len = length(); - if (len == 0) { - // no existing filename, just use the new one - setPathName(*this, name); - return *this; - } - - // make room for oldPath + '/' + newPath - int newlen = strlen(name); - - char* buf = lockBuffer(len+1+newlen); - - // insert a '/' if needed - if (buf[len-1] != OS_PATH_SEPARATOR) - buf[len++] = OS_PATH_SEPARATOR; - - memcpy(buf+len, name, newlen+1); - len += newlen; - - unlockBuffer(len); - - return *this; - } else { - setPathName(*this, name); - return *this; - } -} - }; // namespace android diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp index 6f7a54f9f310..cbce0505891e 100644 --- a/libutils/String8_fuzz.cpp +++ b/libutils/String8_fuzz.cpp @@ -68,30 +68,6 @@ std::vectorConsumeIntegralInRange(0, str1->size()); str1->find(str2->c_str(), start_index); }, - - // Path handling - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - str1->getBasePath(); - }, - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - str1->getPathExtension(); - }, - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - str1->getPathLeaf(); - }, - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - str1->getPathDir(); - }, - [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void { - std::shared_ptr path_out_str = - std::make_shared(); - str1->walkPath(path_out_str.get()); - path_out_str->clear(); - }, - [](FuzzedDataProvider* dataProvider, android::String8* str1, - android::String8*) -> void { - str1->appendPath(dataProvider->ConsumeBytesWithTerminator(5).data()); - }, }; void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend) { diff --git a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump index 46baddecde7b..8881b44eb181 100644 --- a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump +++ b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump @@ -703,9 +703,6 @@ { "name" : "_ZN7android7RefBaseD2Ev" }, - { - "name" : "_ZN7android7String810appendPathEPKc" - }, { "name" : "_ZN7android7String810lockBufferEm" }, @@ -1144,15 +1141,6 @@ { "name" : "_ZNK7android7String810getPathDirEv" }, - { - "name" : "_ZNK7android7String811getBasePathEv" - }, - { - "name" : "_ZNK7android7String811getPathLeafEv" - }, - { - "name" : "_ZNK7android7String814find_extensionEv" - }, { "name" : "_ZNK7android7String816getPathExtensionEv" }, @@ -1162,9 +1150,6 @@ { "name" : "_ZNK7android7String86lengthEv" }, - { - "name" : "_ZNK7android7String88walkPathEPS0_" - }, { "name" : "_ZNK7android8String1610startsWithEPKDs" }, @@ -6808,22 +6793,6 @@ "return_type" : "_ZTIv", "source_file" : "system/core/libutils/include/utils/RefBase.h" }, - { - "function_name" : "android::String8::appendPath", - "linker_set_key" : "_ZN7android7String810appendPathEPKc", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPN7android7String8E" - }, - { - "referenced_type" : "_ZTIPKc" - } - ], - "return_type" : "_ZTIRN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String8::lockBuffer", "linker_set_key" : "_ZN7android7String810lockBufferEm", @@ -9104,6 +9073,7 @@ "source_file" : "system/core/libutils/include/utils/RefBase.h" }, { + "access" : "private", "function_name" : "android::String8::getPathDir", "linker_set_key" : "_ZNK7android7String810getPathDirEv", "parameters" : @@ -9116,47 +9086,8 @@ "return_type" : "_ZTIN7android7String8E", "source_file" : "system/core/libutils/include/utils/String8.h" }, - { - "function_name" : "android::String8::getBasePath", - "linker_set_key" : "_ZNK7android7String811getBasePathEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, - { - "function_name" : "android::String8::getPathLeaf", - "linker_set_key" : "_ZNK7android7String811getPathLeafEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "access" : "private", - "function_name" : "android::String8::find_extension", - "linker_set_key" : "_ZNK7android7String814find_extensionEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIPc", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, - { "function_name" : "android::String8::getPathExtension", "linker_set_key" : "_ZNK7android7String816getPathExtensionEv", "parameters" : @@ -9202,23 +9133,6 @@ "return_type" : "_ZTIm", "source_file" : "system/core/libutils/include/utils/String8.h" }, - { - "function_name" : "android::String8::walkPath", - "linker_set_key" : "_ZNK7android7String88walkPathEPS0_", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - }, - { - "default_arg" : true, - "referenced_type" : "_ZTIPN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String16::startsWith", "linker_set_key" : "_ZNK7android8String1610startsWithEPKDs", diff --git a/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump b/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump index 219c76665bb9..e8236ea5b6af 100644 --- a/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump +++ b/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump @@ -703,9 +703,6 @@ { "name" : "_ZN7android7RefBaseD2Ev" }, - { - "name" : "_ZN7android7String810appendPathEPKc" - }, { "name" : "_ZN7android7String810lockBufferEj" }, @@ -1144,15 +1141,6 @@ { "name" : "_ZNK7android7String810getPathDirEv" }, - { - "name" : "_ZNK7android7String811getBasePathEv" - }, - { - "name" : "_ZNK7android7String811getPathLeafEv" - }, - { - "name" : "_ZNK7android7String814find_extensionEv" - }, { "name" : "_ZNK7android7String816getPathExtensionEv" }, @@ -1162,9 +1150,6 @@ { "name" : "_ZNK7android7String86lengthEv" }, - { - "name" : "_ZNK7android7String88walkPathEPS0_" - }, { "name" : "_ZNK7android8String1610startsWithEPKDs" }, @@ -6804,22 +6789,6 @@ "return_type" : "_ZTIv", "source_file" : "system/core/libutils/include/utils/RefBase.h" }, - { - "function_name" : "android::String8::appendPath", - "linker_set_key" : "_ZN7android7String810appendPathEPKc", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPN7android7String8E" - }, - { - "referenced_type" : "_ZTIPKc" - } - ], - "return_type" : "_ZTIRN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String8::lockBuffer", "linker_set_key" : "_ZN7android7String810lockBufferEj", @@ -9100,6 +9069,7 @@ "source_file" : "system/core/libutils/include/utils/RefBase.h" }, { + "access" : "private", "function_name" : "android::String8::getPathDir", "linker_set_key" : "_ZNK7android7String810getPathDirEv", "parameters" : @@ -9112,47 +9082,8 @@ "return_type" : "_ZTIN7android7String8E", "source_file" : "system/core/libutils/include/utils/String8.h" }, - { - "function_name" : "android::String8::getBasePath", - "linker_set_key" : "_ZNK7android7String811getBasePathEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, - { - "function_name" : "android::String8::getPathLeaf", - "linker_set_key" : "_ZNK7android7String811getPathLeafEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "access" : "private", - "function_name" : "android::String8::find_extension", - "linker_set_key" : "_ZNK7android7String814find_extensionEv", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - } - ], - "return_type" : "_ZTIPc", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, - { "function_name" : "android::String8::getPathExtension", "linker_set_key" : "_ZNK7android7String816getPathExtensionEv", "parameters" : @@ -9198,23 +9129,6 @@ "return_type" : "_ZTIj", "source_file" : "system/core/libutils/include/utils/String8.h" }, - { - "function_name" : "android::String8::walkPath", - "linker_set_key" : "_ZNK7android7String88walkPathEPS0_", - "parameters" : - [ - { - "is_this_ptr" : true, - "referenced_type" : "_ZTIPKN7android7String8E" - }, - { - "default_arg" : true, - "referenced_type" : "_ZTIPN7android7String8E" - } - ], - "return_type" : "_ZTIN7android7String8E", - "source_file" : "system/core/libutils/include/utils/String8.h" - }, { "function_name" : "android::String16::startsWith", "linker_set_key" : "_ZNK7android8String1610startsWithEPKDs", diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h index ea25c6aa3947..fbb0a0ae32ae 100644 --- a/libutils/include/utils/String8.h +++ b/libutils/include/utils/String8.h @@ -130,80 +130,11 @@ class String8 void toLower(); - - /* - * These methods operate on the string as if it were a path name. - */ - - /* - * Get just the filename component. - * - * "/tmp/foo/bar.c" --> "bar.c" - */ - String8 getPathLeaf(void) const; - - /* - * Remove the last (file name) component, leaving just the directory - * name. - * - * "/tmp/foo/bar.c" --> "/tmp/foo" - * "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX - * "bar.c" --> "" - */ - String8 getPathDir(void) const; - - /* - * Retrieve the front (root dir) component. Optionally also return the - * remaining components. - * - * "/tmp/foo/bar.c" --> "tmp" (remain = "foo/bar.c") - * "/tmp" --> "tmp" (remain = "") - * "bar.c" --> "bar.c" (remain = "") - */ - String8 walkPath(String8* outRemains = nullptr) const; - - /* - * Return the filename extension. This is the last '.' and any number - * of characters that follow it. The '.' is included in case we - * decide to expand our definition of what constitutes an extension. - * - * "/tmp/foo/bar.c" --> ".c" - * "/tmp" --> "" - * "/tmp/foo.bar/baz" --> "" - * "foo.jpeg" --> ".jpeg" - * "foo." --> "" - */ - String8 getPathExtension(void) const; - - /* - * Return the path without the extension. Rules for what constitutes - * an extension are described in the comment for getPathExtension(). - * - * "/tmp/foo/bar.c" --> "/tmp/foo/bar" - */ - String8 getBasePath(void) const; - - /* - * Add a component to the pathname. We guarantee that there is - * exactly one path separator between the old path and the new. - * If there is no existing name, we just copy the new name in. - * - * If leaf is a fully qualified path (i.e. starts with '/', it - * replaces whatever was there before. - */ - String8& appendPath(const char* leaf); - String8& appendPath(const String8& leaf) { return appendPath(leaf.c_str()); } - - /* - * Like appendPath(), but does not affect this string. Returns a new one instead. - */ - String8 appendPathCopy(const char* leaf) const - { String8 p(*this); p.appendPath(leaf); return p; } - String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.c_str()); } - private: + String8 getPathDir(void) const; + String8 getPathExtension(void) const; + status_t real_append(const char* other, size_t numChars); - char* find_extension(void) const; const char* mString; }; From 244e581a31da30508648b1a118f864dae491935f Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Tue, 12 Sep 2023 15:53:19 +0800 Subject: [PATCH 0375/1487] fs_mgr: Use /proc/mounts to check if /cache is mounted The fstab provided by the user/caller might not be the default fstab, which might not include the /cache mount entry. We should just use the procfs mount info to determine if /cache is currently mounted. Bug: 300036012 Test: adb_remount test Change-Id: I4643d0a21ae21f3513f715de424f0be1fe64ff9e --- fs_mgr/fs_mgr_overlayfs_control.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs_mgr/fs_mgr_overlayfs_control.cpp b/fs_mgr/fs_mgr_overlayfs_control.cpp index 68576f22086d..2cc0d2d5ea9c 100644 --- a/fs_mgr/fs_mgr_overlayfs_control.cpp +++ b/fs_mgr/fs_mgr_overlayfs_control.cpp @@ -688,7 +688,7 @@ bool fs_mgr_overlayfs_setup(const Fstab& fstab, const char* mount_point, bool* w continue; } } else { - if (GetEntryForMountPoint(&fstab, overlay_mount_point) == nullptr) { + if (!fs_mgr_overlayfs_already_mounted(overlay_mount_point, false /* overlay */)) { continue; } } From 37467f36658aa8ef82eef3e4674099ad6b140940 Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Tue, 12 Sep 2023 15:31:24 +0800 Subject: [PATCH 0376/1487] fs_mgr: Refactor fs_mgr_overlayfs_already_mounted() to be more readable Bug: 293695109 Test: adb_remount test Change-Id: Idadd5b99e48fa601b1046aef533027ea6ba5c2f6 --- fs_mgr/fs_mgr_overlayfs_mount.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/fs_mgr/fs_mgr_overlayfs_mount.cpp b/fs_mgr/fs_mgr_overlayfs_mount.cpp index 8fb63b17435a..9f17c06f7a8f 100644 --- a/fs_mgr/fs_mgr_overlayfs_mount.cpp +++ b/fs_mgr/fs_mgr_overlayfs_mount.cpp @@ -733,15 +733,18 @@ bool fs_mgr_overlayfs_is_setup() { bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only) { Fstab fstab; - if (!ReadFstabFromFile("/proc/mounts", &fstab)) { + if (!ReadFstabFromProcMounts(&fstab)) { return false; } const auto lowerdir = kLowerdirOption + mount_point; - for (const auto& entry : fstab) { - if (overlay_only && "overlay" != entry.fs_type && "overlayfs" != entry.fs_type) continue; - if (mount_point != entry.mount_point) continue; - if (!overlay_only) return true; - const auto options = android::base::Split(entry.fs_options, ","); + for (const auto& entry : GetEntriesForMountPoint(&fstab, mount_point)) { + if (!overlay_only) { + return true; + } + if (entry->fs_type != "overlay" && entry->fs_type != "overlayfs") { + continue; + } + const auto options = android::base::Split(entry->fs_options, ","); for (const auto& opt : options) { if (opt == lowerdir) { return true; From 86c9ea8f861ec80399305f6f5aff422e45e0ac70 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Tue, 12 Sep 2023 16:23:13 +0000 Subject: [PATCH 0377/1487] Implement android::String access methods that avoid C string cast Bug: 295394788 Test: m checkbuild Change-Id: If25fd69319171e8c549fc8fcfd95a0819291d8e6 --- libutils/include/utils/String16.h | 24 +++++++++++++++++ libutils/include/utils/String8.h | 43 ++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h index b48b90765612..fb94174da667 100644 --- a/libutils/include/utils/String16.h +++ b/libutils/include/utils/String16.h @@ -24,6 +24,11 @@ #include #include +#if __has_include() +#include +#define HAS_STRING_VIEW +#endif + // --------------------------------------------------------------------------- namespace android { @@ -91,6 +96,7 @@ class String16 bool startsWith(const char16_t* prefix) const; bool contains(const char16_t* chrs) const; + inline bool contains(const String16& other) const; status_t replaceAll(char16_t replaceThis, char16_t withThis); @@ -113,6 +119,12 @@ class String16 inline operator const char16_t*() const; +#ifdef HAS_STRING_VIEW + // Implicit cast to std::u16string is not implemented on purpose - u16string_view is much + // lighter and if one needs, they can still create u16string from u16string_view. + inline operator std::u16string_view() const; +#endif + // Static and non-static String16 behave the same for the users, so // this method isn't of much use for the users. It is public for testing. bool isStaticString() const; @@ -264,6 +276,11 @@ inline size_t String16::length() const return size(); } +inline bool String16::contains(const String16& other) const +{ + return contains(other.c_str()); +} + inline String16& String16::operator=(const String16& other) { setTo(other); @@ -353,8 +370,15 @@ inline String16::operator const char16_t*() const return mString; } +inline String16::operator std::u16string_view() const +{ + return {mString, length()}; +} + } // namespace android // --------------------------------------------------------------------------- +#undef HAS_STRING_VIEW + #endif // ANDROID_STRING16_H diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h index ea25c6aa3947..38930186575a 100644 --- a/libutils/include/utils/String8.h +++ b/libutils/include/utils/String8.h @@ -18,7 +18,6 @@ #define ANDROID_STRING8_H #include -#include #include #include @@ -27,6 +26,16 @@ #include // for strcmp #include +#if __has_include() +#include +#define HAS_STRING +#endif + +#if __has_include() +#include +#define HAS_STRING_VIEW +#endif + // --------------------------------------------------------------------------- namespace android { @@ -113,6 +122,10 @@ class String8 inline operator const char*() const; +#ifdef HAS_STRING_VIEW + inline explicit operator std::string_view() const; +#endif + char* lockBuffer(size_t size); void unlockBuffer(); status_t unlockBuffer(size_t size); @@ -120,13 +133,16 @@ class String8 // return the index of the first byte of other in this at or after // start, or -1 if not found ssize_t find(const char* other, size_t start = 0) const; + inline ssize_t find(const String8& other, size_t start = 0) const; // return true if this string contains the specified substring inline bool contains(const char* other) const; + inline bool contains(const String8& other) const; // removes all occurrence of the specified substring // returns true if any were found and removed bool removeAll(const char* other); + inline bool removeAll(const String8& other); void toLower(); @@ -264,11 +280,26 @@ inline size_t String8::bytes() const return length(); } +inline ssize_t String8::find(const String8& other, size_t start) const +{ + return find(other.c_str(), start); +} + inline bool String8::contains(const char* other) const { return find(other) >= 0; } +inline bool String8::contains(const String8& other) const +{ + return contains(other.c_str()); +} + +inline bool String8::removeAll(const String8& other) +{ + return removeAll(other.c_str()); +} + inline String8& String8::operator=(const String8& other) { setTo(other); @@ -377,8 +408,18 @@ inline String8::operator const char*() const return mString; } +#ifdef HAS_STRING_VIEW +inline String8::operator std::string_view() const +{ + return {mString, length()}; +} +#endif + } // namespace android // --------------------------------------------------------------------------- +#undef HAS_STRING +#undef HAS_STRING_VIEW + #endif // ANDROID_STRING8_H From f58b009b7b31aca813092f104c84e91e7a8662b7 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Tue, 12 Sep 2023 13:01:10 -0700 Subject: [PATCH 0378/1487] Disable warning which is not detecting problems. A clang update enabled -Wreorder-init-list by default. Since it doesn't provide any benefit to the debuggerd code, disable the warning. Test: Builds without warnings. Change-Id: I75cfe064ba92c74312ba33f329b1364258eba06c --- debuggerd/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index 5393e25e5098..267571b50175 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -12,6 +12,7 @@ cc_defaults { "-Wno-unused-argument", "-Wno-unused-function", "-Wno-nullability-completeness", + "-Wno-reorder-init-list", "-Os", "-fno-finite-loops", "-DANDROID_DEBUGGABLE=0", From b309292859edc1ec9b4df298e6e236067b2b6ed8 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 12 Sep 2023 13:34:07 -0700 Subject: [PATCH 0379/1487] Adding block sz to compressors Adding block sz to compressor classes to prepare for variable block size compression Test: m libsnapshot Change-Id: I84db20c80c0f95188f79ccc73b5c30678bd75e78 --- .../include/libsnapshot/cow_compress.h | 12 ++--- .../libsnapshot_cow/cow_compress.cpp | 45 +++++++++++-------- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h index cf6561559574..fd12b84fe7b1 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h @@ -24,24 +24,26 @@ namespace snapshot { class ICompressor { public: - explicit ICompressor(uint32_t compression_level) : compression_level_(compression_level) {} + explicit ICompressor(uint32_t compression_level, uint32_t block_size) + : compression_level_(compression_level), block_size_(block_size) {} virtual ~ICompressor() {} // Factory methods for compression methods. - static std::unique_ptr Gz(uint32_t compression_level); - static std::unique_ptr Brotli(uint32_t compression_level); - static std::unique_ptr Lz4(uint32_t compression_level); + static std::unique_ptr Gz(uint32_t compression_level, const int32_t BLOCK_SZ); + static std::unique_ptr Brotli(uint32_t compression_level, const int32_t BLOCK_SZ); + static std::unique_ptr Lz4(uint32_t compression_level, const int32_t BLOCK_SZ); static std::unique_ptr Zstd(uint32_t compression_level, const int32_t BLOCK_SZ); static std::unique_ptr Create(CowCompression compression, const int32_t BLOCK_SZ); uint32_t GetCompressionLevel() const { return compression_level_; } - + uint32_t GetBlockSize() const { return block_size_; } [[nodiscard]] virtual std::basic_string Compress(const void* data, size_t length) const = 0; private: uint32_t compression_level_; + uint32_t block_size_; }; } // namespace snapshot } // namespace android \ No newline at end of file diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp index 71ac59f20d20..abc7d336f40c 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp @@ -56,16 +56,16 @@ std::optional CompressionAlgorithmFromString(std::strin } std::unique_ptr ICompressor::Create(CowCompression compression, - const int32_t BLOCK_SZ) { + const int32_t block_size) { switch (compression.algorithm) { case kCowCompressLz4: - return ICompressor::Lz4(compression.compression_level); + return ICompressor::Lz4(compression.compression_level, block_size); case kCowCompressBrotli: - return ICompressor::Brotli(compression.compression_level); + return ICompressor::Brotli(compression.compression_level, block_size); case kCowCompressGz: - return ICompressor::Gz(compression.compression_level); + return ICompressor::Gz(compression.compression_level, block_size); case kCowCompressZstd: - return ICompressor::Zstd(compression.compression_level, BLOCK_SZ); + return ICompressor::Zstd(compression.compression_level, block_size); case kCowCompressNone: return nullptr; } @@ -100,7 +100,8 @@ uint32_t CompressWorker::GetDefaultCompressionLevel(CowCompressionAlgorithm comp class GzCompressor final : public ICompressor { public: - GzCompressor(uint32_t compression_level) : ICompressor(compression_level){}; + GzCompressor(uint32_t compression_level, const uint32_t block_size) + : ICompressor(compression_level, block_size){}; std::basic_string Compress(const void* data, size_t length) const override { const auto bound = compressBound(length); @@ -120,7 +121,8 @@ class GzCompressor final : public ICompressor { class Lz4Compressor final : public ICompressor { public: - Lz4Compressor(uint32_t compression_level) : ICompressor(compression_level){}; + Lz4Compressor(uint32_t compression_level, const uint32_t block_size) + : ICompressor(compression_level, block_size){}; std::basic_string Compress(const void* data, size_t length) const override { const auto bound = LZ4_compressBound(length); @@ -151,7 +153,8 @@ class Lz4Compressor final : public ICompressor { class BrotliCompressor final : public ICompressor { public: - BrotliCompressor(uint32_t compression_level) : ICompressor(compression_level){}; + BrotliCompressor(uint32_t compression_level, const uint32_t block_size) + : ICompressor(compression_level, block_size){}; std::basic_string Compress(const void* data, size_t length) const override { const auto bound = BrotliEncoderMaxCompressedSize(length); @@ -176,10 +179,11 @@ class BrotliCompressor final : public ICompressor { class ZstdCompressor final : public ICompressor { public: - ZstdCompressor(uint32_t compression_level, const uint32_t MAX_BLOCK_SIZE) - : ICompressor(compression_level), zstd_context_(ZSTD_createCCtx(), ZSTD_freeCCtx) { + ZstdCompressor(uint32_t compression_level, const uint32_t block_size) + : ICompressor(compression_level, block_size), + zstd_context_(ZSTD_createCCtx(), ZSTD_freeCCtx) { ZSTD_CCtx_setParameter(zstd_context_.get(), ZSTD_c_compressionLevel, compression_level); - ZSTD_CCtx_setParameter(zstd_context_.get(), ZSTD_c_windowLog, log2(MAX_BLOCK_SIZE)); + ZSTD_CCtx_setParameter(zstd_context_.get(), ZSTD_c_windowLog, log2(GetBlockSize())); }; std::basic_string Compress(const void* data, size_t length) const override { @@ -313,20 +317,23 @@ bool CompressWorker::GetCompressedBuffers(std::vector return true; } -std::unique_ptr ICompressor::Brotli(uint32_t compression_level) { - return std::make_unique(compression_level); +std::unique_ptr ICompressor::Brotli(uint32_t compression_level, + const int32_t block_size) { + return std::make_unique(compression_level, block_size); } -std::unique_ptr ICompressor::Gz(uint32_t compression_level) { - return std::make_unique(compression_level); +std::unique_ptr ICompressor::Gz(uint32_t compression_level, const int32_t block_size) { + return std::make_unique(compression_level, block_size); } -std::unique_ptr ICompressor::Lz4(uint32_t compression_level) { - return std::make_unique(compression_level); +std::unique_ptr ICompressor::Lz4(uint32_t compression_level, + const int32_t block_size) { + return std::make_unique(compression_level, block_size); } -std::unique_ptr ICompressor::Zstd(uint32_t compression_level, const int32_t BLOCK_SZ) { - return std::make_unique(compression_level, BLOCK_SZ); +std::unique_ptr ICompressor::Zstd(uint32_t compression_level, + const int32_t block_size) { + return std::make_unique(compression_level, block_size); } void CompressWorker::Finalize() { From 19a6aa624174f5c21a2e57773c7e1faa5979117c Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Wed, 13 Sep 2023 14:28:54 -0700 Subject: [PATCH 0380/1487] Concatenate conditional Move two separate conditional checks to one in writer_v2 Test: m libsnapshot Change-Id: Id70db313754b770e3fa091e9c127839b9f2a5138 --- fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp index ee445a2d0c16..699529b013f4 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp @@ -636,10 +636,8 @@ bool CowWriterV2::FlushCluster() { } bool CowWriterV2::WriteOperation(const CowOperation& op, const void* data, size_t size) { - if (!EnsureSpaceAvailable(next_op_pos_ + sizeof(op))) { - return false; - } - if (!EnsureSpaceAvailable(next_data_pos_ + size)) { + if (!EnsureSpaceAvailable(next_op_pos_ + sizeof(op)) || + !EnsureSpaceAvailable(next_data_pos_ + size)) { return false; } From 8b5c8477f915e8680257657042e64181104b9bda Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Mon, 14 Aug 2023 18:20:02 +0000 Subject: [PATCH 0381/1487] Lock down String8.isEmpty() usage All users should migrate to .empty() Bug: 295394788 Test: make checkbuild Change-Id: I5ec7921b9cf70e6b0857e1087f141dce958d2587 --- libutils/include/utils/String8.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h index ea25c6aa3947..c79876296034 100644 --- a/libutils/include/utils/String8.h +++ b/libutils/include/utils/String8.h @@ -65,7 +65,6 @@ class String8 inline size_t size() const; inline size_t bytes() const; inline bool empty() const; - inline bool isEmpty() const; size_t length() const; @@ -206,6 +205,14 @@ class String8 char* find_extension(void) const; const char* mString; + +// These symbols are for potential backward compatibility with prebuilts. To be removed. +#ifdef ENABLE_STRING8_OBSOLETE_METHODS +public: +#else +private: +#endif + inline bool isEmpty() const; }; // String8 can be trivially moved using memcpy() because moving does not From 8b95a1248945b8ed565d44dda2500fc5a1a0f6fb Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 11 Aug 2023 18:43:23 +0000 Subject: [PATCH 0382/1487] Lock down String8|16.string() usage All users should migrate to .c_str() Bug: 295394788 Test: make checkbuild Change-Id: Ic6295848cf3377e0bf5334448d5ed7ea53fae7ae --- libutils/include/utils/String16.h | 9 ++++++++- libutils/include/utils/String8.h | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h index 1fa3723b79ef..44a4fd7859ea 100644 --- a/libutils/include/utils/String16.h +++ b/libutils/include/utils/String16.h @@ -59,7 +59,6 @@ class String16 ~String16(); inline const char16_t* c_str() const; - inline const char16_t* string() const; size_t size() const; inline bool empty() const; @@ -188,6 +187,14 @@ class String16 template explicit constexpr String16(const StaticData& s) : mString(s.data) {} + +// These symbols are for potential backward compatibility with prebuilts. To be removed. +#ifdef ENABLE_STRING8_OBSOLETE_METHODS +public: +#else +private: +#endif + inline const char16_t* string() const; }; // String16 can be trivially moved using memcpy() because moving does not diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h index 0b92f5b10ccf..6d250723b628 100644 --- a/libutils/include/utils/String8.h +++ b/libutils/include/utils/String8.h @@ -65,7 +65,6 @@ class String8 static String8 formatV(const char* fmt, va_list args); inline const char* c_str() const; - inline const char* string() const; inline size_t size() const; inline size_t bytes() const; @@ -155,6 +154,7 @@ class String8 #else private: #endif + inline const char* string() const; inline bool isEmpty() const; }; From 7210b285c2a7c8220789e039c9b2a72a931224cc Mon Sep 17 00:00:00 2001 From: Devika Krishnadas Date: Fri, 15 Sep 2023 18:46:03 +0000 Subject: [PATCH 0383/1487] Revert "Lock down String8|16.string() usage" This reverts commit 8b95a1248945b8ed565d44dda2500fc5a1a0f6fb. Reason for revert: DroidMonitor: Test failure Change-Id: I09230ea7c3b80e1b4d277d3c6c6355a38f7bbc92 --- libutils/include/utils/String16.h | 9 +-------- libutils/include/utils/String8.h | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h index 44a4fd7859ea..1fa3723b79ef 100644 --- a/libutils/include/utils/String16.h +++ b/libutils/include/utils/String16.h @@ -59,6 +59,7 @@ class String16 ~String16(); inline const char16_t* c_str() const; + inline const char16_t* string() const; size_t size() const; inline bool empty() const; @@ -187,14 +188,6 @@ class String16 template explicit constexpr String16(const StaticData& s) : mString(s.data) {} - -// These symbols are for potential backward compatibility with prebuilts. To be removed. -#ifdef ENABLE_STRING8_OBSOLETE_METHODS -public: -#else -private: -#endif - inline const char16_t* string() const; }; // String16 can be trivially moved using memcpy() because moving does not diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h index 6d250723b628..0b92f5b10ccf 100644 --- a/libutils/include/utils/String8.h +++ b/libutils/include/utils/String8.h @@ -65,6 +65,7 @@ class String8 static String8 formatV(const char* fmt, va_list args); inline const char* c_str() const; + inline const char* string() const; inline size_t size() const; inline size_t bytes() const; @@ -154,7 +155,6 @@ class String8 #else private: #endif - inline const char* string() const; inline bool isEmpty() const; }; From 61a2897733e15a12b7aa2dfd99957e83cbe59351 Mon Sep 17 00:00:00 2001 From: Keith Mok Date: Thu, 31 Aug 2023 00:31:35 +0000 Subject: [PATCH 0384/1487] Add seal if ashmem-dev is backed by memfd Need to seal the buffer size in align with ashmem if set to PROT_READ only to prevent untrusted remote process to shrink the buffer size and crash it. Bug: 294609150 Test: build Ignore-AOSP-First: Security Change-Id: I9288cf30b41e84ad8d3247c204e20482912bff69 Merged-In: I9288cf30b41e84ad8d3247c204e20482912bff69 (cherry picked from commit f83c5c8fecf89d9315945368aa20350c2f235cc0) --- libcutils/ashmem-dev.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp index 8c232f0cd0dc..501a4acd7256 100644 --- a/libcutils/ashmem-dev.cpp +++ b/libcutils/ashmem-dev.cpp @@ -341,6 +341,12 @@ static int memfd_create_region(const char* name, size_t size) { return -1; } + // forbid size changes to match ashmem behaviour + if (fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK) == -1) { + ALOGE("memfd_create(%s, %zd) F_ADD_SEALS failed: %m", name, size); + return -1; + } + if (debug_log) { ALOGE("memfd_create(%s, %zd) success. fd=%d\n", name, size, fd.get()); } @@ -392,14 +398,29 @@ int ashmem_create_region(const char *name, size_t size) } static int memfd_set_prot_region(int fd, int prot) { - /* Only proceed if an fd needs to be write-protected */ + int seals = fcntl(fd, F_GET_SEALS); + if (seals == -1) { + ALOGE("memfd_set_prot_region(%d, %d): F_GET_SEALS failed: %s\n", fd, prot, strerror(errno)); + return -1; + } + if (prot & PROT_WRITE) { + /* Now we want the buffer to be read-write, let's check if the buffer + * has been previously marked as read-only before, if so return error + */ + if (seals & F_SEAL_FUTURE_WRITE) { + ALOGE("memfd_set_prot_region(%d, %d): region is write protected\n", fd, prot); + errno = EINVAL; // inline with ashmem error code, if already in + // read-only mode + return -1; + } return 0; } - if (fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE) == -1) { - ALOGE("memfd_set_prot_region(%d, %d): F_SEAL_FUTURE_WRITE seal failed: %s\n", fd, prot, - strerror(errno)); + /* We would only allow read-only for any future file operations */ + if (fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE | F_SEAL_SEAL) == -1) { + ALOGE("memfd_set_prot_region(%d, %d): F_SEAL_FUTURE_WRITE | F_SEAL_SEAL seal failed: %s\n", + fd, prot, strerror(errno)); return -1; } From 010c37b6154d6a1d04125b3f140592c83ec70df7 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 15 Sep 2023 22:21:53 +0000 Subject: [PATCH 0385/1487] Revert "Revert "Lock down String8|16.string() usage"" This reverts commit 7210b285c2a7c8220789e039c9b2a72a931224cc. Reason for revert: attempt re-submit Change-Id: Ia95d11628c512163ae3d13cbdd5ebbe60f435937 --- libutils/include/utils/String16.h | 9 ++++++++- libutils/include/utils/String8.h | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h index 1fa3723b79ef..c7135766b097 100644 --- a/libutils/include/utils/String16.h +++ b/libutils/include/utils/String16.h @@ -59,7 +59,6 @@ class String16 ~String16(); inline const char16_t* c_str() const; - inline const char16_t* string() const; size_t size() const; inline bool empty() const; @@ -188,6 +187,14 @@ class String16 template explicit constexpr String16(const StaticData& s) : mString(s.data) {} + +// These symbols are for potential backward compatibility with prebuilts. To be removed. +#ifdef ENABLE_STRING16_OBSOLETE_METHODS +public: +#else +private: +#endif + inline const char16_t* string() const; }; // String16 can be trivially moved using memcpy() because moving does not diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h index 0b92f5b10ccf..6d250723b628 100644 --- a/libutils/include/utils/String8.h +++ b/libutils/include/utils/String8.h @@ -65,7 +65,6 @@ class String8 static String8 formatV(const char* fmt, va_list args); inline const char* c_str() const; - inline const char* string() const; inline size_t size() const; inline size_t bytes() const; @@ -155,6 +154,7 @@ class String8 #else private: #endif + inline const char* string() const; inline bool isEmpty() const; }; From 0a59994c5a37ff3a035950f0f7d145c259d1ea38 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Sun, 17 Sep 2023 09:34:43 -0700 Subject: [PATCH 0386/1487] Compile with -D_FILE_OFFSET_BITS to support 32-bit userspace This is to support when partition sizes are greater than 2GB (2^31) on 32-bit userspace. Bug: 300178204 Test: OTA on device with 32-bit userspace + product partition > 2GB Change-Id: I7074682352d8388ed410c684cb7cb0fa346ba24c Signed-off-by: Akilesh Kailash --- fs_mgr/libsnapshot/snapuserd/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index e56ffbe63d47..7aac4be98060 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -104,6 +104,10 @@ cc_defaults { "user-space-merge/snapuserd_server.cpp", ], + cflags: [ + "-D_FILE_OFFSET_BITS=64", + ], + static_libs: [ "libbase", "libbrotli", From c449ba34d8dc2b605e419515249c0ef3c299306a Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Sun, 17 Sep 2023 09:34:43 -0700 Subject: [PATCH 0387/1487] Compile with -D_FILE_OFFSET_BITS to support 32-bit userspace This is to support when partition sizes are greater than 2GB (2^31) on 32-bit userspace. Bug: 300178204 Test: OTA on device with 32-bit userspace + product partition > 2GB Ignore-AOSP-First: Cherrypick from AOSP Change-Id: I7074682352d8388ed410c684cb7cb0fa346ba24c Signed-off-by: Akilesh Kailash --- fs_mgr/libsnapshot/snapuserd/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 926148201713..dca9f49388eb 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -96,6 +96,10 @@ cc_defaults { "user-space-merge/snapuserd_server.cpp", ], + cflags: [ + "-D_FILE_OFFSET_BITS=64", + ], + static_libs: [ "libbase", "libbrotli", From d2ad53cf81651ca53be4e8e8ab279ccb38ad1d69 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Thu, 31 Aug 2023 10:42:54 -0700 Subject: [PATCH 0388/1487] Add CowOperationV2 this is going to replace the current version of CowOperation and will work with writer v2 and parser v2. This will be the on disk format of the cow, while CowOperation will be updated to be the in memory format of 15 bytes (implicitly will be the v3 version). Test: m libsnapshot Test: m libsnapshot Change-Id: Ibd00ef014a9fc11cdf2bad97c52462db8eef9502 --- .../include/libsnapshot/cow_format.h | 36 +++++++++++++++++++ .../include/libsnapshot/cow_reader.h | 1 - 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h index c9a4dee3af41..aac71de9c774 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h @@ -143,6 +143,42 @@ struct CowOperation { uint64_t source; } __attribute__((packed)); +// The on disk format of cow (currently == CowOperation) +struct CowOperationV2 { + // The operation code (see the constants and structures below). + uint8_t type; + + // If this operation reads from the data section of the COW, this contains + // the compression type of that data (see constants below). + uint8_t compression; + + // If this operation reads from the data section of the COW, this contains + // the length. + uint16_t data_length; + + // The block of data in the new image that this operation modifies. + uint64_t new_block; + + // The value of |source| depends on the operation code. + // + // For copy operations, this is a block location in the source image. + // + // For replace operations, this is a byte offset within the COW's data + // sections (eg, not landing within the header or metadata). It is an + // absolute position within the image. + // + // For zero operations (replace with all zeroes), this is unused and must + // be zero. + // + // For Label operations, this is the value of the applied label. + // + // For Cluster operations, this is the length of the following data region + // + // For Xor operations, this is the byte location in the source image. + uint64_t source; +} __attribute__((packed)); + +static_assert(sizeof(CowOperationV2) == sizeof(CowOperation)); static_assert(sizeof(CowOperation) == sizeof(CowFooterOperation)); static constexpr uint8_t kCowCopyOp = 1; diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h index f4ce52fa3622..67d301d70cff 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h @@ -165,7 +165,6 @@ class CowReader final : public ICowReader { void UpdateMergeOpsCompleted(int num_merge_ops) { header_.num_merge_ops += num_merge_ops; } private: - bool ParseOps(std::optional label); bool PrepMergeOps(); uint64_t FindNumCopyops(); uint8_t GetCompressionType(const CowOperation* op); From cc44c374684ee2f54c6446e97b6f1060784153be Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Mon, 18 Sep 2023 14:02:17 -0700 Subject: [PATCH 0389/1487] Updating comments on cow layout Updating comments to match current format. Scratch space exists in between header and operation Test: th Change-Id: I2f86e9dc4078f03370cdc38918136c894c6ca484 --- fs_mgr/libsnapshot/include/libsnapshot/cow_format.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h index aac71de9c774..9359b9ec1294 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h @@ -49,7 +49,9 @@ static constexpr uint32_t kDefaultCowVersion = 2; // | Footer (fixed) | // +-----------------------+ // -// The operations begin immediately after the header, and the "raw data" +// After the header is a 2mb scratch space that is used to read ahead data during merge operations +// +// The operations begin immediately after the scratch space, and the "raw data" // immediately follows the operation which refers to it. While streaming // an OTA, we can immediately write the op and data, syncing after each pair, // while storing operation metadata in memory. At the end, we compute data and From 6ea36bd1e48597ea070727c6e0851b0591337657 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Mon, 18 Sep 2023 14:09:27 -0700 Subject: [PATCH 0390/1487] Add static_assert to check sizeof off_t Add compile time flags which got dropped during refactoring. Bug: 300178204 Test: Build on 32-bit userspace Change-Id: I16be0973cb2cb2e174ff98c8b10fde27f997e4ab Signed-off-by: Akilesh Kailash --- fs_mgr/libsnapshot/snapuserd/Android.bp | 12 ++++++++++++ .../snapuserd/user-space-merge/snapuserd_core.h | 1 + 2 files changed, 13 insertions(+) diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 7aac4be98060..47a86858a7fb 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -74,6 +74,11 @@ cc_library_static { "user-space-merge/worker.cpp", "utility.cpp", ], + cflags: [ + "-D_FILE_OFFSET_BITS=64", + "-Wall", + "-Werror", + ], static_libs: [ "libbase", "libdm", @@ -106,6 +111,8 @@ cc_defaults { cflags: [ "-D_FILE_OFFSET_BITS=64", + "-Wall", + "-Werror", ], static_libs: [ @@ -230,6 +237,11 @@ cc_defaults { "testing/host_harness.cpp", "user-space-merge/snapuserd_test.cpp", ], + cflags: [ + "-D_FILE_OFFSET_BITS=64", + "-Wall", + "-Werror", + ], shared_libs: [ "libbase", "liblog", diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index 622fc5028dbe..e401c118e893 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -249,6 +249,7 @@ class SnapshotHandler : public std::enable_shared_from_this { }; std::ostream& operator<<(std::ostream& os, MERGE_IO_TRANSITION value); +static_assert(sizeof(off_t) == sizeof(uint64_t)); } // namespace snapshot } // namespace android From 4080e344265593bf3dea3b419b64e39d0deeb1cf Mon Sep 17 00:00:00 2001 From: Harsh Abichandani Date: Tue, 20 Jun 2023 16:01:16 +0530 Subject: [PATCH 0391/1487] Added liblp_builder_fuzzer and liblp_super_layout_builder_fuzzer exec/s: 17002 Test: ./liblp_builder_fuzzer exec/s: 31273 Test: ./liblp_super_layout_builder_fuzzer Bug: 285829660 Change-Id: I05d0a6c72069e500b2c838f9c6d900ca1ce2c8cc --- fs_mgr/liblp/fuzzer/Android.bp | 58 +++ fs_mgr/liblp/fuzzer/README.md | 93 ++++ fs_mgr/liblp/fuzzer/liblp_builder_fuzzer.cpp | 438 ++++++++++++++++++ .../liblp_super_layout_builder_fuzzer.cpp | 151 ++++++ 4 files changed, 740 insertions(+) create mode 100644 fs_mgr/liblp/fuzzer/Android.bp create mode 100644 fs_mgr/liblp/fuzzer/README.md create mode 100644 fs_mgr/liblp/fuzzer/liblp_builder_fuzzer.cpp create mode 100644 fs_mgr/liblp/fuzzer/liblp_super_layout_builder_fuzzer.cpp diff --git a/fs_mgr/liblp/fuzzer/Android.bp b/fs_mgr/liblp/fuzzer/Android.bp new file mode 100644 index 000000000000..bdeb377bfe4e --- /dev/null +++ b/fs_mgr/liblp/fuzzer/Android.bp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2023 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. + * + */ + +cc_defaults { + name: "liblp_fuzz_defaults", + header_libs: [ + "libstorage_literals_headers", + ], + shared_libs: [ + "liblp", + "libbase", + "liblog", + ], + static_libs: [ + "libcutils", + ], + include_dirs: [ + "system/core/fs_mgr/liblp", + ], + fuzz_config: { + cc: [ + "android-media-fuzzing-reports@google.com", + ], + componentid: 59148, + hotlists: ["4593311"], + description: "The fuzzers target the APIs of all liblp modules", + vector: "local_no_privileges_required", + service_privilege: "privileged", + users: "multi_user", + fuzzed_code_usage: "shipped" + } +} + +cc_fuzz { + name: "liblp_builder_fuzzer", + srcs: ["liblp_builder_fuzzer.cpp"], + defaults: ["liblp_fuzz_defaults"], +} + +cc_fuzz { + name: "liblp_super_layout_builder_fuzzer", + srcs: ["liblp_super_layout_builder_fuzzer.cpp"], + defaults: ["liblp_fuzz_defaults"], +} diff --git a/fs_mgr/liblp/fuzzer/README.md b/fs_mgr/liblp/fuzzer/README.md new file mode 100644 index 000000000000..be9adbd8e535 --- /dev/null +++ b/fs_mgr/liblp/fuzzer/README.md @@ -0,0 +1,93 @@ +# Fuzzers for liblp +## Table of contents ++ [liblp_builder_fuzzer](#Builder) ++ [liblp_super_layout_builder_fuzzer](#SuperBuilder) + +# Fuzzer for LiblpBuilder + +LiblpBuilder supports the following parameters: +1. kAttributeTypes (parameter name: "attribute") +2. blockDevSize (parameter name: "blockdev_size") +3. metadataMaxSize (parameter name: "metadata_max_size") +4. metadataSlotCount (parameter name: "metadata_slot_count") +5. partitionName (parameter name: "partition_name") +6. superBlockDeviceName (parameter name: "block_device_name") +7. blockDeviceInfoSize (parameter name: "block_device_info_size") +8. alignment (parameter name: "alignment") +9. alignmentOffset (parameter name: "alignment_offset") +10. logicalBlockSize (parameter name: "logical_block_size") +11. maxMetadataSize (parameter name: "max_metadata_size") +12. numSlots (parameter name: "metadata_slot_count") +13. deviceIndex (parameter name: "device_index") +14. start (parameter name: "start") +15. end (parameter name: "end") +16. addedGroupName (parameter name: "group_name") +17. partitionGroupName (parameter name: "partition_name") +18. numSectors (parameter name: "num_sectors") +19. physicalSector (parameter name: "physical_sector") +20. resizedPartitionSize (parameter name: "requested_size") + +| Parameter| Valid Values| Configured Value| +|------------- |-------------| ----- | +|`kAttributeTypes`| 1.`LP_PARTITION_ATTR_NONE`,
2.`LP_PARTITION_ATTR_READONLY`,
3.`LP_PARTITION_ATTR_SLOT_SUFFIXED`,
4.`LP_PARTITION_ATTR_UPDATED`,
5.`LP_PARTITION_ATTR_DISABLED`|Value obtained from FuzzedDataProvider| +|`blockDevSize`| Integer value from `0` to `100000`|Value obtained from FuzzedDataProvider| +|`metadataMaxSize`| Integer value from `0` to `10000` |Value obtained from FuzzedDataProvider| +|`metadataSlotCount`| Integer value from `0` to `2` |Value obtained from FuzzedDataProvider| +|`partitionName`| String |Value obtained from FuzzedDataProvider| +|`superBlockDeviceName`| String |Value obtained from FuzzedDataProvider| +|`blockDeviceInfoSize`| Integer |Value obtained from FuzzedDataProvider| +|`alignment`| Integer |Value obtained from FuzzedDataProvider| +|`alignmentOffset`| Integer |Value obtained from FuzzedDataProvider| +|`logicalBlockSize`| Integer |Value obtained from FuzzedDataProvider| +|`maxMetadataSize`| Integer value from `0` to `10000` |Value obtained from FuzzedDataProvider| +|`numSlots`| Integer value from `0` to `2` |Value obtained from FuzzedDataProvider| +|`deviceIndex`| Integer |Value obtained from FuzzedDataProvider| +|`start`| Integer |Value obtained from FuzzedDataProvider| +|`end`| Integer |Value obtained from FuzzedDataProvider| +|`partitionGroupName`| String |Value obtained from FuzzedDataProvider| +|`numSectors`| Integer value from `1` to `1000000` |Value obtained from FuzzedDataProvider| +|`physicalSector`| Integer value from `1` to `1000000` |Value obtained from FuzzedDataProvider| +|`resizedPartitionSize`| Integer value from `0` to `10000` |Value obtained from FuzzedDataProvider| + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) liblp_builder_fuzzer +``` +2. Run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/liblp_builder_fuzzer/liblp_builder_fuzzer +``` + +# Fuzzer for LiblpSuperLayoutBuilder + +SuperLayoutBuilder supports the following parameters: +1. kAttributeTypes (parameter name: "attribute") +2. blockDevSize (parameter name: "blockdev_size") +3. metadataMaxSize (parameter name: "metadata_max_size") +4. metadataSlotCount (parameter name: "metadata_slot_count") +5. partitionName (parameter name: "partition_name") +6. data (parameter name: "data") +7. imageName (parameter name: "image_name") + +| Parameter| Valid Values| Configured Value| +|------------- |-------------| ----- | +|`kAttributeTypes`| 1.`LP_PARTITION_ATTR_NONE`,
2.`LP_PARTITION_ATTR_READONLY`,
3.`LP_PARTITION_ATTR_SLOT_SUFFIXED`,
4.`LP_PARTITION_ATTR_UPDATED`,
5.`LP_PARTITION_ATTR_DISABLED`|Value obtained from FuzzedDataProvider| +|`blockDevSize`| Integer value from `0` to `100000`|Value obtained from FuzzedDataProvider| +|`metadataMaxSize`| Integer value from `0` to `10000` |Value obtained from FuzzedDataProvider| +|`metadataSlotCount`| Integer value from `0` to `2` |Value obtained from FuzzedDataProvider| +|`partitionName`| String |Value obtained from FuzzedDataProvider| +|`data`| String |Value obtained from FuzzedDataProvider| +|`imageName`| String |Value obtained from FuzzedDataProvider| + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) liblp_super_layout_builder_fuzzer +``` +2. Run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/liblp_super_layout_builder_fuzzer/liblp_super_layout_builder_fuzzer +``` diff --git a/fs_mgr/liblp/fuzzer/liblp_builder_fuzzer.cpp b/fs_mgr/liblp/fuzzer/liblp_builder_fuzzer.cpp new file mode 100644 index 000000000000..e5fbe272aef7 --- /dev/null +++ b/fs_mgr/liblp/fuzzer/liblp_builder_fuzzer.cpp @@ -0,0 +1,438 @@ +/* + * Copyright (C) 2023 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 +#include +#include +#include + +using namespace android::fs_mgr; +using namespace std; +using namespace android::storage_literals; + +static constexpr uint64_t kValidBlockSize = 4096 * 50; +static constexpr uint64_t kBlockDeviceInfoSize = 1024 * 1024; +static constexpr uint64_t kValidBlockDeviceInfoSize = 8_GiB; +static constexpr uint64_t kValidMaxGroupSize = 40960; +static constexpr uint64_t kMinBlockDevValue = 0; +static constexpr uint64_t kMaxBlockDevValue = 100000; +static constexpr uint64_t kMinSectorValue = 1; +static constexpr uint64_t kMaxSectorValue = 1000000; +static constexpr uint64_t kMinValue = 0; +static constexpr uint64_t kMaxValue = 10000; +static constexpr uint64_t kValidNumSectors = 1901568; +static constexpr uint64_t kValidPhysicalSector = 3608576; +static constexpr uint64_t kMinElements = 0; +static constexpr uint64_t kMaxElements = 10; +static constexpr uint32_t kValidAlignment = 786432; +static constexpr uint32_t kValidMetadataSize = 40960; +static constexpr uint32_t kValidAlignmentOffset = 229376; +static constexpr uint32_t kValidLogicalBlockSize = 4096; +static constexpr uint32_t kValidMaxMetadataSize = 65536; +static constexpr uint32_t kMinMetadataValue = 0; +static constexpr uint32_t kMaxMetadataValue = 10000; +static constexpr uint32_t kZeroAlignment = 0; +static constexpr uint32_t kZeroAlignmentOffset = 0; +static constexpr uint32_t kMaxBytes = 20; +static constexpr uint32_t kMinSlot = 0; +static constexpr uint32_t kMaxSlot = 10; +static constexpr uint32_t kMinBuilder = 0; +static constexpr uint32_t kMaxBuilder = 4; + +const uint64_t kAttributeTypes[] = { + LP_PARTITION_ATTR_NONE, LP_PARTITION_ATTR_READONLY, LP_PARTITION_ATTR_SLOT_SUFFIXED, + LP_PARTITION_ATTR_UPDATED, LP_PARTITION_ATTR_DISABLED, +}; + +const string kFuzzPartitionName = "fuzz_partition_name"; +const string kSuperPartitionName = "super_partition"; +const string kDeviceInfoName = "super"; +const string kDefaultGroupName = "default"; + +class BuilderFuzzer { + public: + BuilderFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; + void process(); + + private: + FuzzedDataProvider mFdp; + void invokeBuilderAPIs(); + void selectRandomBuilder(int32_t randomBuilder, string superBlockDeviceName); + void setupBuilder(string superBlockDeviceName); + void callChangePartitionGroup(); + void callVerifyExtentsAgainstSourceMetadata(); + vector mBlockDevices; + unique_ptr mBuilder; + string mResizePartitionName; + string mGroupNames[4] = { + "default", + "group_a", + "group_b", + mFdp.ConsumeRandomLengthString(kMaxBytes), + }; + string mPartitionNames[5] = { + "system_a", + "vendor_a", + "system_b", + "vendor_b", + mFdp.ConsumeRandomLengthString(kMaxBytes), + }; + Partition* mPartition; + Partition* mFuzzPartition; + Partition* mResizePartition; + template + T getParamValue(T validValue) { + T parameter = validValue; + if (mFdp.ConsumeBool()) { + parameter = mFdp.ConsumeIntegralInRange(kMinValue, kMaxValue); + } + return parameter; + } +}; + +void BuilderFuzzer::selectRandomBuilder(int32_t randomBuilder, string superBlockDeviceName) { + switch (randomBuilder) { + case 0: { + uint32_t maxMetadataSize = getParamValue(kValidMaxMetadataSize); + uint32_t numSlots = mFdp.ConsumeBool() + ? kMaxSlot + : mFdp.ConsumeIntegralInRange(kMinSlot, kMaxSlot); + mBuilder = MetadataBuilder::New(mBlockDevices, superBlockDeviceName, maxMetadataSize, + numSlots); + break; + } + case 1: { + uint64_t blockDevSize = + mFdp.ConsumeIntegralInRange(kMinBlockDevValue, kMaxBlockDevValue); + uint32_t metadataMaxSize = + mFdp.ConsumeIntegralInRange(kMinMetadataValue, kMaxMetadataValue); + uint32_t metadataSlotCount = mFdp.ConsumeIntegralInRange(kMinSlot, kMaxSlot); + mBuilder = MetadataBuilder::New(blockDevSize, metadataMaxSize, metadataSlotCount); + break; + } + case 2: { + uint64_t blockDevSize = getParamValue(kValidBlockSize); + uint32_t metadataSize = getParamValue(kValidMetadataSize); + uint32_t metadataSlotCount = mFdp.ConsumeIntegralInRange(kMinSlot, kMaxSlot); + mBuilder = MetadataBuilder::New(blockDevSize, metadataSize, metadataSlotCount); + break; + } + case 3: { + string superPartitionName = mFdp.ConsumeBool() + ? kSuperPartitionName + : mFdp.ConsumeRandomLengthString(kMaxBytes); + mBuilder = MetadataBuilder::New(PartitionOpener(), superPartitionName, + mFdp.ConsumeIntegralInRange(0, 1) /* slot_number */); + break; + } + case 4: { + string superPartitionName = mFdp.ConsumeBool() + ? kSuperPartitionName + : mFdp.ConsumeRandomLengthString(kMaxBytes); + mBuilder = MetadataBuilder::New( + superPartitionName, + mFdp.ConsumeIntegralInRange(0, 1) /* slot_number */); + break; + } + } +} + +void BuilderFuzzer::setupBuilder(string superBlockDeviceName) { + uint64_t blockDeviceInfoSize = + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() : kValidBlockDeviceInfoSize; + uint32_t alignment = mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() : kValidAlignment; + uint32_t alignmentOffset = + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() : kValidAlignmentOffset; + uint32_t logicalBlockSize = + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() : kValidLogicalBlockSize; + BlockDeviceInfo super(superBlockDeviceName, blockDeviceInfoSize, alignment, alignmentOffset, + logicalBlockSize); + mBlockDevices.push_back(super); + + mBuilder->AddGroup(kDefaultGroupName, mFdp.ConsumeIntegral() /* max_size */); + mPartition = mBuilder->AddPartition(kSuperPartitionName, LP_PARTITION_ATTR_READONLY); + + mFuzzPartition = mBuilder->AddPartition(kFuzzPartitionName, kDefaultGroupName, + LP_PARTITION_ATTR_READONLY); + + string mResizePartitionName = mFdp.ConsumeRandomLengthString(kMaxBytes); + if (!mResizePartitionName.size()) { + mResizePartitionName = "resize_partition"; + } + mResizePartition = mBuilder->AddPartition(mResizePartitionName, kDefaultGroupName, + LP_PARTITION_ATTR_READONLY); + + string changePartitionDeviceInfoName = + mFdp.ConsumeBool() ? kDeviceInfoName : mFdp.ConsumeRandomLengthString(kMaxBytes); + BlockDeviceInfo changePartitionDeviceInfo( + changePartitionDeviceInfoName, + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() : kBlockDeviceInfoSize /* size */, + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() + : kZeroAlignmentOffset /* alignment */, + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() + : kZeroAlignmentOffset /* alignment_offset */, + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() + : kValidLogicalBlockSize /* logical_block_size */); + mBlockDevices.push_back(changePartitionDeviceInfo); +} + +void BuilderFuzzer::callChangePartitionGroup() { + string group1 = mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : "group1"; + uint64_t group1Size = getParamValue(0); + + string group2 = mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : "group2"; + uint64_t group2Size = getParamValue(0); + + bool group1Added = mBuilder->AddGroup(group1, group1Size); + bool group2Added = mBuilder->AddGroup(group2, group2Size); + + string changeGroupPartitionName = mFdp.ConsumeRandomLengthString(kMaxBytes); + if (changeGroupPartitionName.size() && group1Added && group2Added) { + Partition* changeGroupPartition = mBuilder->AddPartition(changeGroupPartitionName, group1, + LP_PARTITION_ATTR_READONLY); + if (changeGroupPartition) { + mBuilder->ChangePartitionGroup(changeGroupPartition, group2); + } + } +} + +void BuilderFuzzer::callVerifyExtentsAgainstSourceMetadata() { + uint64_t sourceBlockDevSize = getParamValue(kValidBlockSize); + uint32_t sourceMetadataMaxSize = getParamValue(kValidMetadataSize); + uint32_t sourceSlotCount = mFdp.ConsumeIntegralInRange(0, 2); + auto sourceBuilder = + MetadataBuilder::New(sourceBlockDevSize, sourceMetadataMaxSize, sourceSlotCount); + + uint64_t targetBlockDevSize = getParamValue(kValidBlockSize); + uint32_t targetMetadataMaxSize = getParamValue(kValidMetadataSize); + uint32_t targetSlotCount = mFdp.ConsumeIntegralInRange(0, 2); + auto targetBuilder = + MetadataBuilder::New(targetBlockDevSize, targetMetadataMaxSize, targetSlotCount); + + if (sourceBuilder && targetBuilder) { + int64_t sourceGroups = mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + for (int64_t idx = 0; idx < sourceGroups; ++idx) { + sourceBuilder->AddGroup( + mFdp.PickValueInArray(mGroupNames), + mFdp.ConsumeBool() ? kValidMaxGroupSize : mFdp.ConsumeIntegral()); + } + + int64_t sourcePartitions = mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + for (int64_t idx = 0; idx < sourcePartitions; ++idx) { + sourceBuilder->AddPartition(mFdp.PickValueInArray(mPartitionNames), + LP_PARTITION_ATTR_READONLY); + } + + int64_t targetGroups = mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + for (int64_t idx = 0; idx < targetGroups; ++idx) { + targetBuilder->AddGroup( + mFdp.PickValueInArray(mGroupNames), + mFdp.ConsumeBool() ? kValidMaxGroupSize : mFdp.ConsumeIntegral()); + } + + int64_t targetPartitions = mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + for (int64_t idx = 0; idx < targetPartitions; ++idx) { + targetBuilder->AddPartition(mFdp.PickValueInArray(mPartitionNames), + LP_PARTITION_ATTR_READONLY); + } + + MetadataBuilder::VerifyExtentsAgainstSourceMetadata( + *sourceBuilder, mFdp.ConsumeBool() ? 0 : 1 /* source_slot_number */, *targetBuilder, + mFdp.ConsumeBool() ? 0 : 1 /* target_slot_number */, + vector{"system", "vendor", mFdp.ConsumeRandomLengthString(kMaxBytes)}); + } +} + +void BuilderFuzzer::invokeBuilderAPIs() { + string superBlockDeviceName = + mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : kDeviceInfoName; + uint32_t randomBuilder = mFdp.ConsumeIntegralInRange(kMinBuilder, kMaxBuilder); + selectRandomBuilder(randomBuilder, superBlockDeviceName); + + if (mBuilder.get()) { + setupBuilder(superBlockDeviceName); + + while (mFdp.remaining_bytes()) { + auto invokeAPIs = mFdp.PickValueInArray>({ + [&]() { callChangePartitionGroup(); }, + [&]() { + string addedGroupName = mFdp.PickValueInArray(mGroupNames); + mBuilder->AddGroup(addedGroupName, + mFdp.ConsumeIntegralInRange( + kMinValue, kMaxValue) /* max_size */); + }, + [&]() { + string partitionName = mFdp.PickValueInArray(mPartitionNames); + Partition* addedPartition = mBuilder->AddPartition( + partitionName, mFdp.PickValueInArray(kAttributeTypes)); + }, + [&]() { + int64_t numSectors = mFdp.ConsumeBool() + ? mFdp.ConsumeIntegralInRange( + kMinSectorValue, kMaxSectorValue) + : kValidNumSectors; + int64_t physicalSector = mFdp.ConsumeBool() + ? mFdp.ConsumeIntegralInRange( + kMinSectorValue, kMaxSectorValue) + : kValidPhysicalSector; + + int64_t numExtents = + mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + bool extentAdded = false; + for (int64_t i = 0; i <= numExtents; ++i) { + extentAdded = mBuilder->AddLinearExtent(mFuzzPartition, kDeviceInfoName, + numSectors, physicalSector); + } + + if (extentAdded) { + unique_ptr metadata = mBuilder->Export(); + uint64_t alignedSize = + mFdp.ConsumeIntegralInRange(kMinValue, kMaxValue); + mFuzzPartition->GetBeginningExtents(LP_SECTOR_SIZE * numExtents); + } + }, + [&]() { callVerifyExtentsAgainstSourceMetadata(); }, + [&]() { mBuilder->ListPartitionsInGroup(mFdp.PickValueInArray(mGroupNames)); }, + [&]() { + int64_t maxSize = mFdp.ConsumeIntegral(); + mBuilder->ChangeGroupSize(mFdp.PickValueInArray(mGroupNames), maxSize); + }, + [&]() { + string deviceInfoName = mFdp.ConsumeBool() + ? kDeviceInfoName + : mFdp.ConsumeRandomLengthString(kMaxBytes); + mBuilder->GetBlockDeviceInfo(deviceInfoName, &mBlockDevices[1]); + }, + [&]() { + string deviceInfoName = mFdp.ConsumeBool() + ? kDeviceInfoName + : mFdp.ConsumeRandomLengthString(kMaxBytes); + mBuilder->UpdateBlockDeviceInfo(deviceInfoName, mBlockDevices[1]); + }, + [&]() { + unique_ptr metadata = mBuilder->Export(); + mBuilder->ImportPartitions(*metadata.get(), + {mFdp.PickValueInArray(mPartitionNames)}); + }, + [&]() { mBuilder->HasBlockDevice(mFdp.PickValueInArray(mPartitionNames)); }, + [&]() { mBuilder->SetVirtualABDeviceFlag(); }, + [&]() { mBuilder->SetAutoSlotSuffixing(); }, + [&]() { mBuilder->ListGroups(); }, + [&]() { mBuilder->UsedSpace(); }, + [&]() { mBuilder->RequireExpandedMetadataHeader(); }, + [&]() { + uint64_t resizedPartitionSize = getParamValue(0); + mBuilder->ResizePartition(mResizePartition, resizedPartitionSize); + }, + [&]() { + uint32_t sourceSlot = mFdp.ConsumeBool() ? 0 : 1; + uint32_t targetSlot = mFdp.ConsumeBool() ? 0 : 1; + PartitionOpener partitionOpener; + string sourcePartition = + mFdp.ConsumeBool() ? kFuzzPartitionName : kDeviceInfoName; + + MetadataBuilder::NewForUpdate(partitionOpener, sourcePartition, sourceSlot, + targetSlot); + partitionOpener.GetDeviceString(mFdp.PickValueInArray(mPartitionNames)); + }, + [&]() { + unique_ptr metadata = mBuilder->Export(); + MetadataBuilder::New(*metadata.get()); + }, + [&]() { mBuilder->AllocatableSpace(); }, + [&]() { + PartitionOpener pOpener; + string superPartitionName = + mFdp.ConsumeBool() ? kSuperPartitionName + : mFdp.ConsumeRandomLengthString(kMaxBytes); + pOpener.Open(superPartitionName, O_RDONLY); + pOpener.GetInfo(superPartitionName, &mBlockDevices[0]); + }, + [&]() { + PartitionOpener pOpener; + string superPartitionName = + mFdp.ConsumeBool() ? kSuperPartitionName + : mFdp.ConsumeRandomLengthString(kMaxBytes); + pOpener.Open(superPartitionName, O_RDONLY); + pOpener.GetDeviceString(superPartitionName); + }, + [&]() { + Interval::Intersect( + Interval(mFdp.ConsumeIntegral() /* device _index */, + mFdp.ConsumeIntegral() /* start */, + mFdp.ConsumeIntegral()) /* end */, + Interval(mFdp.ConsumeIntegral() /* device _index */, + mFdp.ConsumeIntegral() /* start */, + mFdp.ConsumeIntegral() /* end */)); + }, + [&]() { + vector intervalVectorA; + int64_t internalVectorAElements = + mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + for (int64_t idx = 0; idx < internalVectorAElements; ++idx) { + intervalVectorA.push_back( + Interval(mFdp.ConsumeIntegral() /* device _index */, + mFdp.ConsumeIntegral() /* start */, + mFdp.ConsumeIntegral() /* end */)); + } + + vector intervalVectorB; + int64_t internalVectorBElements = + mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + for (int64_t idx = 0; idx < internalVectorBElements; ++idx) { + intervalVectorB.push_back( + Interval(mFdp.ConsumeIntegral() /* device _index */, + mFdp.ConsumeIntegral() /* start */, + mFdp.ConsumeIntegral() /* end */)); + } + + Interval::Intersect(intervalVectorA, intervalVectorB); + }, + [&]() { + uint64_t numSectors = + mFdp.ConsumeIntegralInRange(kMinValue, kMaxValue); + uint32_t deviceIndex = + mFdp.ConsumeIntegralInRange(kMinValue, kMaxValue); + uint64_t physicalSector = + mFdp.ConsumeIntegralInRange(kMinValue, kMaxValue); + LinearExtent extent(numSectors, deviceIndex, physicalSector); + extent.AsInterval(); + }, + [&]() { + IPropertyFetcher::OverrideForTesting(std::make_unique()); + }, + }); + invokeAPIs(); + } + if (mFdp.ConsumeBool()) { + mBuilder->RemoveGroupAndPartitions(mFdp.PickValueInArray(mGroupNames)); + } else { + string removePartition = mFdp.PickValueInArray(mPartitionNames); + mBuilder->RemovePartition(removePartition); + } + } +} + +void BuilderFuzzer::process() { + invokeBuilderAPIs(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + BuilderFuzzer builderFuzzer(data, size); + builderFuzzer.process(); + return 0; +} diff --git a/fs_mgr/liblp/fuzzer/liblp_super_layout_builder_fuzzer.cpp b/fs_mgr/liblp/fuzzer/liblp_super_layout_builder_fuzzer.cpp new file mode 100644 index 000000000000..887093c88b21 --- /dev/null +++ b/fs_mgr/liblp/fuzzer/liblp_super_layout_builder_fuzzer.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2023 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 +#include +#include +#include +#include +#include +#include +#include + +using namespace android::fs_mgr; +using namespace std; +using unique_fd = android::base::unique_fd; +using namespace android::storage_literals; + +static constexpr uint64_t kSuperLayoutValidBlockDevSize = 4_MiB; +static constexpr uint64_t kMinBlockDevValue = 0; +static constexpr uint64_t kMaxBlockDevValue = 100000; +static constexpr uint64_t kMinElements = 0; +static constexpr uint64_t kMaxElements = 10; +static constexpr uint32_t kSuperLayoutValidMetadataSize = 8_KiB; +static constexpr uint32_t kMinMetadataValue = 0; +static constexpr uint32_t kMaxMetadataValue = 10000; +static constexpr uint32_t kMaxBytes = 20; +static constexpr uint32_t kMinSlot = 0; +static constexpr uint32_t kMaxSlot = 10; +static constexpr uint32_t kMinOpen = 0; +static constexpr uint32_t kMaxOpen = 2; + +const uint64_t kAttributeTypes[] = { + LP_PARTITION_ATTR_NONE, LP_PARTITION_ATTR_READONLY, LP_PARTITION_ATTR_SLOT_SUFFIXED, + LP_PARTITION_ATTR_UPDATED, LP_PARTITION_ATTR_DISABLED, +}; + +class SuperLayoutBuilderFuzzer { + public: + SuperLayoutBuilderFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; + void process(); + + private: + FuzzedDataProvider mFdp; + void invokeSuperLayoutBuilderAPIs(); + void callRandomOpen(int32_t open); + void addMultiplePartitions(int32_t numPartitions); + void setupSuperLayoutBuilder(string fuzzPartitionName); + SuperLayoutBuilder mSuperLayoutBuilder; + unique_ptr mSuperBuilder; + unique_ptr mMetadata; + bool mOpenSuccess = false; +}; + +void SuperLayoutBuilderFuzzer::setupSuperLayoutBuilder(string fuzzPartitionName) { + uint64_t randomBlockDevSize = + mFdp.ConsumeIntegralInRange(kMinBlockDevValue, kMaxBlockDevValue); + uint64_t blockDevSize = mFdp.ConsumeBool() ? kSuperLayoutValidBlockDevSize : randomBlockDevSize; + uint32_t randomMetadataMaxSize = + mFdp.ConsumeIntegralInRange(kMinMetadataValue, kMaxMetadataValue); + uint32_t metadataMaxSize = + mFdp.ConsumeBool() ? kSuperLayoutValidMetadataSize : randomMetadataMaxSize; + uint32_t metadataSlotCount = mFdp.ConsumeIntegralInRange(kMinSlot, kMaxSlot); + mSuperBuilder = MetadataBuilder::New(blockDevSize, metadataMaxSize, metadataSlotCount); + + if (mSuperBuilder.get()) { + if (mFdp.ConsumeBool()) { + int32_t numPartitions = + mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + addMultiplePartitions(numPartitions); + } + + uint32_t randomOpen = mFdp.ConsumeIntegralInRange(kMinOpen, kMaxOpen); + callRandomOpen(randomOpen); + + if (!fuzzPartitionName.size()) { + fuzzPartitionName = "builder_partition"; + } + } +} + +void SuperLayoutBuilderFuzzer::addMultiplePartitions(int32_t numPartitions) { + for (int32_t idx = 0; idx < numPartitions; ++idx) { + string partitionName = mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) + : "builder_partition"; + mSuperBuilder->AddPartition(partitionName, mFdp.PickValueInArray(kAttributeTypes)); + } +} + +void SuperLayoutBuilderFuzzer::callRandomOpen(int32_t open) { + mMetadata = mSuperBuilder->Export(); + switch (open) { + case 0: { + vector imageData = mFdp.ConsumeBytes(kMaxBytes); + mOpenSuccess = mSuperLayoutBuilder.Open((void*)(imageData.data()), imageData.size()); + break; + } + case 1: { + mOpenSuccess = mSuperLayoutBuilder.Open(*mMetadata.get()); + break; + } + case 2: { + unique_fd fd(syscall(__NR_memfd_create, "image_file", 0)); + WriteToImageFile(fd, *mMetadata.get()); + mOpenSuccess = mSuperLayoutBuilder.Open(fd); + break; + } + } +} + +void SuperLayoutBuilderFuzzer::invokeSuperLayoutBuilderAPIs() { + string imageName = mFdp.ConsumeRandomLengthString(kMaxBytes); + string fuzzPartitionName = + mFdp.ConsumeBool() ? "builder_partition" : mFdp.ConsumeRandomLengthString(kMaxBytes); + setupSuperLayoutBuilder(fuzzPartitionName); + if (mOpenSuccess) { + while (mFdp.remaining_bytes()) { + auto invokeSuperAPIs = mFdp.PickValueInArray>({ + [&]() { mSuperLayoutBuilder.GetImageLayout(); }, + [&]() { + mSuperLayoutBuilder.AddPartition(fuzzPartitionName, imageName, + mFdp.ConsumeIntegral()); + }, + }); + invokeSuperAPIs(); + } + } +} + +void SuperLayoutBuilderFuzzer::process() { + invokeSuperLayoutBuilderAPIs(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + SuperLayoutBuilderFuzzer superLayoutBuilderFuzzer(data, size); + superLayoutBuilderFuzzer.process(); + return 0; +} From 072af6eec1458620578b06acad867557302df080 Mon Sep 17 00:00:00 2001 From: Harsh Abichandani Date: Tue, 18 Jul 2023 11:27:05 +0530 Subject: [PATCH 0392/1487] Added TestPartitionOpener_group Added TestPartitionOpener_group for test_partition_opener.cpp, as this file shall be used by liblp_apis_fuzzer and liblp_test_defaults Test: make TestPartitionOpener_group Bug: 285829660 Change-Id: I01da0a6896409af99af9e89092f6e1e3760cf4c2 --- fs_mgr/liblp/Android.bp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp index 996ffd759d6d..24eebdfb9192 100644 --- a/fs_mgr/liblp/Android.bp +++ b/fs_mgr/liblp/Android.bp @@ -93,8 +93,8 @@ cc_defaults { srcs: [ "builder_test.cpp", "super_layout_builder_test.cpp", - "test_partition_opener.cpp", "utility_test.cpp", + ":TestPartitionOpener_group", ], } @@ -122,3 +122,8 @@ cc_test { name: "vts_kernel_liblp_test", defaults: ["liblp_test_defaults"], } + +filegroup { + name: "TestPartitionOpener_group", + srcs: [ "test_partition_opener.cpp"], +} From b60befa806ffbdd413aa0c470b311d01d5fdbadd Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 19 Sep 2023 18:47:18 +0000 Subject: [PATCH 0393/1487] riscv64: minor ASLR bits changes. Improve the comment, and increase the "minimum maximum" to 24 --- we only support 64-bit, and 64-bit never has less than 24 bits. Bug: https://github.com/google/android-riscv64/issues/1 Test: treehugger Change-Id: I478c7649aa19258352c908a449cabe12da94952c --- init/security.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/init/security.cpp b/init/security.cpp index 6e616be93c5f..445286aa5695 100644 --- a/init/security.cpp +++ b/init/security.cpp @@ -117,10 +117,10 @@ Result SetMmapRndBitsAction(const BuiltinArguments&) { return {}; } #elif defined(__riscv) - // TODO: sv48 and sv57 were both added to the kernel this year, so we - // probably just need some kernel fixes to enable higher ASLR randomization, - // but for now 24 is the maximum that the kernel supports. - if (SetMmapRndBitsMin(24, 18, false)) { + // TODO: sv48 and sv57 have both been added to the kernel, but the kernel + // still doesn't support more than 24 bits. + // https://github.com/google/android-riscv64/issues/1 + if (SetMmapRndBitsMin(24, 24, false)) { return {}; } #elif defined(__x86_64__) From 6bc53ff7dd4d3da6a52dbda626db30aec7e67389 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 19 Sep 2023 18:40:03 +0000 Subject: [PATCH 0394/1487] arm64: update the "minimum maximum" comment. Noticed while looking at riscv64. Looks like a bug, but actually nothing we can do about it now or for the foreseeable future. Bug: https://github.com/google/android-riscv64/issues/45 Test: treehugger Change-Id: I2be81b2fd7095df40958a1f641d7b89cf5a8e41d --- init/security.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/init/security.cpp b/init/security.cpp index 6e616be93c5f..499978aa9727 100644 --- a/init/security.cpp +++ b/init/security.cpp @@ -106,13 +106,9 @@ Result SetMmapRndBitsAction(const BuiltinArguments&) { // uml does not support mmap_rnd_bits return {}; #elif defined(__aarch64__) - // arm64 architecture supports 18 - 33 rnd bits depending on pagesize and - // VA_SIZE. However the kernel might have been compiled with a narrower - // range using CONFIG_ARCH_MMAP_RND_BITS_MIN/MAX. To use the maximum - // supported number of bits, we start from the theoretical maximum of 33 - // bits and try smaller values until we reach 24 bits which is the - // Android-specific minimum. Don't go lower even if the configured maximum - // is smaller than 24. + // arm64 supports 14 - 33 rnd bits depending on page size and ARM64_VA_BITS. + // The kernel (6.5) still defaults to 39 va bits for 4KiB pages, so shipping + // devices are only getting 24 bits of randomness in practice. if (SetMmapRndBitsMin(33, 24, false) && (!Has32BitAbi() || SetMmapRndBitsMin(16, 16, true))) { return {}; } From 2e6aee53163cd5e6e31599c7948b54a2458d2344 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 19 Sep 2023 16:14:50 -0700 Subject: [PATCH 0395/1487] Removing double delete from flashall From aosp/2475604 the functionality of deleting retrofit partitions wasn't added back correctly. aosp/837186 adds this logic in. We should only have one delete that exists if the image is secondary and is dynamic. Unfortunately don't have a retrofit device to test on, but from an eye test this logic seems to match the old functionality and should be working Test: m fastboot Change-Id: I5481893ab1638541d21813efe1c4aab5219e1dcd --- fastboot/fastboot.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 21df729dc9a1..8ad10dee24a4 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -350,8 +350,7 @@ Result ParseNetworkSerial(const std::string& seria // // The returned Transport is a singleton, so multiple calls to this function will return the same // object, and the caller should not attempt to delete the returned Transport. -static std::unique_ptr open_device(const char* local_serial, - bool wait_for_device = true, +static std::unique_ptr open_device(const char* local_serial, bool wait_for_device = true, bool announce = true) { const Result network_serial = ParseNetworkSerial(local_serial); @@ -1885,9 +1884,8 @@ std::vector> FlashAllTool::CollectTasksFromImageList() { if (is_retrofit_device(fp_->fb)) { std::string partition_name = image->part_name + "_"s + slot; if (image->IsSecondary() && should_flash_in_userspace(partition_name)) { - fp_->fb->DeletePartition(partition_name); + tasks.emplace_back(std::make_unique(fp_, partition_name)); } - tasks.emplace_back(std::make_unique(fp_, partition_name)); } } From 8aba6d022cddb153f144488a9fabd445b08afb71 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 19 Sep 2023 16:59:13 -0700 Subject: [PATCH 0396/1487] Removing headers + using string Removing some unused headers and swapping out std::string_literal to strings Test: fastboot flashall Change-Id: I343272f4a678398a0446660a639c525e42e25891 --- fastboot/fastboot.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 8ad10dee24a4..080ad4261a49 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -28,7 +28,6 @@ #include "fastboot.h" -#include #include #include #include @@ -44,12 +43,10 @@ #include #include -#include #include #include #include #include -#include #include #include #include @@ -79,7 +76,6 @@ #include "fastboot_driver_interface.h" #include "fs.h" #include "storage.h" -#include "super_flash_helper.h" #include "task.h" #include "tcp.h" #include "transport.h" @@ -93,7 +89,6 @@ using android::base::ReadFully; using android::base::Split; using android::base::Trim; using android::base::unique_fd; -using namespace std::string_literals; using namespace std::placeholders; #define FASTBOOT_INFO_VERSION 1 @@ -1882,7 +1877,7 @@ std::vector> FlashAllTool::CollectTasksFromImageList() { // partitions (otherwise they would not mount on first boot). To enforce // this, we delete any logical partitions for the "other" slot. if (is_retrofit_device(fp_->fb)) { - std::string partition_name = image->part_name + "_"s + slot; + std::string partition_name = image->part_name + "_" + slot; if (image->IsSecondary() && should_flash_in_userspace(partition_name)) { tasks.emplace_back(std::make_unique(fp_, partition_name)); } @@ -2134,7 +2129,7 @@ static bool wipe_super(const android::fs_mgr::LpMetadata& metadata, const std::s if (metadata.block_devices.size() > 1) { ok = WriteSplitImageFiles(temp_dir.path, metadata, block_size, {}, true); } else { - auto image_path = temp_dir.path + "/"s + super_bdev_name + ".img"; + auto image_path = std::string(temp_dir.path) + "/" + std::string(super_bdev_name) + ".img"; ok = WriteToImageFile(image_path, metadata, block_size, {}, true); } if (!ok) { @@ -2153,7 +2148,7 @@ static bool wipe_super(const android::fs_mgr::LpMetadata& metadata, const std::s image_name = partition + ".img"; } - auto image_path = temp_dir.path + "/"s + image_name; + auto image_path = std::string(temp_dir.path) + "/" + image_name; auto flash = [&](const std::string& partition_name) { do_flash(partition_name.c_str(), image_path.c_str(), false, fp); }; From 78fb21c0f8dba54eb9a21f6c71923fd20fbb0511 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 19 Sep 2023 22:23:11 -0700 Subject: [PATCH 0397/1487] Removing extra includes Removing includes we aren't using Test: th Change-Id: Ia5d00436f34138789e43008ecd73d65cbad84bde --- fastboot/fastboot.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 8ad10dee24a4..b3f7147e1c0b 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -28,7 +28,6 @@ #include "fastboot.h" -#include #include #include #include @@ -44,12 +43,10 @@ #include #include -#include #include #include #include #include -#include #include #include #include @@ -79,7 +76,6 @@ #include "fastboot_driver_interface.h" #include "fs.h" #include "storage.h" -#include "super_flash_helper.h" #include "task.h" #include "tcp.h" #include "transport.h" From 2b1a0599c4530c34b57ba109917904451b55214e Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Tue, 12 Sep 2023 15:26:15 +0000 Subject: [PATCH 0398/1487] Don't depend on String8 cast to C string Bug: 295394788 Test: m checkbuild Change-Id: I5b86ae56250d409a23ab3f2bc72b725bcf6ab23e --- healthd/BatteryMonitor.cpp | 56 +++++++++++++------------ healthd/BatteryMonitor_v1.cpp | 38 ++++++++--------- libutils/CallStack.cpp | 2 +- libutils/String16_test.cpp | 70 ++++++++++++++++---------------- libutils/String8_test.cpp | 16 ++++---- trusty/stats/test/stats_test.cpp | 22 +++++----- 6 files changed, 102 insertions(+), 102 deletions(-) diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp index e4cf582fbdcf..0c976322d2cd 100644 --- a/healthd/BatteryMonitor.cpp +++ b/healthd/BatteryMonitor.cpp @@ -432,7 +432,7 @@ void BatteryMonitor::updateValues(void) { } if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0) - mHealthInfo->batteryTechnology = String8(buf.c_str()); + mHealthInfo->batteryTechnology = buf; if (readFromFile(mHealthdConfig->chargingPolicyPath, &buf) > 0) mHealthInfo->chargingPolicy = getBatteryChargingPolicy(buf.c_str()); @@ -786,39 +786,35 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) - mHealthdConfig->batteryStatusPath = path; + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryStatusPath = path; } if (mHealthdConfig->batteryHealthPath.empty()) { path.clear(); path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) - mHealthdConfig->batteryHealthPath = path; + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryHealthPath = path; } if (mHealthdConfig->batteryPresentPath.empty()) { path.clear(); path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) - mHealthdConfig->batteryPresentPath = path; + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryPresentPath = path; } if (mHealthdConfig->batteryCapacityPath.empty()) { path.clear(); path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) - mHealthdConfig->batteryCapacityPath = path; + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryCapacityPath = path; } if (mHealthdConfig->batteryVoltagePath.empty()) { path.clear(); path.appendFormat("%s/%s/voltage_now", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) { + if (access(path.c_str(), R_OK) == 0) { mHealthdConfig->batteryVoltagePath = path; } } @@ -827,7 +823,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/charge_full", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryFullChargePath = path; } @@ -835,7 +831,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/current_now", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryCurrentNowPath = path; } @@ -843,27 +839,29 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/cycle_count", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryCycleCountPath = path; } if (mHealthdConfig->batteryCapacityLevelPath.empty()) { path.clear(); path.appendFormat("%s/%s/capacity_level", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) mHealthdConfig->batteryCapacityLevelPath = path; + if (access(path.c_str(), R_OK) == 0) { + mHealthdConfig->batteryCapacityLevelPath = path; + } } if (mHealthdConfig->batteryChargeTimeToFullNowPath.empty()) { path.clear(); path.appendFormat("%s/%s/time_to_full_now", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryChargeTimeToFullNowPath = path; } if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty()) { path.clear(); path.appendFormat("%s/%s/charge_full_design", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryFullChargeDesignCapacityUahPath = path; } @@ -871,7 +869,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/current_avg", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryCurrentAvgPath = path; } @@ -879,7 +877,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/charge_counter", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryChargeCounterPath = path; } @@ -887,7 +885,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) { + if (access(path.c_str(), R_OK) == 0) { mHealthdConfig->batteryTemperaturePath = path; } } @@ -896,19 +894,19 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/technology", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryTechnologyPath = path; } if (mHealthdConfig->batteryStateOfHealthPath.empty()) { path.clear(); path.appendFormat("%s/%s/state_of_health", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) { + if (access(path.c_str(), R_OK) == 0) { mHealthdConfig->batteryStateOfHealthPath = path; } else { path.clear(); path.appendFormat("%s/%s/health_index", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryStateOfHealthPath = path; } } @@ -916,32 +914,36 @@ void BatteryMonitor::init(struct healthd_config *hc) { if (mHealthdConfig->batteryHealthStatusPath.empty()) { path.clear(); path.appendFormat("%s/%s/health_status", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) mHealthdConfig->batteryHealthStatusPath = path; + if (access(path.c_str(), R_OK) == 0) { + mHealthdConfig->batteryHealthStatusPath = path; + } } if (mHealthdConfig->batteryManufacturingDatePath.empty()) { path.clear(); path.appendFormat("%s/%s/manufacturing_date", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryManufacturingDatePath = path; } if (mHealthdConfig->batteryFirstUsageDatePath.empty()) { path.clear(); path.appendFormat("%s/%s/first_usage_date", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) mHealthdConfig->batteryFirstUsageDatePath = path; + if (access(path.c_str(), R_OK) == 0) { + mHealthdConfig->batteryFirstUsageDatePath = path; + } } if (mHealthdConfig->chargingStatePath.empty()) { path.clear(); path.appendFormat("%s/%s/charging_state", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) mHealthdConfig->chargingStatePath = path; + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->chargingStatePath = path; } if (mHealthdConfig->chargingPolicyPath.empty()) { path.clear(); path.appendFormat("%s/%s/charging_policy", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) mHealthdConfig->chargingPolicyPath = path; + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->chargingPolicyPath = path; } break; diff --git a/healthd/BatteryMonitor_v1.cpp b/healthd/BatteryMonitor_v1.cpp index 686c338cc10e..2e0cfc97182a 100644 --- a/healthd/BatteryMonitor_v1.cpp +++ b/healthd/BatteryMonitor_v1.cpp @@ -352,7 +352,7 @@ void BatteryMonitor::updateValues(void) { mHealthInfo->batteryHealth = getBatteryHealth(buf.c_str()); if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0) - mHealthInfo->batteryTechnology = String8(buf.c_str()); + mHealthInfo->batteryTechnology = buf; double MaxPower = 0; @@ -639,39 +639,35 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) - mHealthdConfig->batteryStatusPath = path; + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryStatusPath = path; } if (mHealthdConfig->batteryHealthPath.empty()) { path.clear(); path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) - mHealthdConfig->batteryHealthPath = path; + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryHealthPath = path; } if (mHealthdConfig->batteryPresentPath.empty()) { path.clear(); path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) - mHealthdConfig->batteryPresentPath = path; + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryPresentPath = path; } if (mHealthdConfig->batteryCapacityPath.empty()) { path.clear(); path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) - mHealthdConfig->batteryCapacityPath = path; + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryCapacityPath = path; } if (mHealthdConfig->batteryVoltagePath.empty()) { path.clear(); path.appendFormat("%s/%s/voltage_now", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) { + if (access(path.c_str(), R_OK) == 0) { mHealthdConfig->batteryVoltagePath = path; } } @@ -680,7 +676,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/charge_full", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryFullChargePath = path; } @@ -688,7 +684,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/current_now", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryCurrentNowPath = path; } @@ -696,27 +692,29 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/cycle_count", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryCycleCountPath = path; } if (mHealthdConfig->batteryCapacityLevelPath.empty()) { path.clear(); path.appendFormat("%s/%s/capacity_level", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) mHealthdConfig->batteryCapacityLevelPath = path; + if (access(path.c_str(), R_OK) == 0) { + mHealthdConfig->batteryCapacityLevelPath = path; + } } if (mHealthdConfig->batteryChargeTimeToFullNowPath.empty()) { path.clear(); path.appendFormat("%s/%s/time_to_full_now", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryChargeTimeToFullNowPath = path; } if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty()) { path.clear(); path.appendFormat("%s/%s/charge_full_design", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryFullChargeDesignCapacityUahPath = path; } @@ -724,7 +722,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/current_avg", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryCurrentAvgPath = path; } @@ -732,7 +730,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/charge_counter", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryChargeCounterPath = path; } @@ -740,7 +738,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) { + if (access(path.c_str(), R_OK) == 0) { mHealthdConfig->batteryTemperaturePath = path; } } @@ -749,7 +747,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { path.clear(); path.appendFormat("%s/%s/technology", POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) + if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryTechnologyPath = path; } diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp index 4dcb35b3657b..11f2c9262048 100644 --- a/libutils/CallStack.cpp +++ b/libutils/CallStack.cpp @@ -82,7 +82,7 @@ String8 CallStack::toString(const char* prefix) const { void CallStack::print(Printer& printer) const { for (size_t i = 0; i < mFrameLines.size(); i++) { - printer.printLine(mFrameLines[i]); + printer.printLine(mFrameLines[i].c_str()); } } diff --git a/libutils/String16_test.cpp b/libutils/String16_test.cpp index c6e6f746a858..6f4642e8fb6d 100644 --- a/libutils/String16_test.cpp +++ b/libutils/String16_test.cpp @@ -33,50 +33,50 @@ ::testing::AssertionResult Char16_tStringEquals(const char16_t* a, const char16_ TEST(String16Test, FromChar16_t) { String16 tmp(u"Verify me"); - EXPECT_STR16EQ(u"Verify me", tmp); + EXPECT_STR16EQ(u"Verify me", tmp.c_str()); } TEST(String16Test, FromChar16_tSized) { String16 tmp(u"Verify me", 7); - EXPECT_STR16EQ(u"Verify ", tmp); + EXPECT_STR16EQ(u"Verify ", tmp.c_str()); } TEST(String16Test, FromChar) { String16 tmp("Verify me"); - EXPECT_STR16EQ(u"Verify me", tmp); + EXPECT_STR16EQ(u"Verify me", tmp.c_str()); } TEST(String16Test, FromCharSized) { String16 tmp("Verify me", 7); - EXPECT_STR16EQ(u"Verify ", tmp); + EXPECT_STR16EQ(u"Verify ", tmp.c_str()); } TEST(String16Test, Copy) { String16 tmp("Verify me"); String16 another = tmp; - EXPECT_STR16EQ(u"Verify me", tmp); - EXPECT_STR16EQ(u"Verify me", another); + EXPECT_STR16EQ(u"Verify me", tmp.c_str()); + EXPECT_STR16EQ(u"Verify me", another.c_str()); } TEST(String16Test, CopyAssign) { String16 tmp("Verify me"); String16 another; another = tmp; - EXPECT_STR16EQ(u"Verify me", tmp); - EXPECT_STR16EQ(u"Verify me", another); + EXPECT_STR16EQ(u"Verify me", tmp.c_str()); + EXPECT_STR16EQ(u"Verify me", another.c_str()); } TEST(String16Test, Move) { String16 tmp("Verify me"); String16 another(std::move(tmp)); - EXPECT_STR16EQ(u"Verify me", another); + EXPECT_STR16EQ(u"Verify me", another.c_str()); } TEST(String16Test, MoveAssign) { String16 tmp("Verify me"); String16 another; another = std::move(tmp); - EXPECT_STR16EQ(u"Verify me", another); + EXPECT_STR16EQ(u"Verify me", another.c_str()); } TEST(String16Test, Size) { @@ -88,27 +88,27 @@ TEST(String16Test, setTo) { String16 tmp("Verify me"); tmp.setTo(u"New content"); EXPECT_EQ(11U, tmp.size()); - EXPECT_STR16EQ(u"New content", tmp); + EXPECT_STR16EQ(u"New content", tmp.c_str()); } TEST(String16Test, Append) { String16 tmp("Verify me"); tmp.append(String16("Hello")); EXPECT_EQ(14U, tmp.size()); - EXPECT_STR16EQ(u"Verify meHello", tmp); + EXPECT_STR16EQ(u"Verify meHello", tmp.c_str()); } TEST(String16Test, Insert) { String16 tmp("Verify me"); tmp.insert(6, u"Insert"); EXPECT_EQ(15U, tmp.size()); - EXPECT_STR16EQ(u"VerifyInsert me", tmp); + EXPECT_STR16EQ(u"VerifyInsert me", tmp.c_str()); } TEST(String16Test, ReplaceAll) { String16 tmp("Verify verify Verify"); tmp.replaceAll(u'r', u'!'); - EXPECT_STR16EQ(u"Ve!ify ve!ify Ve!ify", tmp); + EXPECT_STR16EQ(u"Ve!ify ve!ify Ve!ify", tmp.c_str()); } TEST(String16Test, Compare) { @@ -127,8 +127,8 @@ TEST(String16Test, StaticString) { TEST(String16Test, StaticStringCopy) { StaticString16 tmp(u"Verify me"); String16 another = tmp; - EXPECT_STR16EQ(u"Verify me", tmp); - EXPECT_STR16EQ(u"Verify me", another); + EXPECT_STR16EQ(u"Verify me", tmp.c_str()); + EXPECT_STR16EQ(u"Verify me", another.c_str()); EXPECT_TRUE(tmp.isStaticString()); EXPECT_TRUE(another.isStaticString()); } @@ -136,7 +136,7 @@ TEST(String16Test, StaticStringCopy) { TEST(String16Test, StaticStringMove) { StaticString16 tmp(u"Verify me"); String16 another(std::move(tmp)); - EXPECT_STR16EQ(u"Verify me", another); + EXPECT_STR16EQ(u"Verify me", another.c_str()); EXPECT_TRUE(another.isStaticString()); } @@ -157,7 +157,7 @@ TEST(String16Test, StaticStringAppend) { StaticString16 tmp(u"Verify me"); tmp.append(String16("Hello")); EXPECT_EQ(14U, tmp.size()); - EXPECT_STR16EQ(u"Verify meHello", tmp); + EXPECT_STR16EQ(u"Verify meHello", tmp.c_str()); EXPECT_FALSE(tmp.isStaticString()); } @@ -165,14 +165,14 @@ TEST(String16Test, StaticStringInsert) { StaticString16 tmp(u"Verify me"); tmp.insert(6, u"Insert"); EXPECT_EQ(15U, tmp.size()); - EXPECT_STR16EQ(u"VerifyInsert me", tmp); + EXPECT_STR16EQ(u"VerifyInsert me", tmp.c_str()); EXPECT_FALSE(tmp.isStaticString()); } TEST(String16Test, StaticStringReplaceAll) { StaticString16 tmp(u"Verify verify Verify"); tmp.replaceAll(u'r', u'!'); - EXPECT_STR16EQ(u"Ve!ify ve!ify Ve!ify", tmp); + EXPECT_STR16EQ(u"Ve!ify ve!ify Ve!ify", tmp.c_str()); EXPECT_FALSE(tmp.isStaticString()); } @@ -185,17 +185,17 @@ TEST(String16Test, StringSetToStaticString) { StaticString16 tmp(u"Verify me"); String16 another(u"nonstatic"); another = tmp; - EXPECT_STR16EQ(u"Verify me", tmp); - EXPECT_STR16EQ(u"Verify me", another); + EXPECT_STR16EQ(u"Verify me", tmp.c_str()); + EXPECT_STR16EQ(u"Verify me", another.c_str()); } TEST(String16Test, StringCopyAssignFromStaticString) { StaticString16 tmp(u"Verify me"); String16 another(u"nonstatic"); another = tmp; - EXPECT_STR16EQ(u"Verify me", another); + EXPECT_STR16EQ(u"Verify me", another.c_str()); EXPECT_TRUE(another.isStaticString()); - EXPECT_STR16EQ(u"Verify me", tmp); + EXPECT_STR16EQ(u"Verify me", tmp.c_str()); EXPECT_TRUE(tmp.isStaticString()); } @@ -203,7 +203,7 @@ TEST(String16Test, StringMoveAssignFromStaticString) { StaticString16 tmp(u"Verify me"); String16 another(u"nonstatic"); another = std::move(tmp); - EXPECT_STR16EQ(u"Verify me", another); + EXPECT_STR16EQ(u"Verify me", another.c_str()); EXPECT_TRUE(another.isStaticString()); } @@ -221,19 +221,19 @@ TEST(String16Test, OverreadUtf8Conversion) { TEST(String16Test, ValidUtf8Conversion) { String16 another("abcdef"); EXPECT_EQ(6U, another.size()); - EXPECT_STR16EQ(another, u"abcdef"); + EXPECT_STR16EQ(another.c_str(), u"abcdef"); } TEST(String16Test, append) { String16 s; EXPECT_EQ(OK, s.append(String16(u"foo"))); - EXPECT_STR16EQ(u"foo", s); + EXPECT_STR16EQ(u"foo", s.c_str()); EXPECT_EQ(OK, s.append(String16(u"bar"))); - EXPECT_STR16EQ(u"foobar", s); + EXPECT_STR16EQ(u"foobar", s.c_str()); EXPECT_EQ(OK, s.append(u"baz", 0)); - EXPECT_STR16EQ(u"foobar", s); + EXPECT_STR16EQ(u"foobar", s.c_str()); EXPECT_EQ(NO_MEMORY, s.append(u"baz", SIZE_MAX)); - EXPECT_STR16EQ(u"foobar", s); + EXPECT_STR16EQ(u"foobar", s.c_str()); } TEST(String16Test, insert) { @@ -241,19 +241,19 @@ TEST(String16Test, insert) { // Inserting into the empty string inserts at the start. EXPECT_EQ(OK, s.insert(123, u"foo")); - EXPECT_STR16EQ(u"foo", s); + EXPECT_STR16EQ(u"foo", s.c_str()); // Inserting zero characters at any position is okay, but won't expand the string. EXPECT_EQ(OK, s.insert(123, u"foo", 0)); - EXPECT_STR16EQ(u"foo", s); + EXPECT_STR16EQ(u"foo", s.c_str()); // Inserting past the end of a non-empty string appends. EXPECT_EQ(OK, s.insert(123, u"bar")); - EXPECT_STR16EQ(u"foobar", s); + EXPECT_STR16EQ(u"foobar", s.c_str()); EXPECT_EQ(OK, s.insert(3, u"!")); - EXPECT_STR16EQ(u"foo!bar", s); + EXPECT_STR16EQ(u"foo!bar", s.c_str()); EXPECT_EQ(NO_MEMORY, s.insert(3, u"", SIZE_MAX)); - EXPECT_STR16EQ(u"foo!bar", s); + EXPECT_STR16EQ(u"foo!bar", s.c_str()); } diff --git a/libutils/String8_test.cpp b/libutils/String8_test.cpp index 9c12cb12df84..e1fd13a9e137 100644 --- a/libutils/String8_test.cpp +++ b/libutils/String8_test.cpp @@ -100,19 +100,19 @@ TEST_F(String8Test, CheckUtf32Conversion) { TEST_F(String8Test, ValidUtf16Conversion) { char16_t tmp[] = u"abcdef"; String8 valid = String8(String16(tmp)); - EXPECT_STREQ(valid, "abcdef"); + EXPECT_STREQ(valid.c_str(), "abcdef"); } TEST_F(String8Test, append) { String8 s; EXPECT_EQ(OK, s.append("foo")); - EXPECT_STREQ("foo", s); + EXPECT_STREQ("foo", s.c_str()); EXPECT_EQ(OK, s.append("bar")); - EXPECT_STREQ("foobar", s); + EXPECT_STREQ("foobar", s.c_str()); EXPECT_EQ(OK, s.append("baz", 0)); - EXPECT_STREQ("foobar", s); + EXPECT_STREQ("foobar", s.c_str()); EXPECT_EQ(NO_MEMORY, s.append("baz", SIZE_MAX)); - EXPECT_STREQ("foobar", s); + EXPECT_STREQ("foobar", s.c_str()); } TEST_F(String8Test, removeAll) { @@ -123,12 +123,12 @@ TEST_F(String8Test, removeAll) { // expect to return true and string content should remain unchanged EXPECT_TRUE(s.removeAll("")); - EXPECT_STREQ("Hello, world!", s); + EXPECT_STREQ("Hello, world!", s.c_str()); // expect to return false EXPECT_FALSE(s.removeAll("x")); - EXPECT_STREQ("Hello, world!", s); + EXPECT_STREQ("Hello, world!", s.c_str()); EXPECT_TRUE(s.removeAll("o")); - EXPECT_STREQ("Hell, wrld!", s); + EXPECT_STREQ("Hell, wrld!", s.c_str()); } diff --git a/trusty/stats/test/stats_test.cpp b/trusty/stats/test/stats_test.cpp index 1edddeb5abd3..1d6eb34a6d4c 100644 --- a/trusty/stats/test/stats_test.cpp +++ b/trusty/stats/test/stats_test.cpp @@ -252,20 +252,20 @@ TEST_F(TrustyStatsTest, CheckAtoms) { ::testing::AnyOf(::testing::Eq(TrustyAtoms::TrustyAppCrashed), ::testing::Eq(TrustyAtoms::TrustyError), ::testing::Eq(TrustyAtoms::TrustyStorageError))); - ASSERT_STREQ(String8(vendorAtom.reverseDomainName), "google.android.trusty"); + ASSERT_EQ(String8(vendorAtom.reverseDomainName), "google.android.trusty"); switch (vendorAtom.atomId) { case TrustyAtoms::TrustyAppCrashed: ++atomAppCrashedCnt; - ASSERT_STREQ(String8(vendorAtom.values[0].get()), - "5247d19b-cf09-4272-a450-3ef20dbefc14"); + ASSERT_EQ(String8(vendorAtom.values[0].get()), + "5247d19b-cf09-4272-a450-3ef20dbefc14"); break; case TrustyAtoms::TrustyStorageError: ++atomStorageErrorCnt; ASSERT_EQ(vendorAtom.values[0].get(), 5); - ASSERT_STREQ(String8(vendorAtom.values[1].get()), - "5247d19b-cf09-4272-a450-3ef20dbefc14"); - ASSERT_STREQ(String8(vendorAtom.values[2].get()), - "5247d19b-cf09-4272-a450-3ef20dbefc14"); + ASSERT_EQ(String8(vendorAtom.values[1].get()), + "5247d19b-cf09-4272-a450-3ef20dbefc14"); + ASSERT_EQ(String8(vendorAtom.values[2].get()), + "5247d19b-cf09-4272-a450-3ef20dbefc14"); ASSERT_EQ(vendorAtom.values[3].get(), 1); ASSERT_EQ(vendorAtom.values[4].get(), 3); ASSERT_EQ(vendorAtom.values[5].get(), @@ -330,13 +330,13 @@ TEST_F(TrustyMetricsCrashTest, CheckTrustyCrashAtoms) { ::testing::AnyOf(::testing::Eq(TrustyAtoms::TrustyAppCrashed), ::testing::Eq(TrustyAtoms::TrustyError), ::testing::Eq(TrustyAtoms::TrustyStorageError))); - ASSERT_STREQ(String8(vendorAtom.reverseDomainName), "google.android.trusty"); + ASSERT_EQ(String8(vendorAtom.reverseDomainName), "google.android.trusty"); switch (vendorAtom.atomId) { case TrustyAtoms::TrustyAppCrashed: ++atomAppCrashedCnt; - ASSERT_STREQ(String8(vendorAtom.values[0].get()), - kTrustyCrasherUuid); + ASSERT_EQ(String8(vendorAtom.values[0].get()), + kTrustyCrasherUuid); atomCrashReasons.push_back(vendorAtom.values[1].get()); break; case TrustyAtoms::TrustyStorageError: @@ -344,7 +344,7 @@ TEST_F(TrustyMetricsCrashTest, CheckTrustyCrashAtoms) { break; case TrustyAtoms::TrustyError: ++atomTrustyErrorCnt; - ASSERT_STREQ(String8(vendorAtom.values[1].get()), ""); + ASSERT_EQ(String8(vendorAtom.values[1].get()), ""); break; default: FAIL() << "Unknown vendor atom ID: " << vendorAtom.atomId; From a95ed0aeaccf22439e1a6306f42446e48b6f2030 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Mon, 18 Sep 2023 16:42:57 -0700 Subject: [PATCH 0399/1487] Move CF only tests to CF test mapping suite This change doesn't modify presubmit coverage, the tests will still run in the lab as test mapping suite, just on a different ATP test config that dedicated to tests can only run on CF (not aosp_cf), on git_main branch. Bug: 300519349 Test: atest presubmit check Change-Id: Ib179c034dc58f8d8a763d374af0d103baf51343b --- trusty/keymaster/TEST_MAPPING | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/trusty/keymaster/TEST_MAPPING b/trusty/keymaster/TEST_MAPPING index 0475e04018f7..c4fba677ce5a 100644 --- a/trusty/keymaster/TEST_MAPPING +++ b/trusty/keymaster/TEST_MAPPING @@ -7,16 +7,20 @@ "name": "VtsHalRemotelyProvisionedComponentTargetTest" }, { - "name": "RkpdAppUnitTests" + "name": "RkpdAppUnitTests", + "keywords": ["internal"] }, { - "name": "RkpdAppGoogleUnitTests" + "name": "RkpdAppGoogleUnitTests", + "keywords": ["internal"] }, { - "name": "RkpdAppIntegrationTests" + "name": "RkpdAppIntegrationTests", + "keywords": ["internal"] }, { - "name": "RkpdAppGoogleIntegrationTests" + "name": "RkpdAppGoogleIntegrationTests", + "keywords": ["internal"] } ] } From 43c87b3291e7d2d706c287d2b6c5770fb77e5175 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Wed, 20 Sep 2023 13:24:46 -0700 Subject: [PATCH 0400/1487] Remove unnecessary keyword setting These 2 tests can run on aosp cf. Bug: 300519349 Test: atest presubmit check Change-Id: I8ee41c2abe464be2c2ee4537de5edf86308183aa --- trusty/keymaster/TEST_MAPPING | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/trusty/keymaster/TEST_MAPPING b/trusty/keymaster/TEST_MAPPING index c4fba677ce5a..4f082d8956e7 100644 --- a/trusty/keymaster/TEST_MAPPING +++ b/trusty/keymaster/TEST_MAPPING @@ -7,16 +7,14 @@ "name": "VtsHalRemotelyProvisionedComponentTargetTest" }, { - "name": "RkpdAppUnitTests", - "keywords": ["internal"] + "name": "RkpdAppUnitTests" }, { "name": "RkpdAppGoogleUnitTests", "keywords": ["internal"] }, { - "name": "RkpdAppIntegrationTests", - "keywords": ["internal"] + "name": "RkpdAppIntegrationTests" }, { "name": "RkpdAppGoogleIntegrationTests", From f06e218e826039bf5113de5a773803fccfcac561 Mon Sep 17 00:00:00 2001 From: Andrew Scull Date: Thu, 21 Sep 2023 14:50:55 +0000 Subject: [PATCH 0401/1487] Delete unused DATA_MNT_POINT macro The macros isn't used anywhere but was a distraction when tracking down /data mounting behaviour. Test: build Change-Id: Ie23574326cbebd7f515c8409e1dcb91a00cafc6f --- init/builtins.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/init/builtins.cpp b/init/builtins.cpp index a70e86683f52..a95a4a315b64 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -475,8 +475,6 @@ static struct { { 0, 0 }, }; -#define DATA_MNT_POINT "/data" - /* mount */ static Result do_mount(const BuiltinArguments& args) { const char* options = nullptr; From 93377e99e2ffa260f1da5b53326d51ef19ab74f6 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Tue, 19 Sep 2023 21:04:39 -0700 Subject: [PATCH 0402/1487] snapuserd_test: don't discard result of std::async std::async returns a std::future whose destructor blocks until the async function has completed, which defeats the purpose of using std::async. The future needs to be kept alive to allow the function to run concurrently. Starting in C++20, std::async marked [[nodiscard]] to help catch this misuse. Upgrading libc++ adds the [[nodiscard]] attribute to std::async, so fixing this bug is necessary to keep the code compiling after libc++ is updated. Bug: 175635923 Test: treehugger Test: m && m snapuserd_test Change-Id: Id2e820248c2b6111aa843fb709e08a2c19677066 --- .../snapuserd/user-space-merge/snapuserd_test.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 01fe06fe79bf..620ecbd3f102 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -714,10 +714,12 @@ TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST) { } ASSERT_NO_FATAL_FAILURE(SetupDefault()); // Issue I/O before merge begins - std::async(std::launch::async, &SnapuserdTest::ReadSnapshotDeviceAndValidate, this); + auto read_future = + std::async(std::launch::async, &SnapuserdTest::ReadSnapshotDeviceAndValidate, this); // Start the merge ASSERT_TRUE(Merge()); ValidateMerge(); + read_future.wait(); } TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST_1) { @@ -728,9 +730,11 @@ TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST_1) { // Start the merge ASSERT_TRUE(StartMerge()); // Issue I/O in parallel when merge is in-progress - std::async(std::launch::async, &SnapuserdTest::ReadSnapshotDeviceAndValidate, this); + auto read_future = + std::async(std::launch::async, &SnapuserdTest::ReadSnapshotDeviceAndValidate, this); CheckMergeCompletion(); ValidateMerge(); + read_future.wait(); } TEST_F(SnapuserdTest, Snapshot_Merge_Resume) { From 999efbef093214bf8302591a17a777439a0a85e6 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Thu, 21 Sep 2023 17:51:52 -0700 Subject: [PATCH 0403/1487] Add missing and includes Bug: 175635923 Test: m MODULES-IN-system-core-libutils Change-Id: I065907a58a88723ae512f155dfde2d2fcb3fc322 --- libutils/String16_fuzz.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libutils/String16_fuzz.cpp b/libutils/String16_fuzz.cpp index a271aeebd897..8f9781bfef9b 100644 --- a/libutils/String16_fuzz.cpp +++ b/libutils/String16_fuzz.cpp @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include +#include #include "fuzzer/FuzzedDataProvider.h" #include "utils/String16.h" From 87c90e7b65c734ba553a4655d0aee8c7dd939676 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Thu, 21 Sep 2023 19:44:47 -0700 Subject: [PATCH 0404/1487] Add missing include Bug: 175635923 Test: m MODULES-IN-system-core-trusty Change-Id: I7790dde8eba948cf95cb14dd2b436c3f6f88765a --- trusty/apploader/apploader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/trusty/apploader/apploader.cpp b/trusty/apploader/apploader.cpp index 17d083c735cd..f782d2acb842 100644 --- a/trusty/apploader/apploader.cpp +++ b/trusty/apploader/apploader.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include From 7107c582fa1948c3ccdaafa251dcd91ec0e847d1 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 22 Sep 2023 14:33:47 +0000 Subject: [PATCH 0405/1487] Remove unused files. Test: treehugger Change-Id: I7ea71395b87eb12044fb3e7d19c171149f4cc90b --- libcutils/arch-x86/cache.h | 28 ---------------------------- libcutils/arch-x86_64/cache.h | 22 ---------------------- 2 files changed, 50 deletions(-) delete mode 100644 libcutils/arch-x86/cache.h delete mode 100644 libcutils/arch-x86_64/cache.h diff --git a/libcutils/arch-x86/cache.h b/libcutils/arch-x86/cache.h deleted file mode 100644 index 1c22feaa7ae8..000000000000 --- a/libcutils/arch-x86/cache.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#if defined(__slm__) -/* Values are optimized for Silvermont */ -#define SHARED_CACHE_SIZE (1024*1024) /* Silvermont L2 Cache */ -#define DATA_CACHE_SIZE (24*1024) /* Silvermont L1 Data Cache */ -#else -/* Values are optimized for Atom */ -#define SHARED_CACHE_SIZE (512*1024) /* Atom L2 Cache */ -#define DATA_CACHE_SIZE (24*1024) /* Atom L1 Data Cache */ -#endif - -#define SHARED_CACHE_SIZE_HALF (SHARED_CACHE_SIZE / 2) -#define DATA_CACHE_SIZE_HALF (DATA_CACHE_SIZE / 2) diff --git a/libcutils/arch-x86_64/cache.h b/libcutils/arch-x86_64/cache.h deleted file mode 100644 index f1443093909e..000000000000 --- a/libcutils/arch-x86_64/cache.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -/* Values are optimized for Silvermont */ -#define SHARED_CACHE_SIZE (1024*1024) /* Silvermont L2 Cache */ -#define DATA_CACHE_SIZE (24*1024) /* Silvermont L1 Data Cache */ - -#define SHARED_CACHE_SIZE_HALF (SHARED_CACHE_SIZE / 2) -#define DATA_CACHE_SIZE_HALF (DATA_CACHE_SIZE / 2) From 1faedd02a3d1c392136cfcdb38afa698721a7d6f Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 22 Sep 2023 14:45:20 +0000 Subject: [PATCH 0406/1487] Remove redefinition of uapi constant added in R. Test: treehugger Change-Id: If0ef9c36b2f54eb59d222dedc6bf575d46c9db1d --- libcutils/ashmem-dev.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp index 6a27f9a2004b..5e01da9b890b 100644 --- a/libcutils/ashmem-dev.cpp +++ b/libcutils/ashmem-dev.cpp @@ -44,9 +44,6 @@ #include #include -/* Will be added to UAPI once upstream change is merged */ -#define F_SEAL_FUTURE_WRITE 0x0010 - /* * The minimum vendor API level at and after which it is safe to use memfd. * This is to facilitate deprecation of ashmem. From 3369fe9cbb0cce75ff61fbfaac5aaa83dff0b6a7 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 22 Sep 2023 14:51:26 +0000 Subject: [PATCH 0407/1487] Don't duplicate uapi ioprio constants. This code is only used in init and vold, so I suspect all the conditional compilation could be moved into the .bp file instead, but I'm just trying to clean up duplication today... Test: treehugger Change-Id: I97013f5de41e109a0cc377400c396145aed569db --- libcutils/iosched_policy.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libcutils/iosched_policy.cpp b/libcutils/iosched_policy.cpp index 012c537ac688..f7c724da900b 100644 --- a/libcutils/iosched_policy.cpp +++ b/libcutils/iosched_policy.cpp @@ -24,8 +24,7 @@ #include #if defined(__ANDROID__) -#define IOPRIO_WHO_PROCESS (1) -#define IOPRIO_CLASS_SHIFT (13) +#include #include #define __android_unused #else From f6a84e4462c8425869093f26f7e83bc1cb24ee70 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 22 Sep 2023 14:37:37 +0000 Subject: [PATCH 0408/1487] Remove Windows workaround in file not built for Windows. Test: treehugger Change-Id: I311cfbc9245cbe90ed6fc4fa379ff5b9abdf21e7 --- libcutils/fs_config.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp index 26ac576070fc..919be2ff2a0b 100644 --- a/libcutils/fs_config.cpp +++ b/libcutils/fs_config.cpp @@ -41,10 +41,6 @@ #include "fs_config.h" -#ifndef O_BINARY -#define O_BINARY 0 -#endif - using android::base::EndsWith; using android::base::StartsWith; @@ -257,12 +253,12 @@ static int fs_config_open(int dir, int which, const char* target_out_path) { len = strip(target_out_path, len, "/"); len = strip(target_out_path, len, "/system"); if (asprintf(&name, "%.*s%s", (int)len, target_out_path, conf[which][dir]) != -1) { - fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_BINARY)); + fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY)); free(name); } } if (fd < 0) { - fd = TEMP_FAILURE_RETRY(open(conf[which][dir], O_RDONLY | O_BINARY)); + fd = TEMP_FAILURE_RETRY(open(conf[which][dir], O_RDONLY)); } return fd; } From b4987345ff1f97d529cc23b03ca73b58ff7a7e1b Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Thu, 21 Sep 2023 15:52:19 -0700 Subject: [PATCH 0409/1487] Only skip _16k/_64k kernel modules dirs on 4K builds The initramfs.img from kernel builds do not store kernel modules under _16k directory. Currently, init is programmed to only load kernel modules from _16k dir if running on 16K page size kernel. Relax this restriction so that booting on custom 16K kernel would work without going through platform rebuild. Test: th Bug: 293313353 Bug: 300184677 Change-Id: I9ee3c74066ad9ec5127f1e8662f7c1273445994c --- init/first_stage_init.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index c6a287ab6278..e48fa155420f 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -239,8 +239,12 @@ bool LoadKernelModules(BootMode boot_mode, bool want_console, bool want_parallel module_dirs.emplace_back(entry->d_name); break; } - // Ignore _16k/_64k module dirs on 4K kernels - if (GetPageSizeSuffix(entry->d_name) != page_size_suffix) { + // Is a directory does not have page size suffix, it does not mean this directory is for 4K + // kernels. Certain 16K kernel builds put all modules in /lib/modules/`uname -r` without any + // suffix. Therefore, only ignore a directory if it has _16k/_64k suffix and the suffix does + // not match system page size. + const auto dir_page_size_suffix = GetPageSizeSuffix(entry->d_name); + if (!dir_page_size_suffix.empty() && dir_page_size_suffix != page_size_suffix) { continue; } int dir_major = 0, dir_minor = 0; From 5cbcdfae4ec2cfd9ff1f90ecb363504d97b81875 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Thu, 21 Sep 2023 18:27:09 -0700 Subject: [PATCH 0410/1487] is_retrofit_device to work in bootloader Changing is_retrofit_device() to work in bootloader. Previously flashall flow was to boot into fastbootd and then make a call to get "super-image-name", however this does not work in bootloader. Since all tasks are generated ahead of time, this old check will now fail and we will fail to add the correct delete tasks in collectTasks(). This change does make it so that is_retrofit check only works during fastboot flashall + fastboot update (since this function is only used here, nothing is currently affected). To determine if a device is retrofit, it must satisfy two conditions -> Has dynamic partitions && does not contain a super partition. The check for if source has super_empty.img is sufficient for determining if a device has dynamic partitions and if any single partition has LP_PARTITION_ATTR_SLOT_SUFFIXED it is determined to be retrofit Test: logs from fastboot update on sargo device confirms this check returns true. Fastboot update on sargo Bug: 300287332 Change-Id: Iadf5c56de51993a79307c60e45d6cc4988436f23 --- fastboot/fastboot.cpp | 17 ++++++++++++----- fastboot/fastboot.h | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 080ad4261a49..63f78435923e 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1413,12 +1413,19 @@ void do_for_partitions(const std::string& part, const std::string& slot, } } -bool is_retrofit_device(fastboot::IFastBootDriver* fb) { - std::string value; - if (fb->GetVar("super-partition-name", &value) != fastboot::SUCCESS) { +bool is_retrofit_device(const ImageSource* source) { + // Does this device use dynamic partitions at all? + std::vector contents; + if (!source->ReadFile("super_empty.img", &contents)) { return false; } - return android::base::StartsWith(value, "system_"); + auto metadata = android::fs_mgr::ReadFromImageBlob(contents.data(), contents.size()); + for (const auto& partition : metadata->partitions) { + if (partition.attributes & LP_PARTITION_ATTR_SLOT_SUFFIXED) { + return true; + } + } + return false; } // Fetch a partition from the device to a given fd. This is a wrapper over FetchToFd to fetch @@ -1876,7 +1883,7 @@ std::vector> FlashAllTool::CollectTasksFromImageList() { // On these devices, secondary slots must be flashed as physical // partitions (otherwise they would not mount on first boot). To enforce // this, we delete any logical partitions for the "other" slot. - if (is_retrofit_device(fp_->fb)) { + if (is_retrofit_device(fp_->source)) { std::string partition_name = image->part_name + "_" + slot; if (image->IsSecondary() && should_flash_in_userspace(partition_name)) { tasks.emplace_back(std::make_unique(fp_, partition_name)); diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index 35deea7d2a96..eead82c92f8e 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -187,7 +187,7 @@ int64_t get_sparse_limit(int64_t size, const FlashingPlan* fp); std::vector resparse_file(sparse_file* s, int64_t max_size); bool supports_AB(fastboot::IFastBootDriver* fb); -bool is_retrofit_device(fastboot::IFastBootDriver* fb); +bool is_retrofit_device(const ImageSource* source); bool is_logical(const std::string& partition); void fb_perform_format(const std::string& partition, int skip_if_not_supported, const std::string& type_override, const std::string& size_override, From 810274071da6be521d9e198bf6fde64afd1fd077 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Sat, 23 Sep 2023 01:07:47 -0700 Subject: [PATCH 0411/1487] Create_cow: Hash of target blocks should not be stored. Target block hash was in-correctly getting added to map thereby overriding the source-hash. Bug: 299011882 Test: Flash Pixel 6 Pro from A->B and from B->A Change-Id: Ib3887c29cd6b8f2abd50e932273a5cfc2a096bd5 Signed-off-by: Akilesh Kailash --- fs_mgr/libsnapshot/libsnapshot_cow/create_cow.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/create_cow.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/create_cow.cpp index 4e07fe3b3e0b..efb1035c2524 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/create_cow.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/create_cow.cpp @@ -240,9 +240,11 @@ bool CreateSnapshot::ReadBlocks(off_t offset, const int skip_blocks, const uint6 SHA256(bufptr, BLOCK_SZ, checksum); std::string hash = ToHexString(checksum, sizeof(checksum)); - if (create_snapshot_patch_ && !WriteSnapshot(bufptr, blkindex, hash)) { - LOG(ERROR) << "WriteSnapshot failed for block: " << blkindex; - return false; + if (create_snapshot_patch_) { + if (!WriteSnapshot(bufptr, blkindex, hash)) { + LOG(ERROR) << "WriteSnapshot failed for block: " << blkindex; + return false; + } } else { std::lock_guard lock(source_block_hash_lock_); { @@ -256,7 +258,7 @@ bool CreateSnapshot::ReadBlocks(off_t offset, const int skip_blocks, const uint6 num_blocks -= 1; } - file_offset += (skip_blocks * kBlockSizeToRead); + file_offset += (skip_blocks * to_read); if (file_offset >= dev_sz) { break; } From 45d88d496eeef3bbdd0b54a2b0c1618b81d533a4 Mon Sep 17 00:00:00 2001 From: Kiyoung Kim Date: Thu, 21 Sep 2023 16:03:41 +0900 Subject: [PATCH 0412/1487] Do not check with vendor vndk version Current libcutils checks if memfd is supported with vendor VNDK version, but this is no longer valid if VNDK is deprecated. As we can assume that any vendor using this code is supported as long as it is treblelized, simplify logic to check if memfd is valid to vendor only with 'ro.treble.enabled' property. Bug: 290159430 Test: Cuttlefish with VNDK deprecated worked without error from libcutils Change-Id: I351f0798da99cb4827bc3e424b63a2eaee5c7461 --- libcutils/ashmem-dev.cpp | 57 +++++----------------------------------- 1 file changed, 6 insertions(+), 51 deletions(-) diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp index 5e01da9b890b..410dbfd5e05f 100644 --- a/libcutils/ashmem-dev.cpp +++ b/libcutils/ashmem-dev.cpp @@ -44,13 +44,6 @@ #include #include -/* - * The minimum vendor API level at and after which it is safe to use memfd. - * This is to facilitate deprecation of ashmem. - */ -#define MIN_MEMFD_VENDOR_API_LEVEL 29 -#define MIN_MEMFD_VENDOR_API_LEVEL_CHAR 'Q' - /* ashmem identity */ static dev_t __ashmem_rdev; /* @@ -88,55 +81,17 @@ static bool pin_deprecation_warn = true; /* Log the pin deprecation warning only /* Determine if vendor processes would be ok with memfd in the system: * - * If VNDK is using older libcutils, don't use memfd. This is so that the - * same shared memory mechanism is used across binder transactions between - * vendor partition processes and system partition processes. + * Previously this function checked if memfd is supported by checking if + * vendor VNDK version is greater than Q. As we can assume all treblelized + * device using this code is up to date enough to use memfd, memfd is allowed + * if the device is treblelized. */ static bool check_vendor_memfd_allowed() { - std::string vndk_version = android::base::GetProperty("ro.vndk.version", ""); - - if (vndk_version == "") { - ALOGE("memfd: ro.vndk.version not defined or invalid (%s), this is mandated since P.\n", - vndk_version.c_str()); - return false; - } - - /* No issues if vendor is targetting current Dessert */ - if (vndk_version == "current") { - return false; - } - - /* Check if VNDK version is a number and act on it */ - char* p; - long int vers = strtol(vndk_version.c_str(), &p, 10); - if (*p == 0) { - if (vers < MIN_MEMFD_VENDOR_API_LEVEL) { - ALOGI("memfd: device VNDK version (%s) is < Q so using ashmem.\n", - vndk_version.c_str()); - return false; - } + static bool is_treblelized = android::base::GetBoolProperty("ro.treble.enabled", false); - return true; - } - - // Non-numeric should be a single ASCII character. Characters after the - // first are ignored. - if (tolower(vndk_version[0]) < 'a' || tolower(vndk_version[0]) > 'z') { - ALOGE("memfd: ro.vndk.version not defined or invalid (%s), this is mandated since P.\n", - vndk_version.c_str()); - return false; - } - - if (tolower(vndk_version[0]) < tolower(MIN_MEMFD_VENDOR_API_LEVEL_CHAR)) { - ALOGI("memfd: device is using VNDK version (%s) which is less than Q. Use ashmem only.\n", - vndk_version.c_str()); - return false; - } - - return true; + return is_treblelized; } - /* Determine if memfd can be supported. This is just one-time hardwork * which will be cached by the caller. */ From a6b5f94687676032028ae9c72d324bda9ced06f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=C3=A9baud=20Weksteen?= Date: Mon, 25 Sep 2023 16:07:47 +1000 Subject: [PATCH 0413/1487] Skip /metadata/sepolicy creation Bug: 297794885 Test: presubmit Change-Id: I93f94f319d0f86e1cad6f2a4912b5df3aae09cec --- rootdir/init.rc | 1 - 1 file changed, 1 deletion(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 487e5da44953..8eec16c9b4f1 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -610,7 +610,6 @@ on post-fs restorecon_recursive /metadata/apex mkdir /metadata/staged-install 0770 root system - mkdir /metadata/sepolicy 0700 root root on late-fs # Ensure that tracefs has the correct permissions. # This does not work correctly if it is called in post-fs. From 94ccdc06d0bb9725441c7340a2d1606bb32fa303 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 22 Sep 2023 18:44:28 +0000 Subject: [PATCH 0414/1487] Stop duplicating . This doesn't help the person who wants CAP_BPF, but we can fix that better by adding it to our stale glibc (and our future switch to musl will mean we'll never have similar problems again). I think this just dates from when we still supported building the OS on darwin, but those days are long gone, and I think this hack can be put to rest now... Test: treehugger Change-Id: I3c2e56c68a5b00c1ad0aed422c6ce60886063f50 --- libcutils/Android.bp | 10 +- .../private/android_filesystem_capability.h | 119 ------------------ libcutils/include/private/fs_config.h | 4 - 3 files changed, 6 insertions(+), 127 deletions(-) delete mode 100644 libcutils/include/private/android_filesystem_capability.h diff --git a/libcutils/Android.bp b/libcutils/Android.bp index 55a8694ffc31..8ae7d9e5922f 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -171,11 +171,15 @@ cc_library { "libasync_safe", ], }, + linux: { + srcs: [ + "canned_fs_config.cpp", + "fs_config.cpp", + ], + }, not_windows: { srcs: libcutils_nonwindows_sources + [ "ashmem-host.cpp", - "canned_fs_config.cpp", - "fs_config.cpp", "trace-host.cpp", ], }, @@ -201,8 +205,6 @@ cc_library { srcs: libcutils_nonwindows_sources + [ "android_reboot.cpp", "ashmem-dev.cpp", - "canned_fs_config.cpp", - "fs_config.cpp", "klog.cpp", "partition_utils.cpp", "qtaguid.cpp", diff --git a/libcutils/include/private/android_filesystem_capability.h b/libcutils/include/private/android_filesystem_capability.h deleted file mode 100644 index 0227b1de8702..000000000000 --- a/libcutils/include/private/android_filesystem_capability.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -/* - * Taken from linux/capability.h, with minor modifications - */ - -#ifndef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_FILESYSTEM_CAPABILITY_H -#define _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_FILESYSTEM_CAPABILITY_H - -#include - -#define __user -#define __u32 uint32_t -#define __le32 uint32_t - -#define _LINUX_CAPABILITY_VERSION_1 0x19980330 -#define _LINUX_CAPABILITY_U32S_1 1 -#define _LINUX_CAPABILITY_VERSION_2 0x20071026 -#define _LINUX_CAPABILITY_U32S_2 2 -#define _LINUX_CAPABILITY_VERSION_3 0x20080522 -#define _LINUX_CAPABILITY_U32S_3 2 - -typedef struct __user_cap_header_struct { - __u32 version; - int pid; -} __user* cap_user_header_t; - -typedef struct __user_cap_data_struct { - __u32 effective; - __u32 permitted; - __u32 inheritable; -} __user* cap_user_data_t; - -#define VFS_CAP_REVISION_MASK 0xFF000000 -#define VFS_CAP_REVISION_SHIFT 24 -#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK -#define VFS_CAP_FLAGS_EFFECTIVE 0x000001 -#define VFS_CAP_REVISION_1 0x01000000 -#define VFS_CAP_U32_1 1 -#define XATTR_CAPS_SZ_1 (sizeof(__le32) * (1 + 2 * VFS_CAP_U32_1)) -#define VFS_CAP_REVISION_2 0x02000000 -#define VFS_CAP_U32_2 2 -#define XATTR_CAPS_SZ_2 (sizeof(__le32) * (1 + 2 * VFS_CAP_U32_2)) -#define XATTR_CAPS_SZ XATTR_CAPS_SZ_2 -#define VFS_CAP_U32 VFS_CAP_U32_2 -#define VFS_CAP_REVISION VFS_CAP_REVISION_2 - -struct vfs_cap_data { - __le32 magic_etc; - struct { - __le32 permitted; - __le32 inheritable; - } data[VFS_CAP_U32]; -}; - -#define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_1 -#define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_1 -#define CAP_CHOWN 0 -#define CAP_DAC_OVERRIDE 1 -#define CAP_DAC_READ_SEARCH 2 -#define CAP_FOWNER 3 -#define CAP_FSETID 4 -#define CAP_KILL 5 -#define CAP_SETGID 6 -#define CAP_SETUID 7 -#define CAP_SETPCAP 8 -#define CAP_LINUX_IMMUTABLE 9 -#define CAP_NET_BIND_SERVICE 10 -#define CAP_NET_BROADCAST 11 -#define CAP_NET_ADMIN 12 -#define CAP_NET_RAW 13 -#define CAP_IPC_LOCK 14 -#define CAP_IPC_OWNER 15 -#define CAP_SYS_MODULE 16 -#define CAP_SYS_RAWIO 17 -#define CAP_SYS_CHROOT 18 -#define CAP_SYS_PTRACE 19 -#define CAP_SYS_PACCT 20 -#define CAP_SYS_ADMIN 21 -#define CAP_SYS_BOOT 22 -#define CAP_SYS_NICE 23 -#define CAP_SYS_RESOURCE 24 -#define CAP_SYS_TIME 25 -#define CAP_SYS_TTY_CONFIG 26 -#define CAP_MKNOD 27 -#define CAP_LEASE 28 -#define CAP_AUDIT_WRITE 29 -#define CAP_AUDIT_CONTROL 30 -#define CAP_SETFCAP 31 -#define CAP_MAC_OVERRIDE 32 -#define CAP_MAC_ADMIN 33 -#define CAP_SYSLOG 34 -#define CAP_WAKE_ALARM 35 -#define CAP_BLOCK_SUSPEND 36 -#define CAP_AUDIT_READ 37 -#define CAP_LAST_CAP CAP_AUDIT_READ -#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP) -#define CAP_TO_INDEX(x) ((x) >> 5) -#define CAP_TO_MASK(x) (1 << ((x)&31)) - -#undef __user -#undef __u32 -#undef __le32 - -#endif diff --git a/libcutils/include/private/fs_config.h b/libcutils/include/private/fs_config.h index 8a9a1ffd7700..45f46e5494da 100644 --- a/libcutils/include/private/fs_config.h +++ b/libcutils/include/private/fs_config.h @@ -24,11 +24,7 @@ #include #include -#if defined(__BIONIC__) #include -#else // defined(__BIONIC__) -#include -#endif // defined(__BIONIC__) /* Rules for directories and files has moved to system/code/libcutils/fs_config.c */ From 589c8d1e44cff96092c943f22cc10a9c23b81c01 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Sun, 30 Jul 2023 05:31:46 +0000 Subject: [PATCH 0415/1487] rpc_binder: Change `trusty_tipc_fuzzer` to support multiple connections and messages This changes `trusty_tipc_fuzzer` to be more like the existing binder rpc_fuzzer, which opens and closes multiple connections and sends multiple messages in a single fuzz input. The max number of connections is controlled by the define `TRUSTY_APP_MAX_CONNECTIONS`, which defaults to `1`, thus keeping the existing behavior for now. In the next CL, I'll add more fuzzers with `-DTRUSTY_APP_MAX_CONNECTIONS=10` instead. Test: Build and run in trusty emulator Change-Id: I9692e4d0295052a8da2204f63be9e52939e70ac3 --- trusty/fuzz/tipc_fuzzer.cpp | 79 ++++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/trusty/fuzz/tipc_fuzzer.cpp b/trusty/fuzz/tipc_fuzzer.cpp index f265cedb698f..edc2a79a5260 100644 --- a/trusty/fuzz/tipc_fuzzer.cpp +++ b/trusty/fuzz/tipc_fuzzer.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include +#include #include #include #include @@ -23,6 +25,7 @@ #include #include +using android::base::Result; using android::trusty::coverage::CoverageRecord; using android::trusty::fuzz::ExtraCounters; using android::trusty::fuzz::TrustyApp; @@ -41,7 +44,14 @@ using android::trusty::fuzz::TrustyApp; #error "Binary file name must be parameterized using -DTRUSTY_APP_FILENAME." #endif -static TrustyApp kTrustyApp(TIPC_DEV, TRUSTY_APP_PORT); +#ifdef TRUSTY_APP_MAX_CONNECTIONS +constexpr size_t MAX_CONNECTIONS = TRUSTY_APP_MAX_CONNECTIONS; +#else +constexpr size_t MAX_CONNECTIONS = 1; +#endif + +static_assert(MAX_CONNECTIONS >= 1); + static std::unique_ptr record; extern "C" int LLVMFuzzerInitialize(int* /* argc */, char*** /* argv */) { @@ -53,7 +63,8 @@ extern "C" int LLVMFuzzerInitialize(int* /* argc */, char*** /* argv */) { } /* Make sure lazy-loaded TAs have started and connected to coverage service. */ - auto ret = kTrustyApp.Connect(); + TrustyApp ta(TIPC_DEV, TRUSTY_APP_PORT); + auto ret = ta.Connect(); if (!ret.ok()) { std::cerr << ret.error() << std::endl; exit(-1); @@ -73,24 +84,56 @@ extern "C" int LLVMFuzzerInitialize(int* /* argc */, char*** /* argv */) { return 0; } -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - static uint8_t buf[TIPC_MAX_MSG_SIZE]; +Result testOneInput(FuzzedDataProvider& provider) { + std::vector trustyApps; + + while (provider.remaining_bytes() > 0) { + if (trustyApps.size() < MAX_CONNECTIONS && provider.ConsumeBool()) { + auto& ta = trustyApps.emplace_back(TIPC_DEV, TRUSTY_APP_PORT); + const auto result = ta.Connect(); + if (!result.ok()) { + return result; + } + } else { + const auto i = provider.ConsumeIntegralInRange(0, trustyApps.size()); + std::swap(trustyApps[i], trustyApps.back()); + + if (provider.ConsumeBool()) { + auto& ta = trustyApps.back(); + + const auto data = provider.ConsumeRandomLengthString(); + auto result = ta.Write(data.data(), data.size()); + if (!result.ok()) { + return result; + } + + std::array buf; + result = ta.Read(buf.data(), buf.size()); + if (!result.ok()) { + return result; + } + + // Reconnect to ensure that the service is still up. + ta.Disconnect(); + result = ta.Connect(); + if (!result.ok()) { + std::cerr << result.error() << std::endl; + android::trusty::fuzz::Abort(); + return result; + } + } else { + trustyApps.pop_back(); + } + } + } + return {}; +} +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { ExtraCounters counters(record.get()); counters.Reset(); - auto ret = kTrustyApp.Write(data, size); - if (ret.ok()) { - ret = kTrustyApp.Read(&buf, sizeof(buf)); - } - - // Reconnect to ensure that the service is still up - kTrustyApp.Disconnect(); - ret = kTrustyApp.Connect(); - if (!ret.ok()) { - std::cerr << ret.error() << std::endl; - android::trusty::fuzz::Abort(); - } - - return ret.ok() ? 0 : -1; + FuzzedDataProvider provider(data, size); + const auto result = testOneInput(provider); + return result.ok() ? 0 : -1; } From d7c55110956b329b5d314aa851c923e7f1fe3e1e Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 26 Sep 2023 12:27:33 -0700 Subject: [PATCH 0416/1487] Add binary to write basic COW Adding small binary to write a simple COW for version 2. We will then use updated reader to make sure we can read this version 2 cow. Think it would be a good idea to keep the binary here to see how exactly we generated the cow (useful for debugging and if we ever need to recreate this cow) Test: m basic_v2_cow_writer Change-Id: I28435025b7a8280fc5c4574876cc9110b391cb0e --- fs_mgr/libsnapshot/tools/Android.bp | 23 +++++++++ .../libsnapshot/tools/basic_v2_cow_writer.cpp | 48 ++++++++++++++++++ fs_mgr/libsnapshot/tools/testdata/cow_v2 | Bin 0 -> 2105826 bytes 3 files changed, 71 insertions(+) create mode 100644 fs_mgr/libsnapshot/tools/basic_v2_cow_writer.cpp create mode 100644 fs_mgr/libsnapshot/tools/testdata/cow_v2 diff --git a/fs_mgr/libsnapshot/tools/Android.bp b/fs_mgr/libsnapshot/tools/Android.bp index cfa0cefe764c..0f0828699dc7 100644 --- a/fs_mgr/libsnapshot/tools/Android.bp +++ b/fs_mgr/libsnapshot/tools/Android.bp @@ -20,3 +20,26 @@ cc_binary { cflags: ["-Werror"], } + + +cc_binary { + name: "basic_v2_cow_writer", + host_supported: true, + defaults: [ + "fs_mgr_defaults", + "libsnapshot_cow_defaults", + ], + + srcs: ["basic_v2_cow_writer.cpp"], + + static_libs: [ + "libsnapshot_cow", + ], + + shared_libs: [ + "libbase", + "liblog", + ], + + cflags: ["-Werror"], +} diff --git a/fs_mgr/libsnapshot/tools/basic_v2_cow_writer.cpp b/fs_mgr/libsnapshot/tools/basic_v2_cow_writer.cpp new file mode 100644 index 000000000000..59d35399aedb --- /dev/null +++ b/fs_mgr/libsnapshot/tools/basic_v2_cow_writer.cpp @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include + +#include "android-base/unique_fd.h" + +using namespace android::snapshot; + +// This writes a simple cow v2 file in the current directory. This file will serve as testdata for +// ensuring our v3 cow reader will be able to read a cow file created by the v2 writer. +// +// WARNING: We should not be overriding this test file, as it will serve as historic marker for what +// a device with old writer_v2 will write as a cow. +void write_cow_v2() { + 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'); + + char cwd_buffer[1024]; + size_t cwd_buffer_size = sizeof(cwd_buffer); + + // Get the current working directory path. + char* err = getcwd(cwd_buffer, cwd_buffer_size); + if (!err) { + LOG(ERROR) << "Couldn't get current directory"; + } + android::base::unique_fd fd(open(strcat(cwd_buffer, "/cow_v2"), O_CREAT | O_RDWR, 0666)); + if (fd.get() == -1) { + LOG(FATAL) << "couldn't open tmp_cow"; + } + std::unique_ptr writer = CreateCowWriter(2, options, std::move(fd)); + writer->AddCopy(0, 5); + writer->AddRawBlocks(2, data.data(), data.size()); + writer->AddLabel(1); + writer->AddXorBlocks(50, data.data(), data.size(), 24, 10); + writer->AddZeroBlocks(5, 10); + writer->AddLabel(2); + writer->Finalize(); +} + +int main() { + write_cow_v2(); +} diff --git a/fs_mgr/libsnapshot/tools/testdata/cow_v2 b/fs_mgr/libsnapshot/tools/testdata/cow_v2 new file mode 100644 index 0000000000000000000000000000000000000000..9f37dfc50c5550a2ed796d046ab52b3f6960d05b GIT binary patch literal 2105826 zcmeI&yGjE=6b9gvXuQM=L41HsV`b$N2tI&Kz&h$e0!oSmZLNK2oxMRaL=YPZe8X;L z=if6s%ePfv#^ZnuoP$(% z)8@mECheY4$3=5+O|Of`@?~DWmBoD3&estjK!5-N0t5&UAV7cs z0Rp=%;Q#+_e?MSiN_6`uzT!4!?Z%0Vtp2aVZ!rKH(EtDd literal 0 HcmV?d00001 From 301acae35b35d97171a4d316e02a90b3c24181e4 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 26 Sep 2023 16:43:41 -0700 Subject: [PATCH 0417/1487] Add copyright to libsnapshot/tools Adding copyright to cow_benchmark + basic_v2_cow_writer Test: th Change-Id: Ic6c32b68bbeaa3c0c365f146ef4342356e13706a --- fs_mgr/libsnapshot/tools/basic_v2_cow_writer.cpp | 15 +++++++++++++++ fs_mgr/libsnapshot/tools/cow_benchmark.cpp | 16 +++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/fs_mgr/libsnapshot/tools/basic_v2_cow_writer.cpp b/fs_mgr/libsnapshot/tools/basic_v2_cow_writer.cpp index 59d35399aedb..72fb0f547b6a 100644 --- a/fs_mgr/libsnapshot/tools/basic_v2_cow_writer.cpp +++ b/fs_mgr/libsnapshot/tools/basic_v2_cow_writer.cpp @@ -1,3 +1,18 @@ +// +// Copyright (C) 2023 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 #include #include diff --git a/fs_mgr/libsnapshot/tools/cow_benchmark.cpp b/fs_mgr/libsnapshot/tools/cow_benchmark.cpp index da2b87922927..4d5e346c4cd4 100644 --- a/fs_mgr/libsnapshot/tools/cow_benchmark.cpp +++ b/fs_mgr/libsnapshot/tools/cow_benchmark.cpp @@ -1,4 +1,18 @@ - +// +// Copyright (C) 2023 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 #include From 7a8f82acbd3c24ce5ecc7e57d633576b74af30e9 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Thu, 21 Sep 2023 20:37:47 -0700 Subject: [PATCH 0418/1487] should_flash_in_userspace signature change We should change should_flash_in_userspace to work without $ANDROID_PRODUCT_OUT being set and fall back on $OUT directory when source isn't specified This also fixes the flashing issue of flashing retrofit devices without $ANDROID_PRODUCT_OUT set. If we call fastboot update on a retrofit device, copy_avb_footer will resize buf->sz of secondary partitions to the partition size, causing us to send the unsparsed payload to the device -> "Invalid Size" issue. This is because secondary partitions are considered physical partitions on retrofit devices && should_flash_in_userspace wouldn't work if $ANDROID_PRODUCT_OUT is set, so our first return clause in copy_avb_footer doesn't catch this edge case causing us to resize the buf-> sz incorrectly. Did some testing, and also observed a case where flashing is able to succeed despite $ANDROID_PRODUCT_OUT not being set before, so there might still be some other edge case that we are still missing. Test: fastboot update on sargo without $ANDROID_PRODUCT_OUT Change-Id: I0e4781d96709b712f7d71657ec0d16d99b90214d --- fastboot/fastboot.cpp | 48 ++++++++++++++++++++++++++----------------- fastboot/fastboot.h | 2 +- fastboot/task.cpp | 3 ++- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 63f78435923e..3ce81417958f 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1185,9 +1185,10 @@ static uint64_t get_partition_size(const std::string& partition) { return partition_size; } -static void copy_avb_footer(const std::string& partition, struct fastboot_buffer* buf) { +static void copy_avb_footer(const ImageSource* source, const std::string& partition, + struct fastboot_buffer* buf) { if (buf->sz < AVB_FOOTER_SIZE || is_logical(partition) || - should_flash_in_userspace(partition)) { + should_flash_in_userspace(source, partition)) { return; } // If overflows and negative, it should be < buf->sz. @@ -1244,9 +1245,9 @@ void flash_partition_files(const std::string& partition, const std::vectorResizePartition(pname, std::to_string(buf.image_size)); } std::string flash_pname = repack_ramdisk(pname, &buf, fp->fb); - flash_buf(flash_pname, &buf, apply_vbmeta); + flash_buf(fp->source, flash_pname, &buf, apply_vbmeta); } // Sets slot_override as the active slot. If slot_override is blank, @@ -1807,9 +1808,9 @@ std::vector> FlashAllTool::CollectTasks() { tasks = CollectTasksFromImageList(); } if (fp_->exclude_dynamic_partitions) { - auto is_non_static_flash_task = [](const auto& task) -> bool { + auto is_non_static_flash_task = [&](const auto& task) -> bool { if (auto flash_task = task->AsFlashTask()) { - if (!should_flash_in_userspace(flash_task->GetPartitionAndSlot())) { + if (!should_flash_in_userspace(fp_->source, flash_task->GetPartitionAndSlot())) { return false; } } @@ -1885,7 +1886,7 @@ std::vector> FlashAllTool::CollectTasksFromImageList() { // this, we delete any logical partitions for the "other" slot. if (is_retrofit_device(fp_->source)) { std::string partition_name = image->part_name + "_" + slot; - if (image->IsSecondary() && should_flash_in_userspace(partition_name)) { + if (image->IsSecondary() && should_flash_in_userspace(fp_->source, partition_name)) { tasks.emplace_back(std::make_unique(fp_, partition_name)); } } @@ -2087,7 +2088,8 @@ void fb_perform_format(const std::string& partition, int skip_if_not_supported, if (!load_buf_fd(std::move(fd), &buf, fp)) { die("Cannot read image: %s", strerror(errno)); } - flash_buf(partition, &buf, is_vbmeta_partition(partition)); + + flash_buf(fp->source, partition, &buf, is_vbmeta_partition(partition)); return; failed: @@ -2101,18 +2103,26 @@ void fb_perform_format(const std::string& partition, int skip_if_not_supported, } } -bool should_flash_in_userspace(const std::string& partition_name) { - if (!get_android_product_out()) { - return false; - } - auto path = find_item_given_name("super_empty.img"); - if (path.empty() || access(path.c_str(), R_OK)) { - return false; +bool should_flash_in_userspace(const ImageSource* source, const std::string& partition_name) { + if (!source) { + if (!get_android_product_out()) { + return false; + } + auto path = find_item_given_name("super_empty.img"); + if (path.empty() || access(path.c_str(), R_OK)) { + return false; + } + auto metadata = android::fs_mgr::ReadFromImageFile(path); + if (!metadata) { + return false; + } + return should_flash_in_userspace(*metadata.get(), partition_name); } - auto metadata = android::fs_mgr::ReadFromImageFile(path); - if (!metadata) { + std::vector contents; + if (!source->ReadFile("super_empty.img", &contents)) { return false; } + auto metadata = android::fs_mgr::ReadFromImageBlob(contents.data(), contents.size()); return should_flash_in_userspace(*metadata.get(), partition_name); } diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index eead82c92f8e..4859cebc2895 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -148,7 +148,7 @@ class LocalImageSource final : public ImageSource { }; char* get_android_product_out(); -bool should_flash_in_userspace(const std::string& partition_name); +bool should_flash_in_userspace(const ImageSource* source, const std::string& partition_name); bool is_userspace_fastboot(); void do_flash(const char* pname, const char* fname, const bool apply_vbmeta, const FlashingPlan* fp); diff --git a/fastboot/task.cpp b/fastboot/task.cpp index f13dd55b35be..4b2b9e316cc8 100644 --- a/fastboot/task.cpp +++ b/fastboot/task.cpp @@ -41,7 +41,8 @@ bool FlashTask::IsDynamicParitition(const ImageSource* source, const FlashTask* void FlashTask::Run() { auto flash = [&](const std::string& partition) { - if (should_flash_in_userspace(partition) && !is_userspace_fastboot() && !fp_->force_flash) { + if (should_flash_in_userspace(fp_->source, partition) && !is_userspace_fastboot() && + !fp_->force_flash) { die("The partition you are trying to flash is dynamic, and " "should be flashed via fastbootd. Please run:\n" "\n" From 566f1371e4d6ee2b7bc2d027c93d51d08e8b5c20 Mon Sep 17 00:00:00 2001 From: Kiyoung Kim Date: Wed, 27 Sep 2023 10:02:23 +0900 Subject: [PATCH 0419/1487] Remove libbinder_rpc_unstable from system required libs libbinder_rpc_unstable is in the list of system required libs, but the library is already located in the system/{LIB}, and this creates link to the self namespace. Remove libbinder_rpc_unstable from system required libs as it doesn't make sense to have require and provide same library in a single image. Bug: 298333253 Test: Cuttlefish build and boot succeded Change-Id: Idb40e1dbc1053d4882093c188a36b2cc8d86e918 --- rootdir/etc/linker.config.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/rootdir/etc/linker.config.json b/rootdir/etc/linker.config.json index 47f77b198cc0..d72ac66813dd 100644 --- a/rootdir/etc/linker.config.json +++ b/rootdir/etc/linker.config.json @@ -11,9 +11,6 @@ "libsigchain.so", // TODO(b/122876336): Remove libpac.so once it's migrated to Webview "libpac.so", - // TODO(b/184872979): Remove libbinder_rpc_unstable.so once stablized and - // added to libbinder_ndk. - "libbinder_rpc_unstable.so", // TODO(b/120786417 or b/134659294): libicuuc.so // and libicui18n.so are kept for app compat. "libicui18n.so", From 6a12d23eabdfba1bf99016da328b515ae2b5559f Mon Sep 17 00:00:00 2001 From: Snehal Date: Wed, 27 Sep 2023 12:08:45 +0000 Subject: [PATCH 0420/1487] Remove ambgiuity in format specifier Bug: 302163991 Test: m trusty-coverage-controller Change-Id: I26318eeb4a6770bd01d3c677ca3cf5c76ce33fa0 --- trusty/utils/coverage-controller/controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trusty/utils/coverage-controller/controller.cpp b/trusty/utils/coverage-controller/controller.cpp index 0047046d7566..381a45285c2c 100644 --- a/trusty/utils/coverage-controller/controller.cpp +++ b/trusty/utils/coverage-controller/controller.cpp @@ -54,7 +54,7 @@ void Controller::run(std::string output_dir) { if (complete_cnt != counters[index] && start_cnt == complete_cnt) { WRITE_ONCE(control->cntrl_flags, FLAG_NONE); std::string filename; - filename = android::base::StringPrintf("/%s.%lu.profraw", + filename = android::base::StringPrintf("/%s.%" PRIu64 ".profraw", uuid_list_[index].c_str(), counters[index]); filename.insert(0, output_dir); From 5ebc6573863624c98b42cff59244f94614b3e23f Mon Sep 17 00:00:00 2001 From: Steve Muckle Date: Wed, 16 Aug 2023 17:16:50 +0000 Subject: [PATCH 0421/1487] disable sync_on_suspend when flag is set Bug: 285395636 Test: suspend/resume testing Change-Id: I2d97d8366b864ab3e72d7ae38a0f4906dc74ec6f --- rootdir/init.rc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rootdir/init.rc b/rootdir/init.rc index 8eec16c9b4f1..fb6473666d7c 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -1056,6 +1056,9 @@ on boot && property:ro.config.low_ram=true write /proc/sys/vm/dirty_expire_centisecs 200 write /proc/sys/vm/dirty_background_ratio 5 +on boot && property:suspend.disable_sync_on_suspend=true + write /sys/power/sync_on_suspend 0 + on boot # basic network init ifup lo From 69f57f98c5ee9b314405c6d85e08ccb5c6a0dd4c Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Thu, 28 Sep 2023 06:32:29 +0000 Subject: [PATCH 0422/1487] Keep fs_mgr_vendor_overlay_test in internal cf. Bug: 302382476 Change-Id: I369927033b407660d2c0e7bdb85494c826c0b406 Test: presubmit --- fs_mgr/TEST_MAPPING | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING index 169496929bdd..37b4988dcee2 100644 --- a/fs_mgr/TEST_MAPPING +++ b/fs_mgr/TEST_MAPPING @@ -16,7 +16,8 @@ "name": "fiemap_writer_test" }, { - "name": "fs_mgr_vendor_overlay_test" + "name": "fs_mgr_vendor_overlay_test", + "keywords": ["internal"] }, { "name": "vts_libsnapshot_test" From 250aa5ed7218219b4b62dbaf37655a7eb40e8efa Mon Sep 17 00:00:00 2001 From: wuhaitao3 Date: Thu, 28 Sep 2023 14:20:40 +0800 Subject: [PATCH 0423/1487] Adjust unit tests for supporting chain partition with no ab Test: libfs_avb_internal_test libfs_avb_test Signed-off-by: wuhaitao3 Change-Id: I5f91510e72776ed2ed53756ae94a87b1417ae1a5 --- fs_mgr/libfs_avb/tests/avb_util_test.cpp | 11 ++++++++--- fs_mgr/libfs_avb/tests/basic_test.cpp | 4 +++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/fs_mgr/libfs_avb/tests/avb_util_test.cpp b/fs_mgr/libfs_avb/tests/avb_util_test.cpp index 2e34920124c9..ee83cda38d79 100644 --- a/fs_mgr/libfs_avb/tests/avb_util_test.cpp +++ b/fs_mgr/libfs_avb/tests/avb_util_test.cpp @@ -655,10 +655,12 @@ TEST_F(AvbUtilTest, VerifyVBMetaDataWithoutFooter) { " Partition Name: boot\n" " Rollback Index Location: 1\n" " Public key (sha1): cdbb77177f731920bbe0a0f94f84d9038ae0617d\n" + " Flags: 0\n" " Chain Partition descriptor:\n" " Partition Name: system\n" " Rollback Index Location: 2\n" - " Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n", + " Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n" + " Flags: 0\n", InfoImage("vbmeta.img")); android::base::unique_fd fd(open(vbmeta_path.value().c_str(), O_RDONLY | O_CLOEXEC)); @@ -876,10 +878,12 @@ TEST_F(AvbUtilTest, GetChainPartitionInfo) { " Partition Name: boot\n" " Rollback Index Location: 1\n" " Public key (sha1): cdbb77177f731920bbe0a0f94f84d9038ae0617d\n" + " Flags: 0\n" " Chain Partition descriptor:\n" " Partition Name: vbmeta_system\n" " Rollback Index Location: 2\n" - " Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n", + " Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n" + " Flags: 0\n", InfoImage("vbmeta.img")); bool fatal_error = false; @@ -909,7 +913,8 @@ TEST_F(AvbUtilTest, GetChainPartitionInfo) { " Chain Partition descriptor:\n" " Partition Name: system\n" " Rollback Index Location: 3\n" - " Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n", + " Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n" + " Flags: 0\n", InfoImage("vbmeta_system.img")); chained_descriptors = GetChainPartitionInfo(LoadVBMetaData("vbmeta_system.img"), &fatal_error); diff --git a/fs_mgr/libfs_avb/tests/basic_test.cpp b/fs_mgr/libfs_avb/tests/basic_test.cpp index 1c47c0758692..d49affb424d7 100644 --- a/fs_mgr/libfs_avb/tests/basic_test.cpp +++ b/fs_mgr/libfs_avb/tests/basic_test.cpp @@ -268,10 +268,12 @@ TEST_F(BaseFsAvbTest, GenerateVBMetaImageWithChainDescriptors) { " Partition Name: boot\n" " Rollback Index Location: 1\n" " Public key (sha1): cdbb77177f731920bbe0a0f94f84d9038ae0617d\n" + " Flags: 0\n" " Chain Partition descriptor:\n" " Partition Name: system\n" " Rollback Index Location: 2\n" - " Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n", + " Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n" + " Flags: 0\n", InfoImage("vbmeta.img")); } From 041afb2883b804d7fab52ae606f20786ed68a0e3 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 28 Sep 2023 10:41:21 -0700 Subject: [PATCH 0424/1487] Add the missing copyright headers to the .S files. Dates taken from `git log --follow`. Test: treehugger Change-Id: I80e9ea6aa01f8e0553295453749afcbc3af827f9 --- debuggerd/crasher/arm/crashglue.S | 16 ++++++++++++++++ debuggerd/crasher/arm64/crashglue.S | 16 ++++++++++++++++ debuggerd/crasher/riscv64/crashglue.S | 16 ++++++++++++++++ debuggerd/crasher/x86/crashglue.S | 16 ++++++++++++++++ debuggerd/crasher/x86_64/crashglue.S | 16 ++++++++++++++++ 5 files changed, 80 insertions(+) diff --git a/debuggerd/crasher/arm/crashglue.S b/debuggerd/crasher/arm/crashglue.S index 0def8aee3f7b..3001ca19e9b7 100644 --- a/debuggerd/crasher/arm/crashglue.S +++ b/debuggerd/crasher/arm/crashglue.S @@ -1,3 +1,19 @@ +/* + * Copyright 2006, 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. + */ + .globl crash1 .type crash1, %function crash1: diff --git a/debuggerd/crasher/arm64/crashglue.S b/debuggerd/crasher/arm64/crashglue.S index c56e19a388c7..90ba9a1eb2b0 100644 --- a/debuggerd/crasher/arm64/crashglue.S +++ b/debuggerd/crasher/arm64/crashglue.S @@ -1,3 +1,19 @@ +/* + * Copyright 2013, 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. + */ + .globl crash1 .type crash1, %function crash1: diff --git a/debuggerd/crasher/riscv64/crashglue.S b/debuggerd/crasher/riscv64/crashglue.S index f179e336810f..804a511b917f 100644 --- a/debuggerd/crasher/riscv64/crashglue.S +++ b/debuggerd/crasher/riscv64/crashglue.S @@ -1,3 +1,19 @@ +/* + * Copyright 2022, 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. + */ + .globl crash1 crash1: .cfi_startproc diff --git a/debuggerd/crasher/x86/crashglue.S b/debuggerd/crasher/x86/crashglue.S index 453035bf81ab..fe7c6480a448 100644 --- a/debuggerd/crasher/x86/crashglue.S +++ b/debuggerd/crasher/x86/crashglue.S @@ -1,3 +1,19 @@ +/* + * Copyright 2010, 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. + */ + .globl crash1 crash1: movl $0xa5a50000, %eax diff --git a/debuggerd/crasher/x86_64/crashglue.S b/debuggerd/crasher/x86_64/crashglue.S index c3d39c483f3c..ae13aa7e61eb 100644 --- a/debuggerd/crasher/x86_64/crashglue.S +++ b/debuggerd/crasher/x86_64/crashglue.S @@ -1,3 +1,19 @@ +/* + * Copyright 2010, 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. + */ + .globl crash1 crash1: movl $0xa5a50000, %eax From 5eea7e384bb1c2b99622608c327832344937a9ec Mon Sep 17 00:00:00 2001 From: Bradley Furman Date: Fri, 29 Sep 2023 21:16:57 +0000 Subject: [PATCH 0425/1487] Update the fastboot command size from 64 to 4096 to cover the changes from https://android-review.git.corp.google.com/c/platform/system/core/+/2214970 BUG=182864081 Change-Id: I6766647e53d777fd61df6e40cfefb45c7b138c77 --- fastboot/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastboot/README.md b/fastboot/README.md index 28e623ca798b..6996d4a00247 100644 --- a/fastboot/README.md +++ b/fastboot/README.md @@ -25,7 +25,7 @@ Linux, macOS, or Windows. ## Transport and Framing 1. Host sends a command, which is an ascii string in a single - packet no greater than 64 bytes. + packet no greater than 4096 bytes. 2. Client response with a single packet no greater than 256 bytes. The first four bytes of the response are "OKAY", "FAIL", "DATA", From 7d46c3fd7acae054ba5214a7dba99af004c99cad Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 29 Sep 2023 22:45:59 +0000 Subject: [PATCH 0426/1487] Remove obsolete workarounds. We've updated the glibc header (and musl will just use the bionic uapi headers), so this is obsolete (and getting in the way of someone trying to use the PERFMON capability). Test: treehugger Change-Id: Ife7ee076179e1db6246738aa41c2b82bd8546265 --- init/capabilities.cpp | 6 ------ init/capabilities.h | 11 ----------- 2 files changed, 17 deletions(-) diff --git a/init/capabilities.cpp b/init/capabilities.cpp index ab6ff03ef623..0e2cd2acc3e7 100644 --- a/init/capabilities.cpp +++ b/init/capabilities.cpp @@ -66,18 +66,12 @@ static const std::map cap_map = { CAP_MAP_ENTRY(WAKE_ALARM), CAP_MAP_ENTRY(BLOCK_SUSPEND), CAP_MAP_ENTRY(AUDIT_READ), -#if defined(__BIONIC__) CAP_MAP_ENTRY(PERFMON), CAP_MAP_ENTRY(BPF), CAP_MAP_ENTRY(CHECKPOINT_RESTORE), -#endif }; -#if defined(__BIONIC__) static_assert(CAP_LAST_CAP == CAP_CHECKPOINT_RESTORE, "CAP_LAST_CAP is not CAP_CHECKPOINT_RESTORE"); -#else -static_assert(CAP_LAST_CAP == CAP_AUDIT_READ, "CAP_LAST_CAP is not CAP_AUDIT_READ"); -#endif static bool ComputeCapAmbientSupported() { #if defined(__ANDROID__) diff --git a/init/capabilities.h b/init/capabilities.h index 891e0ac982cd..fc80c9864f7a 100644 --- a/init/capabilities.h +++ b/init/capabilities.h @@ -21,17 +21,6 @@ #include #include -#if !defined(__ANDROID__) -#ifndef CAP_BLOCK_SUSPEND -#define CAP_BLOCK_SUSPEND 36 -#endif -#ifndef CAP_AUDIT_READ -#define CAP_AUDIT_READ 37 -#endif -#undef CAP_LAST_CAP -#define CAP_LAST_CAP CAP_AUDIT_READ -#endif - namespace android { namespace init { From ab4c9621d420f92031d1171ed83813280843c914 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Mon, 2 Oct 2023 11:02:18 -0700 Subject: [PATCH 0427/1487] Log the CowOperation when decompression failed Test: th Bug: 302992208 Change-Id: I617062d75a79ae73dfdff13c2e9d2a62c5dfcfc0 --- .../snapuserd/dm-snapshot-merge/snapuserd_worker.cpp | 2 +- fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) 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 559dcc793e98..571b352385a0 100644 --- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp @@ -103,7 +103,7 @@ bool WorkerThread::ProcessReplaceOp(const CowOperation* cow_op) { ssize_t rv = reader_->ReadData(cow_op, buffer, BLOCK_SZ); if (rv != BLOCK_SZ) { SNAP_LOG(ERROR) << "ProcessReplaceOp failed for block " << cow_op->new_block - << ", return = " << rv; + << ", return = " << rv << ", COW operation = " << *cow_op; return false; } return true; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp index b9ecfa5b3235..5cb13e8bcd43 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp @@ -283,7 +283,8 @@ bool ReadWorker::ReadAlignedSector(sector_t sector, size_t sz) { // We found the sector in mapping. Check the type of COW OP and // process it. if (!ProcessCowOp(it->second, buffer)) { - SNAP_LOG(ERROR) << "ProcessCowOp failed"; + SNAP_LOG(ERROR) + << "ProcessCowOp failed, sector = " << sector << ", size = " << sz; return false; } From 9dabc9ef320ce3651dda4db4881cdb49686c4f52 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Mon, 2 Oct 2023 17:02:05 -0700 Subject: [PATCH 0428/1487] Change source to be a unique_ptr. The current code keeps a pointer to a local variable which doesn't work too well. Change this to a unique_ptr and allocate the source object that will be used instead. Test: All unit tests pass. Test: fastboot -w flashall on a mokey which crashed without this change. Change-Id: Ief5437374181e514928c45dd540b42898901a137 --- fastboot/fastboot.cpp | 20 ++++++++++---------- fastboot/fastboot.h | 3 ++- fastboot/task.cpp | 4 ++-- fastboot/task_test.cpp | 18 +++++++----------- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 3ce81417958f..b12e584d6506 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1525,7 +1525,7 @@ void do_flash(const char* pname, const char* fname, const bool apply_vbmeta, fb->ResizePartition(pname, std::to_string(buf.image_size)); } std::string flash_pname = repack_ramdisk(pname, &buf, fp->fb); - flash_buf(fp->source, flash_pname, &buf, apply_vbmeta); + flash_buf(fp->source.get(), flash_pname, &buf, apply_vbmeta); } // Sets slot_override as the active slot. If slot_override is blank, @@ -1679,7 +1679,7 @@ bool AddResizeTasks(const FlashingPlan* fp, std::vector>* } for (size_t i = 0; i < tasks->size(); i++) { if (auto flash_task = tasks->at(i)->AsFlashTask()) { - if (FlashTask::IsDynamicParitition(fp->source, flash_task)) { + if (FlashTask::IsDynamicParitition(fp->source.get(), flash_task)) { if (!loc) { loc = i; } @@ -1810,7 +1810,8 @@ std::vector> FlashAllTool::CollectTasks() { if (fp_->exclude_dynamic_partitions) { auto is_non_static_flash_task = [&](const auto& task) -> bool { if (auto flash_task = task->AsFlashTask()) { - if (!should_flash_in_userspace(fp_->source, flash_task->GetPartitionAndSlot())) { + if (!should_flash_in_userspace(fp_->source.get(), + flash_task->GetPartitionAndSlot())) { return false; } } @@ -1884,9 +1885,10 @@ std::vector> FlashAllTool::CollectTasksFromImageList() { // On these devices, secondary slots must be flashed as physical // partitions (otherwise they would not mount on first boot). To enforce // this, we delete any logical partitions for the "other" slot. - if (is_retrofit_device(fp_->source)) { + if (is_retrofit_device(fp_->source.get())) { std::string partition_name = image->part_name + "_" + slot; - if (image->IsSecondary() && should_flash_in_userspace(fp_->source, partition_name)) { + if (image->IsSecondary() && + should_flash_in_userspace(fp_->source.get(), partition_name)) { tasks.emplace_back(std::make_unique(fp_, partition_name)); } } @@ -1949,8 +1951,7 @@ static void do_update(const char* filename, FlashingPlan* fp) { if (error != 0) { die("failed to open zip file '%s': %s", filename, ErrorCodeString(error)); } - ZipImageSource zp = ZipImageSource(zip); - fp->source = &zp; + fp->source.reset(new ZipImageSource(zip)); FlashAllTool tool(fp); tool.Flash(); @@ -1971,8 +1972,7 @@ unique_fd LocalImageSource::OpenFile(const std::string& name) const { } static void do_flashall(FlashingPlan* fp) { - LocalImageSource s = LocalImageSource(); - fp->source = &s; + fp->source.reset(new LocalImageSource()); FlashAllTool tool(fp); tool.Flash(); } @@ -2089,7 +2089,7 @@ void fb_perform_format(const std::string& partition, int skip_if_not_supported, die("Cannot read image: %s", strerror(errno)); } - flash_buf(fp->source, partition, &buf, is_vbmeta_partition(partition)); + flash_buf(fp->source.get(), partition, &buf, is_vbmeta_partition(partition)); return; failed: diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index 4859cebc2895..cd7bc2d982b6 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -28,6 +28,7 @@ #pragma once #include +#include #include #include "fastboot_driver_interface.h" #include "filesystem.h" @@ -89,7 +90,7 @@ struct FlashingPlan { // If the image uses the default slot, or the user specified "all", then // the paired string will be empty. If the image requests a specific slot // (for example, system_other) it is specified instead. - ImageSource* source; + std::unique_ptr source; bool wants_wipe = false; bool skip_reboot = false; bool wants_set_active = false; diff --git a/fastboot/task.cpp b/fastboot/task.cpp index 4b2b9e316cc8..25c5a6e6bb30 100644 --- a/fastboot/task.cpp +++ b/fastboot/task.cpp @@ -41,7 +41,7 @@ bool FlashTask::IsDynamicParitition(const ImageSource* source, const FlashTask* void FlashTask::Run() { auto flash = [&](const std::string& partition) { - if (should_flash_in_userspace(fp_->source, partition) && !is_userspace_fastboot() && + if (should_flash_in_userspace(fp_->source.get(), partition) && !is_userspace_fastboot() && !fp_->force_flash) { die("The partition you are trying to flash is dynamic, and " "should be flashed via fastbootd. Please run:\n" @@ -174,7 +174,7 @@ std::unique_ptr OptimizedFlashSuperTask::Initialize( LOG(VERBOSE) << "Cannot optimize flashing super for all slots"; return nullptr; } - if (!CanOptimize(fp->source, tasks)) { + if (!CanOptimize(fp->source.get(), tasks)) { return nullptr; } diff --git a/fastboot/task_test.cpp b/fastboot/task_test.cpp index 1e25b6f63e39..9cde1a81e9a8 100644 --- a/fastboot/task_test.cpp +++ b/fastboot/task_test.cpp @@ -192,8 +192,7 @@ TEST_F(ParseTest, CorrectTaskLists) { GTEST_SKIP(); } - LocalImageSource s; - fp->source = &s; + fp->source.reset(new LocalImageSource); fp->sparse_limit = std::numeric_limits::max(); fastboot::MockFastbootDriver fb; @@ -239,8 +238,7 @@ TEST_F(ParseTest, IsDynamicParitiontest) { GTEST_SKIP(); } - LocalImageSource s; - fp->source = &s; + fp->source.reset(new LocalImageSource); fastboot::MockFastbootDriver fb; fp->fb = &fb; @@ -260,7 +258,7 @@ TEST_F(ParseTest, IsDynamicParitiontest) { ParseFastbootInfoLine(fp.get(), android::base::Tokenize(test.first, " ")); auto flash_task = task->AsFlashTask(); ASSERT_FALSE(flash_task == nullptr); - ASSERT_EQ(FlashTask::IsDynamicParitition(fp->source, flash_task), test.second); + ASSERT_EQ(FlashTask::IsDynamicParitition(fp->source.get(), flash_task), test.second); } } @@ -269,8 +267,7 @@ TEST_F(ParseTest, CanOptimizeTest) { GTEST_SKIP(); } - LocalImageSource s; - fp->source = &s; + fp->source.reset(new LocalImageSource); fp->sparse_limit = std::numeric_limits::max(); fastboot::MockFastbootDriver fb; @@ -301,7 +298,7 @@ TEST_F(ParseTest, CanOptimizeTest) { for (auto& test : patternmatchtest) { std::vector> tasks = ParseFastbootInfo(fp.get(), test.first); tasks.erase(std::remove_if(tasks.begin(), tasks.end(), remove_if_callback), tasks.end()); - ASSERT_EQ(OptimizedFlashSuperTask::CanOptimize(fp->source, tasks), test.second); + ASSERT_EQ(OptimizedFlashSuperTask::CanOptimize(fp->source.get(), tasks), test.second); } } @@ -312,8 +309,7 @@ TEST_F(ParseTest, OptimizedFlashSuperPatternMatchTest) { GTEST_SKIP(); } - LocalImageSource s; - fp->source = &s; + fp->source.reset(new LocalImageSource); fp->sparse_limit = std::numeric_limits::max(); fastboot::MockFastbootDriver fb; @@ -362,7 +358,7 @@ TEST_F(ParseTest, OptimizedFlashSuperPatternMatchTest) { contains_optimized_task = true; } if (auto flash_task = task->AsFlashTask()) { - if (FlashTask::IsDynamicParitition(fp->source, flash_task)) { + if (FlashTask::IsDynamicParitition(fp->source.get(), flash_task)) { return false; } } From 5248c5d72ad2a14f3426b7872b8867f97818650f Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 3 Oct 2023 17:13:10 +0000 Subject: [PATCH 0429/1487] libvndksupport: log sphal namespace fallback If someone is trying to use the sphal namespace, but it isn't available, we should probably fix this code or add an sphal namespace there or similar. Add log for more clarity. Bug: N/A Test: boot cuttlefish, this doesn't get logged Change-Id: I2fd2cddc90f529218c99ede8daf2891d84ceb94c --- libvndksupport/linker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libvndksupport/linker.cpp b/libvndksupport/linker.cpp index ad4fb31ef3fb..b2b257e87931 100644 --- a/libvndksupport/linker.cpp +++ b/libvndksupport/linker.cpp @@ -75,7 +75,7 @@ void* android_load_sphal_library(const char* name, int flag) { } return handle; } else { - ALOGD("Loading %s from current namespace instead of sphal namespace.", name); + ALOGW("Loading %s from current namespace instead of sphal namespace.", name); return dlopen(name, flag); } } From 8a28163d33d85b9742900f173ed765145a449a56 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 3 Oct 2023 15:55:09 -0700 Subject: [PATCH 0430/1487] inspect_cow: Add an --extract-to argument. This adds an --extract-to argument to inspect_cow to verify that full OTA snapshots contain correct data. It does not yet work for ordered ops. Test: inspect_cow Bug: N/A Change-Id: I9014da3e83fd4fb5ea54ac1d36e527b3e3e6c9d5 Change-Id: I7e256e8ddec626980cdcf8680bbeac3c2e9d8de1 --- .../libsnapshot_cow/inspect_cow.cpp | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp index a6dee4f43138..83b5a12955a7 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -38,11 +39,13 @@ DEFINE_bool(show_merged, false, DEFINE_bool(verify_merge_sequence, false, "Verify merge order sequencing"); DEFINE_bool(show_merge_sequence, false, "Show merge order sequence"); DEFINE_bool(show_raw_ops, false, "Show raw ops directly from the underlying parser"); +DEFINE_string(extract_to, "", "Extract the COW contents to the given file"); namespace android { namespace snapshot { using android::base::borrowed_fd; +using android::base::unique_fd; void MyLogger(android::base::LogId, android::base::LogSeverity severity, const char*, const char*, unsigned int, const char* message) { @@ -53,7 +56,7 @@ void MyLogger(android::base::LogId, android::base::LogSeverity severity, const c } } -static void ShowBad(CowReader& reader, const struct CowOperation* op) { +static void ShowBad(CowReader& reader, const CowOperation* op) { size_t count; auto buffer = std::make_unique(op->data_length); @@ -104,12 +107,21 @@ static bool ShowRawOpStream(borrowed_fd fd) { } static bool Inspect(const std::string& path) { - android::base::unique_fd fd(open(path.c_str(), O_RDONLY)); + unique_fd fd(open(path.c_str(), O_RDONLY)); if (fd < 0) { PLOG(ERROR) << "open failed: " << path; return false; } + unique_fd extract_to; + if (!FLAGS_extract_to.empty()) { + extract_to.reset(open(FLAGS_extract_to.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0664)); + if (extract_to < 0) { + PLOG(ERROR) << "could not open " << FLAGS_extract_to << " for writing"; + return false; + } + } + CowReader reader; auto start_time = std::chrono::steady_clock::now(); @@ -186,12 +198,23 @@ static bool Inspect(const std::string& path) { if (!FLAGS_silent && FLAGS_show_ops) std::cout << *op << "\n"; - if (FLAGS_decompress && op->type == kCowReplaceOp && op->compression != kCowCompressNone) { + if ((FLAGS_decompress || extract_to >= 0) && op->type == kCowReplaceOp) { if (reader.ReadData(op, buffer.data(), buffer.size()) < 0) { std::cerr << "Failed to decompress for :" << *op << "\n"; success = false; if (FLAGS_show_bad_data) ShowBad(reader, op); } + if (extract_to >= 0) { + off_t offset = uint64_t(op->new_block) * header.block_size; + if (!android::base::WriteFullyAtOffset(extract_to, buffer.data(), buffer.size(), + offset)) { + PLOG(ERROR) << "failed to write block " << op->new_block; + return false; + } + } + } else if (extract_to >= 0 && !IsMetadataOp(*op) && op->type != kCowZeroOp) { + PLOG(ERROR) << "Cannot extract op yet: " << *op; + return false; } if (op->type == kCowSequenceOp && FLAGS_show_merge_sequence) { From c942daf179983d1f9ccf76eb387ec4b809ff6445 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 3 Oct 2023 19:50:53 -0700 Subject: [PATCH 0431/1487] snapuserd: Add an extractor tool. This is similar to inspect_cow --extract-to, except it uses snapuserd. It is a diagnostic host tool and uses the tooling added for host testing. Usage: snapuserd_extractor -cow COW_FILE -base BASE_FILE -out OUT_FILE -num_sectors NUM_SECTORS Unlike inspect_cow, this supports xor/copy operations. The extractor code is separated into a utility file so we can use it for additional tests later on. Bug: N/A Test: manual test Change-Id: Ib7509508cba45e6c3a0db8c75454e33c2a503e03 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 45 ++++++++++ .../snapuserd/snapuserd_extractor.cpp | 68 ++++++++++++++ .../snapuserd/user-space-merge/extractor.cpp | 90 +++++++++++++++++++ .../snapuserd/user-space-merge/extractor.h | 51 +++++++++++ 4 files changed, 254 insertions(+) create mode 100644 fs_mgr/libsnapshot/snapuserd/snapuserd_extractor.cpp create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.cpp create mode 100644 fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.h diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 47a86858a7fb..1b0c5639ee92 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -293,3 +293,48 @@ cc_test { "vts", ], } + +cc_binary_host { + name: "snapuserd_extractor", + defaults: [ + "fs_mgr_defaults", + "libsnapshot_cow_defaults", + ], + srcs: [ + "testing/dm_user_harness.cpp", + "testing/harness.cpp", + "testing/host_harness.cpp", + "user-space-merge/extractor.cpp", + "snapuserd_extractor.cpp", + ], + cflags: [ + "-D_FILE_OFFSET_BITS=64", + "-Wall", + "-Werror", + ], + shared_libs: [ + "libbase", + "liblog", + ], + static_libs: [ + "libbrotli", + "libcutils_sockets", + "libdm", + "libext2_uuid", + "libext4_utils", + "libfs_mgr_file_wait", + "libgflags", + "libsnapshot_cow", + "libsnapuserd", + "liburing", + "libz", + ], + include_dirs: [ + "bionic/libc/kernel", + ".", + ], + header_libs: [ + "libstorage_literals_headers", + "libfiemap_headers", + ], +} diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_extractor.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_extractor.cpp new file mode 100644 index 000000000000..f46cd5bc53c9 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_extractor.cpp @@ -0,0 +1,68 @@ +// Copyright (C) 2023 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include "user-space-merge/extractor.h" + +using namespace std::string_literals; + +DEFINE_string(base, "", "Base device/image"); +DEFINE_string(cow, "", "COW device/image"); +DEFINE_string(out, "", "Output path"); +DEFINE_int32(num_sectors, 0, "Number of sectors to read"); + +int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv) { + android::base::InitLogging(argv); + gflags::ParseCommandLineFlags(&argc, &argv, true); + + if (FLAGS_out.empty()) { + LOG(ERROR) << "Missing -out argument."; + return 1; + } + if (FLAGS_base.empty()) { + LOG(ERROR) << "Missing -base argument."; + return 1; + } + if (FLAGS_cow.empty()) { + LOG(ERROR) << "missing -out argument."; + return 1; + } + if (!FLAGS_num_sectors) { + LOG(ERROR) << "missing -num_sectors argument."; + return 1; + } + + android::snapshot::Extractor extractor(FLAGS_base, FLAGS_cow); + if (!extractor.Init()) { + return 1; + } + if (!extractor.Extract(FLAGS_num_sectors, FLAGS_out)) { + return 1; + } + return 0; +} diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.cpp new file mode 100644 index 000000000000..c5718d5b76a8 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.cpp @@ -0,0 +1,90 @@ +// Copyright (C) 2023 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 "extractor.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +using android::base::unique_fd; +using namespace std::string_literals; + +namespace android { +namespace snapshot { + +Extractor::Extractor(const std::string& base_path, const std::string& cow_path) + : base_path_(base_path), cow_path_(cow_path), control_name_("test") {} + +bool Extractor::Init() { + auto opener = factory_.CreateTestOpener(control_name_); + handler_ = std::make_shared(control_name_, cow_path_, base_path_, base_path_, + opener, 1, false, false); + if (!handler_->InitCowDevice()) { + return false; + } + if (!handler_->InitializeWorkers()) { + return false; + } + + read_worker_ = std::make_unique(cow_path_, base_path_, control_name_, base_path_, + handler_->GetSharedPtr(), opener); + if (!read_worker_->Init()) { + return false; + } + block_server_ = static_cast(read_worker_->block_server()); + + handler_thread_ = std::async(std::launch::async, &SnapshotHandler::Start, handler_.get()); + return true; +} + +Extractor::~Extractor() { + factory_.DeleteQueue(control_name_); +} + +bool Extractor::Extract(off_t num_sectors, const std::string& out_path) { + unique_fd out_fd(open(out_path.c_str(), O_RDWR | O_CLOEXEC | O_TRUNC | O_CREAT, 0664)); + if (out_fd < 0) { + PLOG(ERROR) << "Could not open for writing: " << out_path; + return false; + } + + for (off_t i = 0; i < num_sectors; i++) { + if (!read_worker_->RequestSectors(i, 512)) { + LOG(ERROR) << "Read sector " << i << " failed."; + return false; + } + std::string result = std::move(block_server_->sent_io()); + off_t offset = i * 512; + if (!android::base::WriteFullyAtOffset(out_fd, result.data(), result.size(), offset)) { + PLOG(ERROR) << "write failed"; + return false; + } + } + return true; +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.h new file mode 100644 index 000000000000..65285b1fa5f7 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.h @@ -0,0 +1,51 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include +#include + +#include +#include "merge_worker.h" +#include "read_worker.h" +#include "snapuserd_core.h" +#include "testing/host_harness.h" + +namespace android { +namespace snapshot { + +class Extractor final { + public: + Extractor(const std::string& base_path, const std::string& cow_path); + ~Extractor(); + + bool Init(); + bool Extract(off_t num_sectors, const std::string& out_path); + + private: + std::string base_path_; + std::string cow_path_; + + TestBlockServerFactory factory_; + HostTestHarness harness_; + std::string control_name_; + std::shared_ptr handler_; + std::unique_ptr read_worker_; + std::future handler_thread_; + TestBlockServer* block_server_ = nullptr; +}; + +} // namespace snapshot +} // namespace android From 716ff7b55adf56b212974ea98783422b5682251f Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 4 Oct 2023 23:31:09 +0000 Subject: [PATCH 0432/1487] s/master/main/ Test: treehugger Change-Id: Iabb23436d92686b934f2f2609217714b64ae75de --- libcutils/sockets_windows.cpp | 2 +- rootdir/etc/public.libraries.android.txt | 2 +- rootdir/etc/public.libraries.iot.txt | 2 +- rootdir/etc/public.libraries.wear.txt | 2 +- trusty/stats/test/README.md | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libcutils/sockets_windows.cpp b/libcutils/sockets_windows.cpp index 4adb79691d8d..99a2e2ddeeb5 100644 --- a/libcutils/sockets_windows.cpp +++ b/libcutils/sockets_windows.cpp @@ -35,7 +35,7 @@ // can be extremely tricky and cause deadlock when using threads or atexit(). // // Both adb (1) and Chrome (2) purposefully avoid WSACleanup() with no issues. -// (1) https://android.googlesource.com/platform/system/core.git/+/master/adb/sysdeps_win32.cpp +// (1) https://android.googlesource.com/platform/packages/modules/adb.git/+/main/sysdeps_win32.cpp // (2) https://code.google.com/p/chromium/codesearch#chromium/src/net/base/winsock_init.cc bool initialize_windows_sockets() { // There's no harm in calling WSAStartup() multiple times but no benefit diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt index cacc47c59b89..9be2ef69df09 100644 --- a/rootdir/etc/public.libraries.android.txt +++ b/rootdir/etc/public.libraries.android.txt @@ -1,4 +1,4 @@ -# See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md +# See https://android.googlesource.com/platform/ndk/+/main/docs/PlatformApis.md libandroid.so libaaudio.so libamidi.so diff --git a/rootdir/etc/public.libraries.iot.txt b/rootdir/etc/public.libraries.iot.txt index 77f8bb802f3b..051396812690 100644 --- a/rootdir/etc/public.libraries.iot.txt +++ b/rootdir/etc/public.libraries.iot.txt @@ -1,4 +1,4 @@ -# See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md +# See https://android.googlesource.com/platform/ndk/+/main/docs/PlatformApis.md libandroid.so libandroidthings.so libaaudio.so diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt index ea1e234373de..5915dcb0695e 100644 --- a/rootdir/etc/public.libraries.wear.txt +++ b/rootdir/etc/public.libraries.wear.txt @@ -1,4 +1,4 @@ -# See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md +# See https://android.googlesource.com/platform/ndk/+/main/docs/PlatformApis.md libandroid.so libaaudio.so libamidi.so diff --git a/trusty/stats/test/README.md b/trusty/stats/test/README.md index 45e6af8b066b..175409e99df2 100644 --- a/trusty/stats/test/README.md +++ b/trusty/stats/test/README.md @@ -1,8 +1,8 @@ # Development Notes -* First get [repo_pull.py and gerrit.py](https://android.googlesource.com/platform/development/+/master/tools/repo_pull/) from aosp. +* First get [repo_pull.py and gerrit.py](https://android.googlesource.com/platform/development/+/main/tools/repo_pull/) from aosp. -* Although this repo is not currently in Trusty’s manifest, it’s sufficient to copy these two python scripts to the root of the Trusty project and run them from there. Make sure to follow the [repo_pull installation](https://android.googlesource.com/platform/development/+/master/tools/repo_pull/#installation) steps if necessary. +* Although this repo is not currently in Trusty’s manifest, it’s sufficient to copy these two python scripts to the root of the Trusty project and run them from there. Make sure to follow the [repo_pull installation](https://android.googlesource.com/platform/development/+/main/tools/repo_pull/#installation) steps if necessary. ## Build From a16436d5d737f65d7dca3335a834ef877b0e9c7b Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 26 Sep 2023 17:22:36 -0700 Subject: [PATCH 0433/1487] Adding test for reader compatibility Reader + Parser v3 should be able to read V2 cow format written to disk. This test reads in a small cow file written by basic_v2_cow_writer and parses it to ensure this compatibility checks out. Test: cow_api_test Change-Id: I46ebf4e3f12cdb3e4716ca5b624aab5836086733 --- fs_mgr/libsnapshot/Android.bp | 3 ++ .../libsnapshot/libsnapshot_cow/test_v2.cpp | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index 0131f732e6fa..fe47801f3f72 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -415,6 +415,9 @@ cc_test { test_options: { min_shipping_api_level: 30, }, + data: [ + "tools/testdata/cow_v2", + ], auto_gen_config: true, require_root: false, host_supported: true, diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp index e59bd927fe08..9676bf9b23b4 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp @@ -1504,6 +1504,37 @@ TEST_F(CowTest, InvalidMergeOrderTest) { ASSERT_FALSE(reader.VerifyMergeOps()); } +unique_fd OpenTestFile(const std::string& file, int flags) { + std::string path = "tools/testdata/" + file; + + unique_fd fd(open(path.c_str(), flags)); + if (fd >= 0) { + return fd; + } + + path = android::base::GetExecutableDirectory() + "/" + path; + return unique_fd{open(path.c_str(), flags)}; +} + +TEST_F(CowTest, CompatibilityTest) { + std::string filename = "cow_v2"; + auto fd = OpenTestFile(filename, O_RDONLY); + if (fd.get() == -1) { + LOG(ERROR) << filename << " not found"; + GTEST_SKIP(); + } + CowReader reader; + reader.Parse(fd); + + const auto& header = reader.GetHeader(); + ASSERT_EQ(header.prefix.magic, kCowMagicNumber); + ASSERT_EQ(header.prefix.major_version, kCowVersionMajor); + ASSERT_EQ(header.prefix.minor_version, kCowVersionMinor); + + CowFooter footer; + ASSERT_TRUE(reader.GetFooter(&footer)); +} + } // namespace snapshot } // namespace android From c9770b29b94b6bcb2a5f8c08fa92e99c460fd7dd Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Thu, 31 Aug 2023 13:22:05 -0700 Subject: [PATCH 0434/1487] Refactor off V2 Cow Ops Refactor writer, reader + parser to work off v2 version of CowOperations. Test: m libsnapshot. ota on cuttlefish Change-Id: Iec59be91e5f54782272b37702d645942df38c771 --- .../include/libsnapshot/cow_format.h | 55 ++++----- .../include/libsnapshot/cow_reader.h | 4 +- .../libsnapshot_cow/cow_format.cpp | 114 ++++++++++++------ .../libsnapshot_cow/cow_reader.cpp | 47 +++++++- .../libsnapshot/libsnapshot_cow/parser_v2.cpp | 22 ++-- .../libsnapshot/libsnapshot_cow/parser_v2.h | 4 +- .../libsnapshot/libsnapshot_cow/test_v2.cpp | 39 +++--- .../libsnapshot/libsnapshot_cow/writer_v2.cpp | 49 ++++---- .../libsnapshot/libsnapshot_cow/writer_v2.h | 6 +- 9 files changed, 205 insertions(+), 135 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h index 9359b9ec1294..2a2cee2b72b5 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h @@ -22,6 +22,9 @@ namespace android { namespace snapshot { +struct CowOperationV3; +typedef CowOperationV3 CowOperation; + static constexpr uint64_t kCowMagicNumber = 0x436f77634f572121ULL; static constexpr uint32_t kCowVersionMajor = 2; static constexpr uint32_t kCowVersionMinor = 0; @@ -109,9 +112,8 @@ struct CowFooterOperation { uint64_t num_ops; } __attribute__((packed)); -// Cow operations are currently fixed-size entries, but this may change if -// needed. -struct CowOperation { +// V2 version of COW. On disk format for older devices +struct CowOperationV2 { // The operation code (see the constants and structures below). uint8_t type; @@ -146,42 +148,32 @@ struct CowOperation { } __attribute__((packed)); // The on disk format of cow (currently == CowOperation) -struct CowOperationV2 { +struct CowOperationV3 { // The operation code (see the constants and structures below). uint8_t type; - // If this operation reads from the data section of the COW, this contains - // the compression type of that data (see constants below). - uint8_t compression; - // If this operation reads from the data section of the COW, this contains // the length. uint16_t data_length; // The block of data in the new image that this operation modifies. - uint64_t new_block; + uint32_t new_block; // The value of |source| depends on the operation code. // - // For copy operations, this is a block location in the source image. - // - // For replace operations, this is a byte offset within the COW's data - // sections (eg, not landing within the header or metadata). It is an - // absolute position within the image. - // - // For zero operations (replace with all zeroes), this is unused and must - // be zero. - // - // For Label operations, this is the value of the applied label. - // - // For Cluster operations, this is the length of the following data region + // CopyOp: a 32-bit block location in the source image. + // ReplaceOp: an absolute byte offset within the COW's data section. + // XorOp: an absolute byte offset in the source image. + // ZeroOp: unused + // LabelOp: a 64-bit opaque identifier. // - // For Xor operations, this is the byte location in the source image. - uint64_t source; + // For ops other than Label: + // Bits 47-62 are reserved and must be zero. + // A block is compressed if it’s data is < block_sz + uint64_t source_info; } __attribute__((packed)); -static_assert(sizeof(CowOperationV2) == sizeof(CowOperation)); -static_assert(sizeof(CowOperation) == sizeof(CowFooterOperation)); +static_assert(sizeof(CowOperationV2) == sizeof(CowFooterOperation)); static constexpr uint8_t kCowCopyOp = 1; static constexpr uint8_t kCowReplaceOp = 2; @@ -208,11 +200,14 @@ static constexpr uint8_t kCowReadAheadNotStarted = 0; static constexpr uint8_t kCowReadAheadInProgress = 1; static constexpr uint8_t kCowReadAheadDone = 2; +static constexpr uint64_t kCowOpSourceInfoDataMask = (1ULL << 48) - 1; +static constexpr uint64_t kCowOpSourceInfoCompressBit = (1ULL << 63); + static inline uint64_t GetCowOpSourceInfoData(const CowOperation* op) { - return op->source; + return op->source_info & kCowOpSourceInfoDataMask; } static inline bool GetCowOpSourceInfoCompression(const CowOperation* op) { - return op->compression != kCowCompressNone; + return !!(op->source_info & kCowOpSourceInfoCompressBit); } struct CowFooter { @@ -236,10 +231,12 @@ struct BufferState { // 2MB Scratch space used for read-ahead static constexpr uint64_t BUFFER_REGION_DEFAULT_SIZE = (1ULL << 21); +std::ostream& operator<<(std::ostream& os, CowOperationV2 const& arg); + std::ostream& operator<<(std::ostream& os, CowOperation const& arg); -int64_t GetNextOpOffset(const CowOperation& op, uint32_t cluster_size); -int64_t GetNextDataOffset(const CowOperation& op, uint32_t cluster_size); +int64_t GetNextOpOffset(const CowOperationV2& op, uint32_t cluster_size); +int64_t GetNextDataOffset(const CowOperationV2& op, uint32_t cluster_size); // Ops that are internal to the Cow Format and not OTA data bool IsMetadataOp(const CowOperation& op); diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h index 67d301d70cff..1d6fd62b4046 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h @@ -165,9 +165,10 @@ class CowReader final : public ICowReader { void UpdateMergeOpsCompleted(int num_merge_ops) { header_.num_merge_ops += num_merge_ops; } private: + bool ParseV2(android::base::borrowed_fd fd, std::optional label); bool PrepMergeOps(); uint64_t FindNumCopyops(); - uint8_t GetCompressionType(const CowOperation* op); + uint8_t GetCompressionType(); android::base::unique_fd owned_fd_; android::base::borrowed_fd fd_; @@ -184,6 +185,7 @@ class CowReader final : public ICowReader { std::shared_ptr> data_loc_; ReaderFlags reader_flag_; bool is_merge_{}; + uint8_t compression_type_ = kCowCompressNone; }; } // namespace snapshot diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp index ff3ccecb86aa..58dca64e19bd 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp @@ -14,11 +14,14 @@ // limitations under the License. // +#include #include #include #include #include +#include +#include #include "writer_v2.h" namespace android { @@ -26,45 +29,82 @@ namespace snapshot { using android::base::unique_fd; -std::ostream& operator<<(std::ostream& os, CowOperation const& op) { - os << "CowOperation(type:"; - if (op.type == kCowCopyOp) - os << "kCowCopyOp, "; - else if (op.type == kCowReplaceOp) - os << "kCowReplaceOp, "; - else if (op.type == kCowZeroOp) - os << "kZeroOp, "; - else if (op.type == kCowFooterOp) - os << "kCowFooterOp, "; - else if (op.type == kCowLabelOp) - os << "kCowLabelOp, "; - else if (op.type == kCowClusterOp) - os << "kCowClusterOp "; - else if (op.type == kCowXorOp) - os << "kCowXorOp "; - else if (op.type == kCowSequenceOp) - os << "kCowSequenceOp "; - else if (op.type == kCowFooterOp) - os << "kCowFooterOp "; - else - os << (int)op.type << "?,"; - os << "compression:"; - if (op.compression == kCowCompressNone) - os << "kCowCompressNone, "; - else if (op.compression == kCowCompressGz) - os << "kCowCompressGz, "; - else if (op.compression == kCowCompressBrotli) - os << "kCowCompressBrotli, "; - else - os << (int)op.compression << "?, "; - os << "data_length:" << op.data_length << ",\t"; - os << "new_block:" << op.new_block << ",\t"; +std::ostream& EmitCowTypeString(std::ostream& os, uint8_t cow_type) { + switch (cow_type) { + case kCowCopyOp: + return os << "kCowCopyOp"; + case kCowReplaceOp: + return os << "kCowReplaceOp"; + case kCowZeroOp: + return os << "kZeroOp"; + case kCowFooterOp: + return os << "kCowFooterOp"; + case kCowLabelOp: + return os << "kCowLabelOp"; + case kCowClusterOp: + return os << "kCowClusterOp"; + case kCowXorOp: + return os << "kCowXorOp"; + case kCowSequenceOp: + return os << "kCowSequenceOp"; + default: + return os << (int)cow_type << "unknown"; + } +} + +std::ostream& operator<<(std::ostream& os, CowOperationV2 const& op) { + os << "CowOperationV2("; + EmitCowTypeString(os, op.type) << ", "; + switch (op.compression) { + case kCowCompressNone: + os << "uncompressed, "; + break; + case kCowCompressGz: + os << "gz, "; + break; + case kCowCompressBrotli: + os << "brotli, "; + break; + case kCowCompressLz4: + os << "lz4, "; + break; + case kCowCompressZstd: + os << "zstd, "; + break; + } + os << "data_length:" << op.data_length << ", "; + os << "new_block:" << op.new_block << ", "; os << "source:" << op.source; os << ")"; return os; } -int64_t GetNextOpOffset(const CowOperation& op, uint32_t cluster_ops) { +std::ostream& operator<<(std::ostream& os, CowOperation const& op) { + os << "CowOperation("; + EmitCowTypeString(os, op.type); + if (op.type == kCowReplaceOp || op.type == kCowXorOp || op.type == kCowSequenceOp) { + if (op.source_info & kCowOpSourceInfoCompressBit) { + os << ", compressed"; + } else { + os << ", uncompressed"; + } + os << ", data_length:" << op.data_length; + } + if (op.type != kCowClusterOp && op.type != kCowSequenceOp && op.type != kCowLabelOp) { + os << ", new_block:" << op.new_block; + } + if (op.type == kCowXorOp || op.type == kCowReplaceOp || op.type == kCowCopyOp) { + os << ", source:" << (op.source_info & kCowOpSourceInfoDataMask); + } else if (op.type == kCowClusterOp) { + os << ", cluster_data:" << (op.source_info & kCowOpSourceInfoDataMask); + } else { + os << ", label:0x" << android::base::StringPrintf("%" PRIx64, op.source_info); + } + os << ")"; + return os; +} + +int64_t GetNextOpOffset(const CowOperationV2& op, uint32_t cluster_ops) { if (op.type == kCowClusterOp) { return op.source; } else if ((op.type == kCowReplaceOp || op.type == kCowXorOp) && cluster_ops == 0) { @@ -74,11 +114,11 @@ int64_t GetNextOpOffset(const CowOperation& op, uint32_t cluster_ops) { } } -int64_t GetNextDataOffset(const CowOperation& op, uint32_t cluster_ops) { +int64_t GetNextDataOffset(const CowOperationV2& op, uint32_t cluster_ops) { if (op.type == kCowClusterOp) { - return cluster_ops * sizeof(CowOperation); + return cluster_ops * sizeof(CowOperationV2); } else if (cluster_ops == 0) { - return sizeof(CowOperation); + return sizeof(CowOperationV2); } else { return 0; } diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp index 1b5d72484a5a..bf50f2f5eb2d 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp @@ -55,6 +55,7 @@ std::unique_ptr CowReader::CloneCowReader() { cow->data_loc_ = data_loc_; cow->block_pos_index_ = block_pos_index_; cow->is_merge_ = is_merge_; + cow->compression_type_ = compression_type_; return cow; } @@ -101,8 +102,44 @@ bool CowReader::Parse(android::base::borrowed_fd fd, std::optional lab footer_ = parser.footer(); fd_size_ = parser.fd_size(); last_label_ = parser.last_label(); - ops_ = parser.ops(); data_loc_ = parser.data_loc(); + ops_ = std::make_shared>(parser.ops()->size()); + + // Translate the operation buffer from on disk to in memory + for (size_t i = 0; i < parser.ops()->size(); i++) { + const auto& v2_op = parser.ops()->at(i); + + auto& new_op = ops_->at(i); + new_op.type = v2_op.type; + new_op.data_length = v2_op.data_length; + + if (v2_op.new_block > std::numeric_limits::max()) { + LOG(ERROR) << "Out-of-range new block in COW op: " << v2_op; + return false; + } + new_op.new_block = v2_op.new_block; + + uint64_t source_info = v2_op.source; + if (new_op.type != kCowLabelOp) { + source_info &= kCowOpSourceInfoDataMask; + if (source_info != v2_op.source) { + LOG(ERROR) << "Out-of-range source value in COW op: " << v2_op; + return false; + } + } + if (v2_op.compression != kCowCompressNone) { + if (compression_type_ == kCowCompressNone) { + compression_type_ = v2_op.compression; + } else if (compression_type_ != v2_op.compression) { + LOG(ERROR) << "COW has mixed compression types which is not supported;" + << " previously saw " << compression_type_ << ", got " + << v2_op.compression << ", op: " << v2_op; + return false; + } + source_info |= kCowOpSourceInfoCompressBit; + } + new_op.source_info = source_info; + } // If we're resuming a write, we're not ready to merge if (label.has_value()) return true; @@ -597,14 +634,14 @@ class CowDataStream final : public IByteStream { size_t remaining_; }; -uint8_t CowReader::GetCompressionType(const CowOperation* op) { - return op->compression; +uint8_t CowReader::GetCompressionType() { + return compression_type_; } ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_size, size_t ignore_bytes) { std::unique_ptr decompressor; - switch (GetCompressionType(op)) { + switch (GetCompressionType()) { case kCowCompressNone: break; case kCowCompressGz: @@ -624,7 +661,7 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_ } break; default: - LOG(ERROR) << "Unknown compression type: " << GetCompressionType(op); + LOG(ERROR) << "Unknown compression type: " << GetCompressionType(); return -1; } diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.cpp index fdb5c5911d1c..8edeae127ac8 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.cpp @@ -66,18 +66,18 @@ bool CowParserV2::Parse(borrowed_fd fd, const CowHeader& header, std::optional label) { uint64_t data_pos = 0; if (header_.cluster_ops) { - data_pos = pos + header_.cluster_ops * sizeof(CowOperation); + data_pos = pos + header_.cluster_ops * sizeof(CowOperationV2); } else { - data_pos = pos + sizeof(CowOperation); + data_pos = pos + sizeof(CowOperationV2); } - auto ops_buffer = std::make_shared>(); + auto ops_buffer = std::make_shared>(); uint64_t current_op_num = 0; uint64_t cluster_ops = header_.cluster_ops ?: 1; bool done = false; // Alternating op clusters and data while (!done) { - uint64_t to_add = std::min(cluster_ops, (fd_size_ - pos) / sizeof(CowOperation)); + uint64_t to_add = std::min(cluster_ops, (fd_size_ - pos) / sizeof(CowOperationV2)); if (to_add == 0) break; ops_buffer->resize(current_op_num + to_add); if (!android::base::ReadFully(fd, &ops_buffer->data()[current_op_num], - to_add * sizeof(CowOperation))) { + to_add * sizeof(CowOperationV2))) { PLOG(ERROR) << "read op failed"; return false; } @@ -150,7 +150,7 @@ bool CowParserV2::ParseOps(borrowed_fd fd, std::optional label) { if (current_op.type == kCowXorOp) { data_loc->insert({current_op.new_block, data_pos}); } - pos += sizeof(CowOperation) + GetNextOpOffset(current_op, header_.cluster_ops); + pos += sizeof(CowOperationV2) + GetNextOpOffset(current_op, header_.cluster_ops); data_pos += current_op.data_length + GetNextDataOffset(current_op, header_.cluster_ops); if (current_op.type == kCowClusterOp) { @@ -222,7 +222,7 @@ bool CowParserV2::ParseOps(borrowed_fd fd, std::optional label) { << ops_buffer->size(); return false; } - if (ops_buffer->size() * sizeof(CowOperation) != footer_->op.ops_size) { + if (ops_buffer->size() * sizeof(CowOperationV2) != footer_->op.ops_size) { LOG(ERROR) << "ops size does not match "; return false; } diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.h b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.h index afcf687fd67a..92e2b08c42d4 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.h +++ b/fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.h @@ -33,7 +33,7 @@ class CowParserV2 { const CowHeader& header() const { return header_; } const std::optional& footer() const { return footer_; } - std::shared_ptr> ops() { return ops_; } + std::shared_ptr> ops() { return ops_; } std::shared_ptr> data_loc() const { return data_loc_; } uint64_t fd_size() const { return fd_size_; } const std::optional& last_label() const { return last_label_; } @@ -43,7 +43,7 @@ class CowParserV2 { CowHeader header_ = {}; std::optional footer_; - std::shared_ptr> ops_; + std::shared_ptr> ops_; std::shared_ptr> data_loc_; uint64_t fd_size_; std::optional last_label_; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp index 9676bf9b23b4..8f3f03f38f3f 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp @@ -86,10 +86,9 @@ TEST_F(CowTest, CopyContiguous) { while (!iter->AtEnd()) { auto op = iter->Get(); ASSERT_EQ(op->type, kCowCopyOp); - ASSERT_EQ(op->compression, kCowCompressNone); ASSERT_EQ(op->data_length, 0); ASSERT_EQ(op->new_block, 10 + i); - ASSERT_EQ(op->source, 1000 + i); + ASSERT_EQ(op->source_info, 1000 + i); iter->Next(); i += 1; } @@ -133,10 +132,9 @@ TEST_F(CowTest, ReadWrite) { auto op = iter->Get(); ASSERT_EQ(op->type, kCowCopyOp); - ASSERT_EQ(op->compression, kCowCompressNone); ASSERT_EQ(op->data_length, 0); ASSERT_EQ(op->new_block, 10); - ASSERT_EQ(op->source, 20); + ASSERT_EQ(op->source_info, 20); std::string sink(data.size(), '\0'); @@ -157,20 +155,18 @@ TEST_F(CowTest, ReadWrite) { // Note: the zero operation gets split into two blocks. ASSERT_EQ(op->type, kCowZeroOp); - ASSERT_EQ(op->compression, kCowCompressNone); ASSERT_EQ(op->data_length, 0); ASSERT_EQ(op->new_block, 51); - ASSERT_EQ(op->source, 0); + ASSERT_EQ(op->source_info, 0); iter->Next(); ASSERT_FALSE(iter->AtEnd()); op = iter->Get(); ASSERT_EQ(op->type, kCowZeroOp); - ASSERT_EQ(op->compression, kCowCompressNone); ASSERT_EQ(op->data_length, 0); ASSERT_EQ(op->new_block, 52); - ASSERT_EQ(op->source, 0); + ASSERT_EQ(op->source_info, 0); iter->Next(); ASSERT_TRUE(iter->AtEnd()); @@ -212,10 +208,9 @@ TEST_F(CowTest, ReadWriteXor) { auto op = iter->Get(); ASSERT_EQ(op->type, kCowCopyOp); - ASSERT_EQ(op->compression, kCowCompressNone); ASSERT_EQ(op->data_length, 0); ASSERT_EQ(op->new_block, 10); - ASSERT_EQ(op->source, 20); + ASSERT_EQ(op->source_info, 20); std::string sink(data.size(), '\0'); @@ -237,20 +232,18 @@ TEST_F(CowTest, ReadWriteXor) { // Note: the zero operation gets split into two blocks. ASSERT_EQ(op->type, kCowZeroOp); - ASSERT_EQ(op->compression, kCowCompressNone); ASSERT_EQ(op->data_length, 0); ASSERT_EQ(op->new_block, 51); - ASSERT_EQ(op->source, 0); + ASSERT_EQ(op->source_info, 0); iter->Next(); ASSERT_FALSE(iter->AtEnd()); op = iter->Get(); ASSERT_EQ(op->type, kCowZeroOp); - ASSERT_EQ(op->compression, kCowCompressNone); ASSERT_EQ(op->data_length, 0); ASSERT_EQ(op->new_block, 52); - ASSERT_EQ(op->source, 0); + ASSERT_EQ(op->source_info, 0); iter->Next(); ASSERT_TRUE(iter->AtEnd()); @@ -677,7 +670,7 @@ TEST_F(CowTest, AppendLabelSmall) { ASSERT_FALSE(iter->AtEnd()); op = iter->Get(); ASSERT_EQ(op->type, kCowLabelOp); - ASSERT_EQ(op->source, 3); + ASSERT_EQ(op->source_info, 3); iter->Next(); @@ -730,7 +723,7 @@ TEST_F(CowTest, AppendLabelMissing) { ASSERT_FALSE(iter->AtEnd()); auto op = iter->Get(); ASSERT_EQ(op->type, kCowLabelOp); - ASSERT_EQ(op->source, 0); + ASSERT_EQ(op->source_info, 0); iter->Next(); @@ -788,7 +781,7 @@ TEST_F(CowTest, AppendExtendedCorrupted) { ASSERT_FALSE(iter->AtEnd()); auto op = iter->Get(); ASSERT_EQ(op->type, kCowLabelOp); - ASSERT_EQ(op->source, 5); + ASSERT_EQ(op->source_info, 5); iter->Next(); ASSERT_TRUE(iter->AtEnd()); @@ -857,7 +850,7 @@ TEST_F(CowTest, AppendbyLabel) { ASSERT_FALSE(iter->AtEnd()); op = iter->Get(); ASSERT_EQ(op->type, kCowLabelOp); - ASSERT_EQ(op->source, 4); + ASSERT_EQ(op->source_info, 4); iter->Next(); @@ -875,7 +868,7 @@ TEST_F(CowTest, AppendbyLabel) { ASSERT_FALSE(iter->AtEnd()); op = iter->Get(); ASSERT_EQ(op->type, kCowLabelOp); - ASSERT_EQ(op->source, 5); + ASSERT_EQ(op->source_info, 5); iter->Next(); @@ -928,7 +921,7 @@ TEST_F(CowTest, ClusterTest) { ASSERT_FALSE(iter->AtEnd()); op = iter->Get(); ASSERT_EQ(op->type, kCowLabelOp); - ASSERT_EQ(op->source, 4); + ASSERT_EQ(op->source_info, 4); iter->Next(); @@ -953,7 +946,7 @@ TEST_F(CowTest, ClusterTest) { ASSERT_FALSE(iter->AtEnd()); op = iter->Get(); ASSERT_EQ(op->type, kCowLabelOp); - ASSERT_EQ(op->source, 5); + ASSERT_EQ(op->source_info, 5); iter->Next(); @@ -972,7 +965,7 @@ TEST_F(CowTest, ClusterTest) { ASSERT_FALSE(iter->AtEnd()); op = iter->Get(); ASSERT_EQ(op->type, kCowLabelOp); - ASSERT_EQ(op->source, 6); + ASSERT_EQ(op->source_info, 6); iter->Next(); @@ -1019,7 +1012,7 @@ TEST_F(CowTest, ClusterAppendTest) { ASSERT_FALSE(iter->AtEnd()); auto op = iter->Get(); ASSERT_EQ(op->type, kCowLabelOp); - ASSERT_EQ(op->source, 50); + ASSERT_EQ(op->source_info, 50); iter->Next(); diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp index 699529b013f4..a52297ffc0ce 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp @@ -110,7 +110,7 @@ void CowWriterV2::SetupHeaders() { header_.prefix.minor_version = kCowVersionMinor; header_.prefix.header_size = sizeof(CowHeader); header_.footer_size = sizeof(CowFooter); - header_.op_size = sizeof(CowOperation); + header_.op_size = sizeof(CowOperationV2); header_.block_size = options_.block_size; header_.num_merge_ops = options_.num_merge_ops; header_.cluster_ops = options_.cluster_ops; @@ -159,9 +159,9 @@ void CowWriterV2::InitBatchWrites() { struct iovec* cowop_ptr = cowop_vec_.get(); struct iovec* data_ptr = data_vec_.get(); for (size_t i = 0; i < header_.cluster_ops; i++) { - std::unique_ptr op = std::make_unique(); + std::unique_ptr op = std::make_unique(); cowop_ptr[i].iov_base = op.get(); - cowop_ptr[i].iov_len = sizeof(CowOperation); + cowop_ptr[i].iov_len = sizeof(CowOperationV2); opbuffer_vec_.push_back(std::move(op)); std::unique_ptr buffer = std::make_unique(header_.block_size * 2); @@ -214,19 +214,19 @@ bool CowWriterV2::Initialize(std::optional label) { } void CowWriterV2::InitPos() { - next_op_pos_ = sizeof(header_) + header_.buffer_size; - cluster_size_ = header_.cluster_ops * sizeof(CowOperation); + next_op_pos_ = sizeof(CowHeader) + header_.buffer_size; + cluster_size_ = header_.cluster_ops * sizeof(CowOperationV2); if (header_.cluster_ops) { next_data_pos_ = next_op_pos_ + cluster_size_; } else { - next_data_pos_ = next_op_pos_ + sizeof(CowOperation); + next_data_pos_ = next_op_pos_ + sizeof(CowOperationV2); } current_cluster_size_ = 0; current_data_size_ = 0; } bool CowWriterV2::OpenForWrite() { - // This limitation is tied to the data field size in CowOperation. + // This limitation is tied to the data field size in CowOperationV2. if (header_.block_size > std::numeric_limits::max()) { LOG(ERROR) << "Block size is too large"; return false; @@ -313,7 +313,7 @@ bool CowWriterV2::EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_ CHECK(!merge_in_progress_); for (size_t i = 0; i < num_blocks; i++) { - CowOperation op = {}; + CowOperationV2 op = {}; op.type = kCowCopyOp; op.new_block = new_block + i; op.source = old_block + i; @@ -399,7 +399,7 @@ bool CowWriterV2::EmitBlocks(uint64_t new_block_start, const void* data, size_t num_blocks -= pending_blocks; while (i < size / header_.block_size && pending_blocks) { - CowOperation op = {}; + CowOperationV2 op = {}; op.new_block = new_block_start + i; op.type = type; if (type == kCowXorOp) { @@ -451,7 +451,7 @@ bool CowWriterV2::EmitBlocks(uint64_t new_block_start, const void* data, size_t bool CowWriterV2::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { CHECK(!merge_in_progress_); for (uint64_t i = 0; i < num_blocks; i++) { - CowOperation op = {}; + CowOperationV2 op = {}; op.type = kCowZeroOp; op.new_block = new_block_start + i; op.source = 0; @@ -462,7 +462,7 @@ bool CowWriterV2::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) bool CowWriterV2::EmitLabel(uint64_t label) { CHECK(!merge_in_progress_); - CowOperation op = {}; + CowOperationV2 op = {}; op.type = kCowLabelOp; op.source = label; return WriteOperation(op) && Sync(); @@ -473,7 +473,7 @@ bool CowWriterV2::EmitSequenceData(size_t num_ops, const uint32_t* data) { size_t to_add = 0; size_t max_ops = (header_.block_size * 2) / sizeof(uint32_t); while (num_ops > 0) { - CowOperation op = {}; + CowOperationV2 op = {}; op.type = kCowSequenceOp; op.source = next_data_pos_; to_add = std::min(num_ops, max_ops); @@ -489,16 +489,16 @@ bool CowWriterV2::EmitSequenceData(size_t num_ops, const uint32_t* data) { } bool CowWriterV2::EmitCluster() { - CowOperation op = {}; + CowOperationV2 op = {}; op.type = kCowClusterOp; // Next cluster starts after remainder of current cluster and the next data block. - op.source = current_data_size_ + cluster_size_ - current_cluster_size_ - sizeof(CowOperation); + op.source = current_data_size_ + cluster_size_ - current_cluster_size_ - sizeof(CowOperationV2); return WriteOperation(op); } bool CowWriterV2::EmitClusterIfNeeded() { // If there isn't room for another op and the cluster end op, end the current cluster - if (cluster_size_ && cluster_size_ < current_cluster_size_ + 2 * sizeof(CowOperation)) { + if (cluster_size_ && cluster_size_ < current_cluster_size_ + 2 * sizeof(CowOperationV2)) { if (!EmitCluster()) return false; } return true; @@ -539,7 +539,7 @@ bool CowWriterV2::Finalize() { extra_cluster = true; } - footer_.op.ops_size = footer_.op.num_ops * sizeof(CowOperation); + footer_.op.ops_size = footer_.op.num_ops * sizeof(CowOperationV2); if (lseek(fd_.get(), next_op_pos_, SEEK_SET) < 0) { PLOG(ERROR) << "Failed to seek to footer position."; return false; @@ -611,9 +611,9 @@ bool CowWriterV2::FlushCluster() { if (op_vec_index_) { ret = pwritev(fd_.get(), cowop_vec_.get(), op_vec_index_, current_op_pos_); - if (ret != (op_vec_index_ * sizeof(CowOperation))) { - PLOG(ERROR) << "pwritev failed for CowOperation. Expected: " - << (op_vec_index_ * sizeof(CowOperation)); + if (ret != (op_vec_index_ * sizeof(CowOperationV2))) { + PLOG(ERROR) << "pwritev failed for CowOperationV2. Expected: " + << (op_vec_index_ * sizeof(CowOperationV2)); return false; } } @@ -635,15 +635,16 @@ bool CowWriterV2::FlushCluster() { return true; } -bool CowWriterV2::WriteOperation(const CowOperation& op, const void* data, size_t size) { +bool CowWriterV2::WriteOperation(const CowOperationV2& op, const void* data, size_t size) { if (!EnsureSpaceAvailable(next_op_pos_ + sizeof(op)) || !EnsureSpaceAvailable(next_data_pos_ + size)) { return false; } if (batch_write_) { - CowOperation* cow_op = reinterpret_cast(cowop_vec_[op_vec_index_].iov_base); - std::memcpy(cow_op, &op, sizeof(CowOperation)); + CowOperationV2* cow_op = + reinterpret_cast(cowop_vec_[op_vec_index_].iov_base); + std::memcpy(cow_op, &op, sizeof(CowOperationV2)); op_vec_index_ += 1; if (data != nullptr && size > 0) { @@ -681,7 +682,7 @@ bool CowWriterV2::WriteOperation(const CowOperation& op, const void* data, size_ return EmitClusterIfNeeded(); } -void CowWriterV2::AddOperation(const CowOperation& op) { +void CowWriterV2::AddOperation(const CowOperationV2& op) { footer_.op.num_ops++; if (op.type == kCowClusterOp) { @@ -693,7 +694,7 @@ void CowWriterV2::AddOperation(const CowOperation& op) { } next_data_pos_ += op.data_length + GetNextDataOffset(op, header_.cluster_ops); - next_op_pos_ += sizeof(CowOperation) + GetNextOpOffset(op, header_.cluster_ops); + next_op_pos_ += sizeof(CowOperationV2) + GetNextOpOffset(op, header_.cluster_ops); } bool CowWriterV2::WriteRawData(const void* data, const size_t size) { diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h index 131a068455ba..c72a9b47c5d7 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h @@ -50,8 +50,8 @@ class CowWriterV2 : public CowWriterBase { bool OpenForAppend(uint64_t label); bool GetDataPos(uint64_t* pos); bool WriteRawData(const void* data, size_t size); - bool WriteOperation(const CowOperation& op, const void* data = nullptr, size_t size = 0); - void AddOperation(const CowOperation& op); + bool WriteOperation(const CowOperationV2& op, const void* data = nullptr, size_t size = 0); + void AddOperation(const CowOperationV2& op); void InitPos(); void InitBatchWrites(); void InitWorkers(); @@ -84,7 +84,7 @@ class CowWriterV2 : public CowWriterBase { std::vector> compressed_buf_; std::vector>::iterator buf_iter_; - std::vector> opbuffer_vec_; + std::vector> opbuffer_vec_; std::vector> databuffer_vec_; std::unique_ptr cowop_vec_; int op_vec_index_ = 0; From 4ac5b76d9661d77f79f4cad7476d207bf5c96d3d Mon Sep 17 00:00:00 2001 From: Harsh Abichandani Date: Fri, 23 Jun 2023 14:51:16 +0530 Subject: [PATCH 0435/1487] Added liblp_apis_fuzzer exec/s: 9393 Test: ./liblp_apis_fuzzer Bug: 285829660 Change-Id: I9830baf7ffbcffa7571aea75e69d1ced64fe613a --- fs_mgr/liblp/fuzzer/Android.bp | 143 +++++++++++++ fs_mgr/liblp/fuzzer/README.md | 43 ++++ fs_mgr/liblp/fuzzer/image_gen_rand.py | 32 +++ fs_mgr/liblp/fuzzer/liblp_apis_fuzzer.cpp | 243 ++++++++++++++++++++++ 4 files changed, 461 insertions(+) create mode 100644 fs_mgr/liblp/fuzzer/image_gen_rand.py create mode 100644 fs_mgr/liblp/fuzzer/liblp_apis_fuzzer.cpp diff --git a/fs_mgr/liblp/fuzzer/Android.bp b/fs_mgr/liblp/fuzzer/Android.bp index bdeb377bfe4e..a9e3509af7fa 100644 --- a/fs_mgr/liblp/fuzzer/Android.bp +++ b/fs_mgr/liblp/fuzzer/Android.bp @@ -56,3 +56,146 @@ cc_fuzz { srcs: ["liblp_super_layout_builder_fuzzer.cpp"], defaults: ["liblp_fuzz_defaults"], } + +python_binary_host { + name: "image_gen_rand", + srcs: ["image_gen_rand.py"], +} + +genrule_defaults { + name: "test_data_gen_defaults", + tools: [ + "image_gen_rand", + ], +} + +// Fake dtb image. +genrule { + name: "test_dtb", + defaults: ["test_data_gen_defaults"], + out: ["test_dtb.img"], + cmd: "$(location image_gen_rand) --seed dtb --length 1024 > $(out)", +} + +// Fake bootconfig image. +genrule { + name: "test_bootconfig", + defaults: ["test_data_gen_defaults"], + out: ["test_bootconfig.img"], + cmd: "$(location image_gen_rand) --seed bootconfig --length 1024 > $(out)", +} + +// Fake vendor ramdisk with type "none". +genrule { + name: "test_vendor_ramdisk_none", + defaults: ["test_data_gen_defaults"], + out: ["test_vendor_ramdisk_none.img"], + cmd: "$(location image_gen_rand) --seed vendor_ramdisk_none --length 1024 > $(out)", +} + +// Fake vendor ramdisk with type "platform". +genrule { + name: "test_vendor_ramdisk_platform", + defaults: ["test_data_gen_defaults"], + out: ["test_vendor_ramdisk_platform.img"], + cmd: "$(location image_gen_rand) --seed vendor_ramdisk_platform --length 1024 > $(out)", +} + +// Fake replacement ramdisk. +genrule { + name: "test_vendor_ramdisk_replace", + defaults: ["test_data_gen_defaults"], + out: ["test_vendor_ramdisk_replace.img"], + cmd: "$(location image_gen_rand) --seed replace --length 3072 > $(out)", +} + +// Genrules for test vendor boot images. +fastboot_sign_test_image = "$(location avbtool) add_hash_footer --salt 00 --image $(out) " + + "--partition_name vendor_boot --partition_size $$(( 1 * 1024 * 1024 ))" + +genrule_defaults { + name: "test_vendor_boot_gen_defaults", + defaults: ["test_data_gen_defaults"], + tools: [ + "avbtool", + "mkbootimg", + ], +} + +genrule { + name: "test_vendor_boot_v3", + defaults: ["test_vendor_boot_gen_defaults"], + out: ["test_vendor_boot_v3.img"], + srcs: [ + ":test_dtb", + ":test_vendor_ramdisk_none", + ], + cmd: "$(location mkbootimg) --header_version 3 " + + "--vendor_ramdisk $(location :test_vendor_ramdisk_none) " + + "--dtb $(location :test_dtb) " + + "--vendor_boot $(out) && " + + fastboot_sign_test_image, +} + +genrule { + name: "test_vendor_boot_v4_without_frag", + defaults: ["test_vendor_boot_gen_defaults"], + out: ["test_vendor_boot_v4_without_frag.img"], + srcs: [ + ":test_dtb", + ":test_vendor_ramdisk_none", + ":test_bootconfig", + ], + cmd: "$(location mkbootimg) --header_version 4 " + + "--vendor_ramdisk $(location :test_vendor_ramdisk_none) " + + "--dtb $(location :test_dtb) " + + "--vendor_bootconfig $(location :test_bootconfig) " + + "--vendor_boot $(out) && " + + fastboot_sign_test_image, +} + +genrule { + name: "test_vendor_boot_v4_with_frag", + defaults: ["test_vendor_boot_gen_defaults"], + out: ["test_vendor_boot_v4_with_frag.img"], + srcs: [ + ":test_dtb", + ":test_vendor_ramdisk_none", + ":test_vendor_ramdisk_platform", + ":test_bootconfig", + ], + cmd: "$(location mkbootimg) --header_version 4 " + + "--dtb $(location :test_dtb) " + + "--vendor_bootconfig $(location :test_bootconfig) " + + "--ramdisk_type none --ramdisk_name none_ramdisk " + + "--vendor_ramdisk_fragment $(location :test_vendor_ramdisk_none) " + + "--ramdisk_type platform --ramdisk_name platform_ramdisk " + + "--vendor_ramdisk_fragment $(location :test_vendor_ramdisk_platform) " + + "--vendor_boot $(out) && " + + fastboot_sign_test_image, +} + +cc_fuzz { + name: "liblp_apis_fuzzer", + srcs: [ + "liblp_apis_fuzzer.cpp", + ":TestPartitionOpener_group", + ], + defaults: ["liblp_fuzz_defaults"], + shared_libs: [ + "libsparse", + ], + data: [ + ":test_dtb", + ":test_bootconfig", + ":test_vendor_ramdisk_none", + ":test_vendor_ramdisk_platform", + ":test_vendor_ramdisk_replace", + ":test_vendor_boot_v3", + ":test_vendor_boot_v4_without_frag", + ":test_vendor_boot_v4_with_frag", + ], + cflags: [ + "-Wno-unused-parameter", + ], +} diff --git a/fs_mgr/liblp/fuzzer/README.md b/fs_mgr/liblp/fuzzer/README.md index be9adbd8e535..f831e2e5db8e 100644 --- a/fs_mgr/liblp/fuzzer/README.md +++ b/fs_mgr/liblp/fuzzer/README.md @@ -2,6 +2,7 @@ ## Table of contents + [liblp_builder_fuzzer](#Builder) + [liblp_super_layout_builder_fuzzer](#SuperBuilder) ++ [liblp_apis_fuzzer](#APIs) # Fuzzer for LiblpBuilder @@ -91,3 +92,45 @@ SuperLayoutBuilder supports the following parameters: $ adb sync data $ adb shell /data/fuzz/arm64/liblp_super_layout_builder_fuzzer/liblp_super_layout_builder_fuzzer ``` + +# Fuzzer for LiblpApis + +LiblpAPIs supports the following parameters: +1. blockDeviceInfoSize (parameter name: "block_device_info_size") +2. alignment (parameter name: "alignment") +3. alignmentOffset (parameter name: "alignment_offset") +4. logicalBlockSize (parameter name: "logical_block_size") +5. blockDevSize (parameter name: "blockdev_size") +6. metadataMaxSize (parameter name: "metadata_max_size") +7. metadataSlotCount (parameter name: "metadata_slot_count") +8. blockDeviceInfoName (parameter name: "block_device_info_name") +9. numSectors (parameter name: "num_sectors") +10. physicalSector (parameter name: "physical_sector") +11. sparsify (parameter name: "sparsify") +12. buffer (parameter name: "data") + +| Parameter| Valid Values| Configured Value| +|------------- |-------------| ----- | +|`blockDeviceInfoSize`| Integer |Value obtained from FuzzedDataProvider| +|`alignment`| Integer |Value obtained from FuzzedDataProvider| +|`alignmentOffset`| Integer |Value obtained from FuzzedDataProvider| +|`logicalBlockSize`| Integer |Value obtained from FuzzedDataProvider| +|`blockDevSize`| Integer value in multiples of `LP_SECTOR_SIZE`|Value obtained from FuzzedDataProvider| +|`metadataMaxSize`| Integer value from `0` to `10000` |Value obtained from FuzzedDataProvider| +|`metadataSlotCount`| Integer value from `0` to `2` |Value obtained from FuzzedDataProvider| +|`blockDeviceInfoName`| String |Value obtained from FuzzedDataProvider| +|`numSectors`| Integer value from `1` to `1000000` |Value obtained from FuzzedDataProvider| +|`physicalSector`| Integer value from `1` to `1000000` |Value obtained from FuzzedDataProvider| +|`alignment`| Bool |Value obtained from FuzzedDataProvider| +|`alignment`| Vector |Value obtained from FuzzedDataProvider| + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) liblp_apis_fuzzer +``` +2. Run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/liblp_apis_fuzzer/liblp_apis_fuzzer +``` diff --git a/fs_mgr/liblp/fuzzer/image_gen_rand.py b/fs_mgr/liblp/fuzzer/image_gen_rand.py new file mode 100644 index 000000000000..6e8547276102 --- /dev/null +++ b/fs_mgr/liblp/fuzzer/image_gen_rand.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2023 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. + +""" +Write given number of random bytes, generated with optional seed. +""" + +import random, argparse + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--seed', help='Seed to random generator') + parser.add_argument('--length', type=int, required=True, help='Length of output') + args = parser.parse_args() + + if args.seed: + random.seed(args.seed) + + print(''.join(chr(random.randrange(0,0xff)) for _ in range(args.length))) diff --git a/fs_mgr/liblp/fuzzer/liblp_apis_fuzzer.cpp b/fs_mgr/liblp/fuzzer/liblp_apis_fuzzer.cpp new file mode 100644 index 000000000000..b6fbc142a0c9 --- /dev/null +++ b/fs_mgr/liblp/fuzzer/liblp_apis_fuzzer.cpp @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2023 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 +#include +#include +#include +#include +#include +#include +#include +#include "images.h" +#include "test_partition_opener.h" + +using namespace std; +using namespace android; +using namespace android::fs_mgr; +using unique_fd = android::base::unique_fd; + +static constexpr size_t kDiskSize = 131072; +static constexpr size_t kMetadataSize = 512; +static constexpr size_t kMetadataSlots = 2; +static constexpr uint32_t kMaxBytes = 20; +static constexpr uint32_t kValidAlignment = 0; +static constexpr uint32_t kValidAlignmentOffset = 0; +static constexpr uint32_t kValidLogicalBlockSize = 4096; +static constexpr uint32_t kMinMetadataSize = 0; +static constexpr uint32_t kMaxMetadataSize = 10000; +static constexpr uint32_t kMinSlot = 0; +static constexpr uint32_t kMaxSlot = 10; +static constexpr uint32_t kMinFactor = 0; +static constexpr uint32_t kMaxFactor = 10; +static constexpr uint32_t kMetadataGeometrySize = 4096; +static constexpr uint64_t kValidNumSectors = 1901568; +static constexpr uint64_t kValidPhysicalSector = 3608576; +static constexpr uint64_t kMinSectorValue = 1; +static constexpr uint64_t kMaxSectorValue = 1000000; +static constexpr uint64_t kMaxBufferSize = 100000; + +const string kImageFile = "image_file"; +const string kSuperName = "super"; +const string kSystemPartitionName = "system"; +const string kPartitionName = "builder_partition"; +const string kSuperPartitionName = "super_partition"; + +const string kSuffix[] = {"_a", "_b", "a", "b"}; + +class LiplpApisFuzzer { + public: + LiplpApisFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; + void process(); + + private: + void setupBuilder(); + BlockDeviceInfo getBlockDevice(); + FuzzedDataProvider mFdp; + unique_ptr mBuilder; + string mBlockDeviceInfoName; + string mSuperPartitionName; + string mPartitionName; + const string mImagePaths[10] = { + "data/test_dtb.img", + "data/test_bootconfig.img", + "data/test_vendor_ramdisk_none.img", + "data/test_vendor_ramdisk_platform.img", + "data/test_vendor_ramdisk_replace.img", + "data/test_vendor_boot_v4_with_frag.img", + "data/test_vendor_boot_v4_without_frag.img", + "data/test_vendor_boot_v3.img", + "dev/null", + mFdp.ConsumeRandomLengthString(kMaxBytes), + }; +}; + +BlockDeviceInfo LiplpApisFuzzer::getBlockDevice() { + mBlockDeviceInfoName = + mFdp.ConsumeBool() ? kSuperName : mFdp.ConsumeRandomLengthString(kMaxBytes); + uint64_t blockDeviceInfoSize = + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() : kDiskSize; + uint32_t alignment = mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() : kValidAlignment; + uint32_t alignmentOffset = + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() : kValidAlignmentOffset; + uint32_t logicalBlockSize = + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() : kValidLogicalBlockSize; + + BlockDeviceInfo superInfo{mBlockDeviceInfoName, blockDeviceInfoSize, alignment, alignmentOffset, + logicalBlockSize}; + return superInfo; +} + +void LiplpApisFuzzer::setupBuilder() { + uint64_t randomBlockDevSize = + mFdp.ConsumeIntegralInRange(kMinFactor, kMaxFactor) * LP_SECTOR_SIZE; + uint64_t blockDevSize = mFdp.ConsumeBool() ? randomBlockDevSize : kDiskSize; + uint32_t randomMetadataMaxSize = + mFdp.ConsumeIntegralInRange(kMinMetadataSize, kMaxMetadataSize); + uint32_t metadataMaxSize = mFdp.ConsumeBool() ? kMetadataSize : randomMetadataMaxSize; + uint32_t metadataSlotCount = mFdp.ConsumeIntegralInRange(kMinSlot, kMaxSlot); + mBuilder = MetadataBuilder::New(blockDevSize, metadataMaxSize, metadataSlotCount); + + if (mBuilder.get()) { + mBuilder->AddPartition(kSystemPartitionName, LP_PARTITION_ATTR_READONLY); + + mPartitionName = + mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : kPartitionName; + if (!mPartitionName.size()) { + mPartitionName = kPartitionName; + } + mSuperPartitionName = mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) + : kSuperPartitionName; + if (!mSuperPartitionName.size()) { + mSuperPartitionName = kSuperPartitionName; + } + + Partition* super = mBuilder->AddPartition(mSuperPartitionName, LP_PARTITION_ATTR_READONLY); + mBuilder->AddPartition(mPartitionName, LP_PARTITION_ATTR_READONLY); + + int64_t numSectors = mFdp.ConsumeBool() ? mFdp.ConsumeIntegralInRange( + kMinSectorValue, kMaxSectorValue) + : kValidNumSectors; + int64_t physicalSector = mFdp.ConsumeBool() ? mFdp.ConsumeIntegralInRange( + kMinSectorValue, kMaxSectorValue) + : kValidPhysicalSector; + + mBuilder->AddLinearExtent(super, mBlockDeviceInfoName, numSectors, physicalSector); + } +} + +void LiplpApisFuzzer::process() { + BlockDeviceInfo superInfo = getBlockDevice(); + unique_fd fd(syscall(__NR_memfd_create, "image_file", MFD_ALLOW_SEALING)); + setupBuilder(); + + TestPartitionOpener opener( + {{mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : kSuperName, fd}}, + {{mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : kSuperName, + superInfo}}); + + if (mBuilder.get()) { + unique_ptr metadata = mBuilder->Export(); + const LpMetadata& metadataValue = *metadata.get(); + + map images = {}; + if (mFdp.ConsumeBool()) { + images[mSuperPartitionName] = mFdp.PickValueInArray(mImagePaths); + } + + while (mFdp.remaining_bytes()) { + auto invokeAPIs = mFdp.PickValueInArray>({ + [&]() { WriteToImageFile(fd, metadataValue); }, + [&]() { WriteToImageFile(kImageFile.c_str(), metadataValue); }, + [&]() { FlashPartitionTable(opener, kSuperName, metadataValue); }, + [&]() { + UpdatePartitionTable(opener, mPartitionName, metadataValue, + mFdp.ConsumeBool() ? 0 : 1 /* slot_number */); + }, + [&]() { + ReadMetadata(mPartitionName, mFdp.ConsumeBool() ? 0 : 1 /* slot_number */); + }, + [&]() { FlashPartitionTable(mPartitionName, metadataValue); }, + [&]() { + UpdatePartitionTable(mPartitionName, metadataValue, + mFdp.ConsumeBool() ? 0 : 1 /* slot_number */); + }, + [&]() { + WriteToImageFile(kImageFile.c_str(), metadataValue, + metadata->geometry.logical_block_size, images, + mFdp.ConsumeBool() ? true : false /* sparsify */); + }, + + [&]() { + WriteSplitImageFiles(kImageFile.c_str(), metadataValue, + metadata->geometry.logical_block_size, images, + mFdp.ConsumeBool() ? true : false /* sparsify */); + }, + [&]() { ReadFromImageFile(kImageFile.c_str()); }, + [&]() { IsEmptySuperImage(kImageFile.c_str()); }, + [&]() { + uint64_t bufferSize = mFdp.ConsumeIntegralInRange( + 2 * kMetadataGeometrySize, kMaxBufferSize); + vector buffer = mFdp.ConsumeBytes(kMaxBytes); + buffer.resize(bufferSize); + ReadFromImageBlob(buffer.data(), buffer.size()); + }, + [&]() { + uint32_t groupVectorSize = metadata->groups.size(); + uint32_t randomGroupIndex = + mFdp.ConsumeIntegralInRange(0, groupVectorSize); + GetPartitionGroupName(metadata->groups[randomGroupIndex]); + }, + [&]() { + uint32_t blockDeviceVectorSize = metadata->block_devices.size(); + uint32_t randomBlockDeviceIndex = + mFdp.ConsumeIntegralInRange(0, blockDeviceVectorSize); + GetBlockDevicePartitionName( + metadata->block_devices[randomBlockDeviceIndex]); + }, + [&]() { GetMetadataSuperBlockDevice(metadataValue); }, + [&]() { + string suffix = mFdp.ConsumeBool() + ? mFdp.PickValueInArray(kSuffix) + : mFdp.ConsumeRandomLengthString(kMaxBytes); + SlotNumberForSlotSuffix(suffix); + }, + [&]() { + auto entry = FindPartition(metadataValue, kSystemPartitionName); + GetPartitionSize(metadataValue, *entry); + }, + [&]() { GetPartitionSlotSuffix(mPartitionName); }, + [&]() { FindPartition(metadataValue, mPartitionName); }, + [&]() { + uint32_t partitionVectorSize = metadata->partitions.size(); + uint32_t randomPartitionIndex = + mFdp.ConsumeIntegralInRange(0, partitionVectorSize); + GetPartitionName(metadata->partitions[randomPartitionIndex]); + }, + [&]() { GetTotalSuperPartitionSize(metadataValue); }, + [&]() { GetBlockDevicePartitionNames(metadataValue); }, + }); + invokeAPIs(); + } + remove(kImageFile.c_str()); + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + LiplpApisFuzzer liplpApisFuzzer(data, size); + liplpApisFuzzer.process(); + return 0; +} From cffa413de4e91c62893b57959ac44b058d380e4a Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Mon, 2 Oct 2023 22:22:36 -0700 Subject: [PATCH 0436/1487] snapuserd: I/O request on overlapping blocks during snapshot-merge. This fixes the case when all the following conditions are true: 1: Incremental OTA 2: When there are sequence of overlapping COPY operations within one merge-window (510 blocks) 3: Device is rebooted when snapshot-merge is in-progress of this merge-window. When device reboots, the state of merge-window (of 510 blocks) was merge-in-progress (aka - only partial set of blocks were merged in this window thereby the state of the base device is in-complete for this window) 4: During the next boot, if there any I/O request from the filesystem which maps to the merge-window in (3): a: The data has to be retrieved from the scratch space of the COW until the snapshot-merge for that window is completed. b: Once the snapshot-merge is complete for that window, data has to be retrieved from base device. The bug was in step 4(a) wherein I/O request was getting routed to base device. This patch addresses the above flow by fixing step 4(a). A new vts test has been added to explicitly track this issue. Additionally, there is no need to re-scan the partition if partition is in merge resume path. This should cut down the overhead of the scan. Bug: 275296365 Test: 1: 100 iterations of ./vts_snapuserd_test --gtest_filter=SnapuserdTest.Snapshot_COPY_Overlap_Merge_Resume_IO_Validate_TEST 2: Incremental OTA on Pixel 6 Pro with multiple iterations of device reboot when merge is in progress Change-Id: Ib53be7f07ff192a84ec7f7049b2c6be01dad1041 Signed-off-by: Akilesh Kailash --- .../user-space-merge/snapuserd_core.cpp | 13 ++- .../user-space-merge/snapuserd_core.h | 4 + .../user-space-merge/snapuserd_readahead.cpp | 9 +- .../user-space-merge/snapuserd_test.cpp | 95 +++++++++++++++++++ .../snapuserd_transitions.cpp | 28 +++++- 5 files changed, 145 insertions(+), 4 deletions(-) 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 c2958512d1c1..e886ec399bee 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -173,6 +173,10 @@ bool SnapshotHandler::ReadMetadata() { } SNAP_LOG(INFO) << "Merge-ops: " << header.num_merge_ops; + if (header.num_merge_ops) { + resume_merge_ = true; + SNAP_LOG(INFO) << "Resume Snapshot-merge"; + } if (!MmapMetadata()) { SNAP_LOG(ERROR) << "mmap failed"; @@ -295,6 +299,11 @@ bool SnapshotHandler::Start() { if (ra_thread_) { ra_thread_status = std::async(std::launch::async, &ReadAhead::RunThread, read_ahead_thread_.get()); + // If this is a merge-resume path, wait until RA thread is fully up as + // the data has to be re-constructed from the scratch space. + if (resume_merge_ && ShouldReconstructDataFromCow()) { + WaitForRaThreadToStart(); + } } // Launch worker threads @@ -307,7 +316,9 @@ bool SnapshotHandler::Start() { std::async(std::launch::async, &MergeWorker::Run, merge_thread_.get()); // Now that the worker threads are up, scan the partitions. - if (perform_verification_) { + // If the snapshot-merge is being resumed, there is no need to scan as the + // current slot is already marked as boot complete. + if (perform_verification_ && !resume_merge_) { update_verify_->VerifyUpdatePartition(); } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index e401c118e893..f88406d2aa46 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -147,6 +147,8 @@ class SnapshotHandler : public std::enable_shared_from_this { void WakeupMonitorMergeThread(); void WaitForMergeComplete(); bool WaitForMergeBegin(); + void RaThreadStarted(); + void WaitForRaThreadToStart(); void NotifyRAForMergeReady(); bool WaitForMergeReady(); void MergeFailed(); @@ -221,6 +223,7 @@ class SnapshotHandler : public std::enable_shared_from_this { // Read-ahead related bool populate_data_from_cow_ = false; bool ra_thread_ = false; + bool ra_thread_started_ = false; int total_ra_blocks_merged_ = 0; MERGE_IO_TRANSITION io_state_ = MERGE_IO_TRANSITION::INVALID; std::unique_ptr read_ahead_thread_; @@ -242,6 +245,7 @@ class SnapshotHandler : public std::enable_shared_from_this { bool scratch_space_ = false; int num_worker_threads_ = kNumWorkerThreads; bool perform_verification_ = true; + bool resume_merge_ = false; std::unique_ptr ring_; std::unique_ptr update_verify_; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp index d2128c5d02fa..998d233d5ad1 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp @@ -206,6 +206,7 @@ bool ReadAhead::ReconstructDataFromCow() { return false; } + snapuserd_->RaThreadStarted(); SNAP_LOG(INFO) << "ReconstructDataFromCow success"; notify_read_ahead_failed.Cancel(); return true; @@ -716,9 +717,13 @@ bool ReadAhead::ReadAheadIOStart() { total_ra_blocks_completed_ += total_blocks_merged_; snapuserd_->SetMergedBlockCountForNextCommit(total_blocks_merged_); - // Flush the data only if we have a overlapping blocks in the region + // Flush the scratch data - Technically, we should flush only for overlapping + // blocks; However, since this region is mmap'ed, the dirty pages can still + // get flushed to disk at any random point in time. Instead, make sure + // the data in scratch is in the correct state before merge thread resumes. + // // Notify the Merge thread to resume merging this window - if (!snapuserd_->ReadAheadIOCompleted(overlap_)) { + if (!snapuserd_->ReadAheadIOCompleted(true)) { SNAP_LOG(ERROR) << "ReadAheadIOCompleted failed..."; snapuserd_->ReadAheadIOFailed(); return false; 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 620ecbd3f102..65f31cf7c7cb 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -235,9 +235,11 @@ class SnapuserdTest : public SnapuserdTestBase { bool Merge(); void ValidateMerge(); void ReadSnapshotDeviceAndValidate(); + void ReadSnapshotAndValidateOverlappingBlocks(); void Shutdown(); void MergeInterrupt(); void MergeInterruptFixed(int duration); + void MergeInterruptAndValidate(int duration); void MergeInterruptRandomly(int max_duration); bool StartMerge(); void CheckMergeCompletion(); @@ -358,6 +360,76 @@ void SnapuserdTest::ReadSnapshotDeviceAndValidate() { ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 4), size_), 0); } +void SnapuserdTest::ReadSnapshotAndValidateOverlappingBlocks() { + // Open COW device + unique_fd fd(open(cow_system_->path, O_RDONLY)); + ASSERT_GE(fd, 0); + + CowReader reader; + ASSERT_TRUE(reader.Parse(fd)); + + const auto& header = reader.GetHeader(); + size_t total_mapped_addr_length = header.prefix.header_size + BUFFER_REGION_DEFAULT_SIZE; + + ASSERT_GE(header.prefix.major_version, 2); + + void* mapped_addr = mmap(NULL, total_mapped_addr_length, PROT_READ, MAP_SHARED, fd.get(), 0); + ASSERT_NE(mapped_addr, MAP_FAILED); + + bool populate_data_from_scratch = false; + struct BufferState* ra_state = + reinterpret_cast((char*)mapped_addr + header.prefix.header_size); + if (ra_state->read_ahead_state == kCowReadAheadDone) { + populate_data_from_scratch = true; + } + + size_t num_merge_ops = header.num_merge_ops; + // We have some partial merge operations completed. + // To test the merge-resume path, forcefully corrupt the data of the base + // device for the offsets where the merge is still pending. + if (num_merge_ops && populate_data_from_scratch) { + std::string corrupt_buffer(4096, 0); + // Corrupt two blocks from the point where the merge has to be resumed by + // writing down zeroe's. + // + // Now, since this is a merge-resume path, the "correct" data should be + // in the scratch space of the COW device. When there is an I/O request + // from the snapshot device, the data has to be retrieved from the + // scratch space. If not and I/O is routed to the base device, we + // may end up with corruption. + off_t corrupt_offset = (num_merge_ops + 2) * 4096; + + if (corrupt_offset < size_) { + ASSERT_EQ(android::base::WriteFullyAtOffset(base_fd_, (void*)corrupt_buffer.c_str(), + 4096, corrupt_offset), + true); + corrupt_offset -= 4096; + ASSERT_EQ(android::base::WriteFullyAtOffset(base_fd_, (void*)corrupt_buffer.c_str(), + 4096, corrupt_offset), + true); + fsync(base_fd_.get()); + } + } + + // Time to read the snapshot device. + unique_fd snapshot_fd(open(dmuser_dev_->GetPath().c_str(), O_RDONLY | O_DIRECT | O_SYNC)); + ASSERT_GE(snapshot_fd, 0); + + void* buff_addr; + ASSERT_EQ(posix_memalign(&buff_addr, 4096, size_), 0); + + std::unique_ptr snapshot_buffer(buff_addr, ::free); + + // Scan the entire snapshot device and read the data and verify data + // integrity. Since the base device was forcefully corrupted, the data from + // this scan should be retrieved from scratch space of the COW partition. + // + // Furthermore, after the merge is complete, base device data is again + // verified as the aforementioned corrupted blocks aren't persisted. + ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapshot_buffer.get(), size_, 0), true); + ASSERT_EQ(memcmp(snapshot_buffer.get(), orig_buffer_.get(), size_), 0); +} + void SnapuserdTest::CreateCowDeviceWithCopyOverlap_2() { auto writer = CreateCowDeviceInternal(); ASSERT_NE(writer, nullptr); @@ -665,6 +737,20 @@ void SnapuserdTest::MergeInterruptFixed(int duration) { ASSERT_TRUE(Merge()); } +void SnapuserdTest::MergeInterruptAndValidate(int duration) { + ASSERT_TRUE(StartMerge()); + + for (int i = 0; i < 15; i++) { + std::this_thread::sleep_for(std::chrono::milliseconds(duration)); + ASSERT_NO_FATAL_FAILURE(SimulateDaemonRestart()); + ReadSnapshotAndValidateOverlappingBlocks(); + ASSERT_TRUE(StartMerge()); + } + + ASSERT_NO_FATAL_FAILURE(SimulateDaemonRestart()); + ASSERT_TRUE(Merge()); +} + void SnapuserdTest::MergeInterrupt() { // Interrupt merge at various intervals ASSERT_TRUE(StartMerge()); @@ -761,6 +847,15 @@ TEST_F(SnapuserdTest, Snapshot_COPY_Overlap_Merge_Resume_TEST) { ValidateMerge(); } +TEST_F(SnapuserdTest, Snapshot_COPY_Overlap_Merge_Resume_IO_Validate_TEST) { + if (!harness_->HasUserDevice()) { + GTEST_SKIP() << "Skipping snapshot read; not supported"; + } + ASSERT_NO_FATAL_FAILURE(SetupCopyOverlap_2()); + ASSERT_NO_FATAL_FAILURE(MergeInterruptAndValidate(2)); + ValidateMerge(); +} + TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Fixed_Ordered) { ASSERT_NO_FATAL_FAILURE(SetupOrderedOps()); ASSERT_NO_FATAL_FAILURE(MergeInterruptFixed(300)); diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp index f3e00195266a..8d090bf58955 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp @@ -366,6 +366,26 @@ void SnapshotHandler::WaitForMergeComplete() { } } +void SnapshotHandler::RaThreadStarted() { + std::unique_lock lock(lock_); + ra_thread_started_ = true; +} + +void SnapshotHandler::WaitForRaThreadToStart() { + auto now = std::chrono::system_clock::now(); + auto deadline = now + 3s; + { + std::unique_lock lock(lock_); + while (!ra_thread_started_) { + auto status = cv.wait_until(lock, deadline); + if (status == std::cv_status::timeout) { + SNAP_LOG(ERROR) << "Read-ahead thread did not start"; + return; + } + } + } +} + std::string SnapshotHandler::GetMergeStatus() { bool merge_not_initiated = false; bool merge_monitored = false; @@ -618,7 +638,6 @@ bool SnapshotHandler::GetRABuffer(std::unique_lock* lock, uint64_t b std::unordered_map::iterator it = read_ahead_buffer_map_.find(block); if (it == read_ahead_buffer_map_.end()) { - SNAP_LOG(ERROR) << "Block: " << block << " not found in RA buffer"; return false; } @@ -642,6 +661,13 @@ MERGE_GROUP_STATE SnapshotHandler::ProcessMergingBlock(uint64_t new_block, void* MERGE_GROUP_STATE state = blk_state->merge_state_; switch (state) { case MERGE_GROUP_STATE::GROUP_MERGE_PENDING: { + // If this is a merge-resume path, check if the data is + // available from scratch space. Data from scratch space takes + // higher precedence than from source device for overlapping + // blocks. + if (resume_merge_ && GetRABuffer(&lock, new_block, buffer)) { + return (MERGE_GROUP_STATE::GROUP_MERGE_IN_PROGRESS); + } blk_state->num_ios_in_progress += 1; // ref count [[fallthrough]]; } From 7fa8dd655ac242fef79184a611aa9e5d7a8c62eb Mon Sep 17 00:00:00 2001 From: Harry Pan Date: Tue, 3 Oct 2023 17:48:26 +0000 Subject: [PATCH 0437/1487] Add new fastbootd battery-soc variable Introduce new battery-soc variable to read battery SSOC, this benefits manufacturing to better track the SSOC after FSI image flashing in the userspace fastbootd using the same approach as Android space, otherwise it is difficult to implement the entire battery SW stack from Android to fastboot bootloader and generate the same test experience monotonically. Bug: 303561559 Test: fastboot getvar battery-soc # in fastbootd Change-Id: Ia3f68e314263d7dd4d4c45a908a0a49db6e761f9 Signed-off-by: Harry Pan --- fastboot/constants.h | 1 + fastboot/device/commands.cpp | 1 + fastboot/device/variables.cpp | 26 ++++++++++++++++++++++++++ fastboot/device/variables.h | 2 ++ 4 files changed, 30 insertions(+) diff --git a/fastboot/constants.h b/fastboot/constants.h index ad169d1dc5cc..a803307466da 100644 --- a/fastboot/constants.h +++ b/fastboot/constants.h @@ -69,6 +69,7 @@ #define FB_VAR_VARIANT "variant" #define FB_VAR_OFF_MODE_CHARGE_STATE "off-mode-charge" #define FB_VAR_BATTERY_VOLTAGE "battery-voltage" +#define FB_VAR_BATTERY_SOC "battery-soc" #define FB_VAR_BATTERY_SOC_OK "battery-soc-ok" #define FB_VAR_SUPER_PARTITION_NAME "super-partition-name" #define FB_VAR_SNAPSHOT_UPDATE_STATUS "snapshot-update-status" diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp index 6de598f6934d..bd936ae771dc 100644 --- a/fastboot/device/commands.cpp +++ b/fastboot/device/commands.cpp @@ -134,6 +134,7 @@ const std::unordered_map kVariableMap = { {FB_VAR_IS_FORCE_DEBUGGABLE, {GetIsForceDebuggable, nullptr}}, {FB_VAR_OFF_MODE_CHARGE_STATE, {GetOffModeChargeState, nullptr}}, {FB_VAR_BATTERY_VOLTAGE, {GetBatteryVoltage, nullptr}}, + {FB_VAR_BATTERY_SOC, {GetBatterySoC, nullptr}}, {FB_VAR_BATTERY_SOC_OK, {GetBatterySoCOk, nullptr}}, {FB_VAR_HW_REVISION, {GetHardwareRevision, nullptr}}, {FB_VAR_SUPER_PARTITION_NAME, {GetSuperPartitionName, nullptr}}, diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp index d2a794715ba8..2847e35ab6ad 100644 --- a/fastboot/device/variables.cpp +++ b/fastboot/device/variables.cpp @@ -130,6 +130,21 @@ bool GetBatteryVoltageHelper(FastbootDevice* device, int32_t* battery_voltage) { return true; } +bool GetBatterySoCHelper(FastbootDevice* device, int32_t* battery_soc) { + using aidl::android::hardware::health::HealthInfo; + + auto health_hal = device->health_hal(); + if (!health_hal) { + return false; + } + + HealthInfo health_info; + auto res = health_hal->getHealthInfo(&health_info); + if (!res.isOk()) return false; + *battery_soc = health_info.batteryLevel; + return true; +} + bool GetBatterySoCOk(FastbootDevice* device, const std::vector& /* args */, std::string* message) { int32_t battery_voltage = 0; @@ -185,6 +200,17 @@ bool GetBatteryVoltage(FastbootDevice* device, const std::vector& / return false; } +bool GetBatterySoC(FastbootDevice* device, const std::vector& /* args */, + std::string* message) { + int32_t battery_soc = 0; + if (GetBatterySoCHelper(device, &battery_soc)) { + *message = std::to_string(battery_soc); + return true; + } + *message = "Unable to get battery soc"; + return false; +} + bool GetCurrentSlot(FastbootDevice* device, const std::vector& /* args */, std::string* message) { std::string suffix = device->GetCurrentSlot(); diff --git a/fastboot/device/variables.h b/fastboot/device/variables.h index 3b2d48447473..9a46786410b9 100644 --- a/fastboot/device/variables.h +++ b/fastboot/device/variables.h @@ -63,6 +63,8 @@ bool GetOffModeChargeState(FastbootDevice* device, const std::vector& args, std::string* message); +bool GetBatterySoC(FastbootDevice* device, const std::vector& args, + std::string* message); bool GetBatterySoCOk(FastbootDevice* device, const std::vector& args, std::string* message); bool GetSuperPartitionName(FastbootDevice* device, const std::vector& args, From 1a3456f0bce99cdbec087cfb0199c113ca722304 Mon Sep 17 00:00:00 2001 From: Arun Sharma Date: Tue, 3 Oct 2023 14:55:48 -0700 Subject: [PATCH 0438/1487] FastbootDevice::boot1_1 null pointer dereference FastbootDevice::boot1_1 attempts to dereference a null pointer when the boot_control_hal_ is not set. It needs a guard statement to prevent that. Test: Manually tested on device without BootControl. Bug: 301682120 Change-Id: Id86bcb915c8e2857bda26f64738dd5b643048e98 --- fastboot/device/fastboot_device.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp index 6b6a9820e212..0dc4e97640c0 100644 --- a/fastboot/device/fastboot_device.cpp +++ b/fastboot/device/fastboot_device.cpp @@ -151,7 +151,8 @@ std::string FastbootDevice::GetCurrentSlot() { } BootControlClient* FastbootDevice::boot1_1() const { - if (boot_control_hal_->GetVersion() >= android::hal::BootControlVersion::BOOTCTL_V1_1) { + if (boot_control_hal_ && + boot_control_hal_->GetVersion() >= android::hal::BootControlVersion::BOOTCTL_V1_1) { return boot_control_hal_.get(); } return nullptr; From 3e9b88d50401177820c522bf2b762292c320368b Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Mon, 25 Sep 2023 16:41:05 -0700 Subject: [PATCH 0439/1487] Removing is_retrofit code path This code path was never invoked. is_logical will return false on secondary partitions in retrofit devices, so nothing actually is ever deleted. If we manage to call the delete, the device side code will fail with "cannot open the super partition" Test: fastboot flashall on sargo device Change-Id: I20b430c5c30bf992506190ea4e00b0b69c7b1005 --- fastboot/fastboot.cpp | 28 ---------------------------- fastboot/fastboot.h | 1 - 2 files changed, 29 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index b12e584d6506..56b90b98179b 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1414,21 +1414,6 @@ void do_for_partitions(const std::string& part, const std::string& slot, } } -bool is_retrofit_device(const ImageSource* source) { - // Does this device use dynamic partitions at all? - std::vector contents; - if (!source->ReadFile("super_empty.img", &contents)) { - return false; - } - auto metadata = android::fs_mgr::ReadFromImageBlob(contents.data(), contents.size()); - for (const auto& partition : metadata->partitions) { - if (partition.attributes & LP_PARTITION_ATTR_SLOT_SUFFIXED) { - return true; - } - } - return false; -} - // Fetch a partition from the device to a given fd. This is a wrapper over FetchToFd to fetch // the full image. static uint64_t fetch_partition(const std::string& partition, borrowed_fd fd, @@ -1880,19 +1865,6 @@ std::vector> FlashAllTool::CollectTasksFromImageList() { // Sync the super partition. This will reboot to userspace fastboot if needed. tasks.emplace_back(std::make_unique(fp_)); - for (const auto& [image, slot] : os_images_) { - // Retrofit devices have two super partitions, named super_a and super_b. - // On these devices, secondary slots must be flashed as physical - // partitions (otherwise they would not mount on first boot). To enforce - // this, we delete any logical partitions for the "other" slot. - if (is_retrofit_device(fp_->source.get())) { - std::string partition_name = image->part_name + "_" + slot; - if (image->IsSecondary() && - should_flash_in_userspace(fp_->source.get(), partition_name)) { - tasks.emplace_back(std::make_unique(fp_, partition_name)); - } - } - } AddFlashTasks(os_images_, tasks); diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index cd7bc2d982b6..2c40890b5105 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -188,7 +188,6 @@ int64_t get_sparse_limit(int64_t size, const FlashingPlan* fp); std::vector resparse_file(sparse_file* s, int64_t max_size); bool supports_AB(fastboot::IFastBootDriver* fb); -bool is_retrofit_device(const ImageSource* source); bool is_logical(const std::string& partition); void fb_perform_format(const std::string& partition, int skip_if_not_supported, const std::string& type_override, const std::string& size_override, From 5880692ae2dc37cd0c5d3bb7722b2cf55cc0b300 Mon Sep 17 00:00:00 2001 From: Sophia Coldren Date: Fri, 6 Oct 2023 18:46:11 +0000 Subject: [PATCH 0440/1487] Add an include Change-Id: I0a6c64d9f1ddd9211de994fd4c6c44d53499775f --- libcutils/socket_local_unix.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcutils/socket_local_unix.h b/libcutils/socket_local_unix.h index 45b9856b6040..ea98c0815a5f 100644 --- a/libcutils/socket_local_unix.h +++ b/libcutils/socket_local_unix.h @@ -17,6 +17,8 @@ #ifndef __SOCKET_LOCAL_H #define __SOCKET_LOCAL_H +#include + #define FILESYSTEM_SOCKET_PREFIX "/tmp/" #define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/" From d8a9a0c81c6d9da9d1a5118d19adbc1f9bd8522a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 6 Oct 2023 14:52:08 -0700 Subject: [PATCH 0441/1487] init: Remove arbitrary delay in async persist writes. Bug: 297093092 Test: manual test Change-Id: Ia80b33d2fe87aa5da64b4f156fefeb474e68dc93 --- init/property_service.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/init/property_service.cpp b/init/property_service.cpp index 2064fae8f14c..cdd0afe8b70a 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -1461,8 +1461,6 @@ void PersistWriteThread::Work() { work_.pop_front(); } - std::this_thread::sleep_for(1s); - // Perform write/fsync outside the lock. WritePersistentProperty(std::get<0>(item), std::get<1>(item)); NotifyPropertyChange(std::get<0>(item), std::get<1>(item)); From b02f94490dc84877c210eb1b46a9b57d96fc45b2 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Fri, 6 Oct 2023 23:11:09 +0000 Subject: [PATCH 0442/1487] libprocessgroup: Don't sleep after last cgroup removal attempt Currently we sleep for 5ms before decrementing retries for the last time. This is a waste of time, so bail out of the loop if the last rmdir attempt fails. Change-Id: Ia20840d27592b4eb3d9762647b19c111ff94209f --- libprocessgroup/processgroup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index 450643912e09..cc2565fadfa8 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -219,7 +219,7 @@ static int RemoveProcessGroup(const char* cgroup, uid_t uid, int pid, unsigned i while (retries--) { ret = rmdir(uid_pid_path.c_str()); - if (!ret || errno != EBUSY) break; + if (!ret || errno != EBUSY || !retries) break; std::this_thread::sleep_for(5ms); } From 066e625b6b74028f10848ce73a758bd8ea83f378 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Sat, 7 Oct 2023 00:29:44 +0000 Subject: [PATCH 0443/1487] libutils: use log/log.h internally utils/Log.h is one less file we need if we're splitting up this library for binder. Bug: 302720583 Test: build Change-Id: Ibc7ec5402df342627f465354d7cf59e98f450a31 --- libutils/CallStack.cpp | 2 +- libutils/FileMap.cpp | 2 +- libutils/Printer.cpp | 2 +- libutils/RefBase_fuzz.cpp | 2 +- libutils/StopWatch.cpp | 2 +- libutils/String16.cpp | 2 +- libutils/String8.cpp | 2 +- libutils/String8_test.cpp | 2 +- libutils/SystemClock.cpp | 2 +- libutils/Threads.cpp | 2 +- libutils/Timers.cpp | 2 +- libutils/Tokenizer.cpp | 2 +- libutils/Vector_fuzz.cpp | 2 +- libutils/misc.cpp | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp index 11f2c9262048..fe827eb0e208 100644 --- a/libutils/CallStack.cpp +++ b/libutils/CallStack.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp index 0abb86191f04..3acbce98b03e 100644 --- a/libutils/FileMap.cpp +++ b/libutils/FileMap.cpp @@ -21,7 +21,7 @@ #define LOG_TAG "filemap" #include -#include +#include #if defined(__MINGW32__) && !defined(__USE_MINGW_ANSI_STDIO) # define PRId32 "I32d" diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp index c9ae210ba7bc..4bd49f19e4ae 100644 --- a/libutils/Printer.cpp +++ b/libutils/Printer.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #include diff --git a/libutils/RefBase_fuzz.cpp b/libutils/RefBase_fuzz.cpp index 8291be93af52..05f47a0de6c8 100644 --- a/libutils/RefBase_fuzz.cpp +++ b/libutils/RefBase_fuzz.cpp @@ -19,7 +19,7 @@ #include #include "fuzzer/FuzzedDataProvider.h" -#include "utils/Log.h" +#include "log/log.h" #include "utils/RWLock.h" #include "utils/RefBase.h" #include "utils/StrongPointer.h" diff --git a/libutils/StopWatch.cpp b/libutils/StopWatch.cpp index 28e2d76bcf7e..c88d60fc0562 100644 --- a/libutils/StopWatch.cpp +++ b/libutils/StopWatch.cpp @@ -24,7 +24,7 @@ #endif #include -#include +#include namespace android { diff --git a/libutils/String16.cpp b/libutils/String16.cpp index 38d483e9495e..07a3d23f694c 100644 --- a/libutils/String16.cpp +++ b/libutils/String16.cpp @@ -16,7 +16,7 @@ #include -#include +#include #include diff --git a/libutils/String8.cpp b/libutils/String8.cpp index 4301f0ea3a77..6a754843117f 100644 --- a/libutils/String8.cpp +++ b/libutils/String8.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include diff --git a/libutils/String8_test.cpp b/libutils/String8_test.cpp index e1fd13a9e137..6f7882a3892b 100644 --- a/libutils/String8_test.cpp +++ b/libutils/String8_test.cpp @@ -16,7 +16,7 @@ #define LOG_TAG "String8_test" -#include +#include #include #include diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp index 9c71141f2d5a..df3a8986520e 100644 --- a/libutils/SystemClock.cpp +++ b/libutils/SystemClock.cpp @@ -30,7 +30,7 @@ #include #include -#include +#include namespace android { diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp index e756fecca001..90ea29b22887 100644 --- a/libutils/Threads.cpp +++ b/libutils/Threads.cpp @@ -34,7 +34,7 @@ #include #endif -#include +#include #if defined(__ANDROID__) #include diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp index 4cfac57be024..98082c95761d 100644 --- a/libutils/Timers.cpp +++ b/libutils/Timers.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include static constexpr size_t clock_id_max = 5; diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp index 9fc955c1a37d..aa097aeadba9 100644 --- a/libutils/Tokenizer.cpp +++ b/libutils/Tokenizer.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #ifndef DEBUG_TOKENIZER // Enables debug output for the tokenizer. diff --git a/libutils/Vector_fuzz.cpp b/libutils/Vector_fuzz.cpp index 6fd2baf17ca2..3cef4870915a 100644 --- a/libutils/Vector_fuzz.cpp +++ b/libutils/Vector_fuzz.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ #include -#include +#include #include #include diff --git a/libutils/misc.cpp b/libutils/misc.cpp index f77e1899ffe5..e1b5f013ccec 100644 --- a/libutils/misc.cpp +++ b/libutils/misc.cpp @@ -20,7 +20,7 @@ #include -#include +#include #include #if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__) From 0666c3a632e811fc1f49685ddfff21ce6b3efa34 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Sat, 7 Oct 2023 00:35:38 +0000 Subject: [PATCH 0444/1487] libutils: remove unused 'CALLSTACKS' This macro is set, but it doesn't exist. Bug: 302720583 Test: build Change-Id: I88032c24b8bc8dc52d521e769149cbd8f619dde8 --- libutils/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/libutils/Android.bp b/libutils/Android.bp index 2c05fbc24cc5..0f63df43d016 100644 --- a/libutils/Android.bp +++ b/libutils/Android.bp @@ -208,7 +208,6 @@ cc_library { defaults: ["libutils_impl_defaults"], cflags: [ - "-DCALLSTACKS=1", "-DDEBUG_POLL_AND_WAKE=1", "-DDEBUG_REFS=1", "-DDEBUG_TOKENIZER=1", From f75464d65e935a7216cbd3db5753716a9cd6e546 Mon Sep 17 00:00:00 2001 From: Yurii Shutkin Date: Mon, 9 Oct 2023 15:25:29 +0200 Subject: [PATCH 0445/1487] acvp: handle flush commond in modulewrapper as stated in BoringSSL. Change-Id: Ife655f0764851cf2d9677abd507daec3f531031e Bug: 287626912 Test: ACVP test --- trusty/utils/acvp/trusty_modulewrapper.cpp | 35 +++++++++++++++------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/trusty/utils/acvp/trusty_modulewrapper.cpp b/trusty/utils/acvp/trusty_modulewrapper.cpp index 70ffb52ec19c..85b7159d3ced 100644 --- a/trusty/utils/acvp/trusty_modulewrapper.cpp +++ b/trusty/utils/acvp/trusty_modulewrapper.cpp @@ -21,15 +21,16 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include -#include #include "acvp_ipc.h" @@ -208,6 +209,11 @@ Result ModuleWrapper::ForwardResponse() { return {}; } +static bool EqString(bssl::Span cmd, const char *str) { + return cmd.size() == strlen(str) && + memcmp(str, cmd.data(), cmd.size()) == 0; +} + int main() { for (;;) { auto buffer = bssl::acvp::RequestBuffer::New(); @@ -217,17 +223,24 @@ int main() { return EXIT_FAILURE; } - ModuleWrapper wrapper; - auto res = wrapper.SendMessage(args); - if (!res.ok()) { - std::cerr << res.error() << std::endl; - return EXIT_FAILURE; - } + if (EqString(args[0], "flush")) { + if (!bssl::acvp::FlushBuffer(STDOUT_FILENO)) { + ALOGE("Could not flush the buffer to stdout\n"); + return EXIT_FAILURE; + } + } else { + ModuleWrapper wrapper; + auto res = wrapper.SendMessage(args); + if (!res.ok()) { + std::cerr << res.error() << std::endl; + return EXIT_FAILURE; + } - res = wrapper.ForwardResponse(); - if (!res.ok()) { - std::cerr << res.error() << std::endl; - return EXIT_FAILURE; + res = wrapper.ForwardResponse(); + if (!res.ok()) { + std::cerr << res.error() << std::endl; + return EXIT_FAILURE; + } } } From 04e4c2a6c2ad0dd8d8380877cb5adf1fa9628293 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 12 Sep 2023 15:35:31 -0700 Subject: [PATCH 0446/1487] Add v3 writer Adding v3 writer that works off of Cow Operation v3. Adding test file that will test this new writer. Adding in stub implementations to v3 writer. None of these functions have to work yet, we just need the implementations here to compile. Test: m libsnapshot Change-Id: If86437d5ceb2c33520d4ca26dea5193984f86546 --- fs_mgr/libsnapshot/Android.bp | 2 + .../libsnapshot/libsnapshot_cow/test_v3.cpp | 53 ++++++++ .../libsnapshot/libsnapshot_cow/writer_v3.cpp | 117 ++++++++++++++++++ .../libsnapshot/libsnapshot_cow/writer_v3.h | 43 +++++++ 4 files changed, 215 insertions(+) create mode 100644 fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp create mode 100644 fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp create mode 100644 fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index fe47801f3f72..6fad6626655e 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -201,6 +201,7 @@ cc_library_static { "libsnapshot_cow/snapshot_reader.cpp", "libsnapshot_cow/writer_base.cpp", "libsnapshot_cow/writer_v2.cpp", + "libsnapshot_cow/writer_v3.cpp", ], export_include_dirs: ["include"], host_supported: true, @@ -392,6 +393,7 @@ cc_test { srcs: [ "libsnapshot_cow/snapshot_reader_test.cpp", "libsnapshot_cow/test_v2.cpp", + "libsnapshot_cow/test_v3.cpp", ], cflags: [ "-D_FILE_OFFSET_BITS=64", diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp new file mode 100644 index 000000000000..2373d4df5bf3 --- /dev/null +++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp @@ -0,0 +1,53 @@ +// Copyright (C) 2023 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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "cow_decompress.h" +#include "libsnapshot/cow_format.h" +#include "writer_v3.h" +using android::base::unique_fd; +using testing::AssertionFailure; +using testing::AssertionResult; +using testing::AssertionSuccess; + +namespace android { +namespace snapshot { + +class CowOperationV3Test : public ::testing::Test { + protected: + virtual void SetUp() override { + cow_ = std::make_unique(); + ASSERT_GE(cow_->fd, 0) << strerror(errno); + } + + virtual void TearDown() override { cow_ = nullptr; } + + unique_fd GetCowFd() { return unique_fd{dup(cow_->fd)}; } + + std::unique_ptr cow_; +}; + +} // namespace snapshot +} // namespace android \ No newline at end of file diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp new file mode 100644 index 000000000000..2b9867ef1b0c --- /dev/null +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp @@ -0,0 +1,117 @@ +// +// Copyright (C) 2020 The Android Open Source_info 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 "writer_v3.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// The info messages here are spammy, but as useful for update_engine. Disable +// them when running on the host. +#ifdef __ANDROID__ +#define LOG_INFO LOG(INFO) +#else +#define LOG_INFO LOG(VERBOSE) +#endif + +namespace android { +namespace snapshot { + +static_assert(sizeof(off_t) == sizeof(uint64_t)); + +using android::base::unique_fd; + +CowWriterV3::CowWriterV3(const CowOptions& options, unique_fd&& fd) + : CowWriterBase(options, std::move(fd)) {} + +CowWriterV3::~CowWriterV3() {} + +bool CowWriterV3::Initialize(std::optional label) { + LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; + if (label) return false; + return false; +} + +bool CowWriterV3::EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks) { + LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; + if (new_block || old_block || num_blocks) return false; + return false; +} + +bool CowWriterV3::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) { + LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; + + if (new_block_start || data || size) return false; + return false; +} + +bool CowWriterV3::EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, + uint32_t old_block, uint16_t offset) { + LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; + if (new_block_start || old_block || offset || data || size) return false; + return false; +} + +bool CowWriterV3::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { + LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; + if (new_block_start && num_blocks) return false; + return false; +} + +bool CowWriterV3::EmitLabel(uint64_t label) { + LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; + if (label) return false; + return false; +} + +bool CowWriterV3::EmitSequenceData(size_t num_ops, const uint32_t* data) { + LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; + if (num_ops && data) return false; + return false; +} + +bool CowWriterV3::Finalize() { + LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; + return false; +} + +uint64_t CowWriterV3::GetCowSize() { + LOG(ERROR) << __LINE__ << " " << __FILE__ + << " <- Get Cow Size function here should never be called"; + return 0; +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h new file mode 100644 index 000000000000..ddd72873c1b8 --- /dev/null +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h @@ -0,0 +1,43 @@ +// Copyright (C) 2023 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. + +#pragma once + +#include +#include "writer_base.h" + +namespace android { +namespace snapshot { + +class CowWriterV3 : public CowWriterBase { + public: + explicit CowWriterV3(const CowOptions& options, android::base::unique_fd&& fd); + ~CowWriterV3() override; + + bool Initialize(std::optional label = {}) override; + bool Finalize() override; + uint64_t GetCowSize() override; + + protected: + virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override; + virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override; + virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, + uint32_t old_block, uint16_t offset) override; + virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override; + virtual bool EmitLabel(uint64_t label) override; + virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) override; +}; + +} // namespace snapshot +} // namespace android From ce57c58e6b0efd4621e1c84abfce38f4e30deff3 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Thu, 5 Oct 2023 13:22:52 -0700 Subject: [PATCH 0447/1487] Removing compression bit from v3 op We don't need the compression bit in v3 op since all operations will have the same compression per COW Device and it will be stored within the COW header. We can check to see if an operation contains compressioned data by checking data_length and see if it's less than BLOCK_SZ Test: 4 critical OTA paths Change-Id: I3f86756d83bf54bf6efd15d9cb7ac064eefdd949 --- fs_mgr/libsnapshot/include/libsnapshot/cow_format.h | 4 ---- fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp | 5 ----- fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp | 1 - fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp | 6 ------ 4 files changed, 16 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h index 2a2cee2b72b5..1c92f9157fae 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h @@ -201,14 +201,10 @@ static constexpr uint8_t kCowReadAheadInProgress = 1; static constexpr uint8_t kCowReadAheadDone = 2; static constexpr uint64_t kCowOpSourceInfoDataMask = (1ULL << 48) - 1; -static constexpr uint64_t kCowOpSourceInfoCompressBit = (1ULL << 63); static inline uint64_t GetCowOpSourceInfoData(const CowOperation* op) { return op->source_info & kCowOpSourceInfoDataMask; } -static inline bool GetCowOpSourceInfoCompression(const CowOperation* op) { - return !!(op->source_info & kCowOpSourceInfoCompressBit); -} struct CowFooter { CowFooterOperation op; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp index 58dca64e19bd..5ab4f7a52226 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp @@ -83,11 +83,6 @@ std::ostream& operator<<(std::ostream& os, CowOperation const& op) { os << "CowOperation("; EmitCowTypeString(os, op.type); if (op.type == kCowReplaceOp || op.type == kCowXorOp || op.type == kCowSequenceOp) { - if (op.source_info & kCowOpSourceInfoCompressBit) { - os << ", compressed"; - } else { - os << ", uncompressed"; - } os << ", data_length:" << op.data_length; } if (op.type != kCowClusterOp && op.type != kCowSequenceOp && op.type != kCowLabelOp) { diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp index bf50f2f5eb2d..0285c175526f 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp @@ -136,7 +136,6 @@ bool CowReader::Parse(android::base::borrowed_fd fd, std::optional lab << v2_op.compression << ", op: " << v2_op; return false; } - source_info |= kCowOpSourceInfoCompressBit; } new_op.source_info = source_info; } diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp index 8f3f03f38f3f..100b13778a5b 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp @@ -143,7 +143,6 @@ TEST_F(CowTest, ReadWrite) { op = iter->Get(); ASSERT_EQ(op->type, kCowReplaceOp); - ASSERT_FALSE(GetCowOpSourceInfoCompression(op)); ASSERT_EQ(op->data_length, 4096); ASSERT_EQ(op->new_block, 50); ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size())); @@ -219,7 +218,6 @@ TEST_F(CowTest, ReadWriteXor) { op = iter->Get(); ASSERT_EQ(op->type, kCowXorOp); - ASSERT_FALSE(GetCowOpSourceInfoCompression(op)); ASSERT_EQ(op->data_length, 4096); ASSERT_EQ(op->new_block, 50); ASSERT_EQ(GetCowOpSourceInfoData(op), 98314); // 4096 * 24 + 10 @@ -276,7 +274,6 @@ TEST_F(CowTest, CompressGz) { std::string sink(data.size(), '\0'); ASSERT_EQ(op->type, kCowReplaceOp); - ASSERT_TRUE(GetCowOpSourceInfoCompression(op)); ASSERT_EQ(op->data_length, 56); // compressed! ASSERT_EQ(op->new_block, 50); ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size())); @@ -523,7 +520,6 @@ TEST_F(CowTest, ClusterCompressGz) { std::string sink(data.size(), '\0'); ASSERT_EQ(op->type, kCowReplaceOp); - ASSERT_TRUE(GetCowOpSourceInfoCompression(op)); ASSERT_EQ(op->data_length, 56); // compressed! ASSERT_EQ(op->new_block, 50); ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size())); @@ -541,7 +537,6 @@ TEST_F(CowTest, ClusterCompressGz) { sink = {}; sink.resize(data2.size(), '\0'); - ASSERT_TRUE(GetCowOpSourceInfoCompression(op)); ASSERT_EQ(op->data_length, 41); // compressed! ASSERT_EQ(op->new_block, 51); ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size())); @@ -586,7 +581,6 @@ TEST_F(CowTest, CompressTwoBlocks) { auto op = iter->Get(); ASSERT_EQ(op->type, kCowReplaceOp); - ASSERT_TRUE(GetCowOpSourceInfoCompression(op)); ASSERT_EQ(op->new_block, 51); ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size())); } From 7a1ca59839f3ebb8fd73037c7380af958e03ef07 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Sat, 7 Oct 2023 01:09:39 +0000 Subject: [PATCH 0448/1487] libutils: split out libutils_binder Dependencies of libbinder, so we can build a core libbinder library, libbinder_sdk. This is preparing the way to move this part of libbinder together with binder code into a single project. Bug: 302720583 Change-Id: Icff078ac6e36c7f2b91cf815d5b9ed19b2e706e1 --- libutils/Android.bp | 48 +- libutils/TEST_MAPPING | 3 + libutils/binder/Android.bp | 126 +++ libutils/{ => binder}/Errors.cpp | 0 libutils/{ => binder}/Errors_test.cpp | 0 libutils/{ => binder}/FuzzFormatTypes.h | 0 libutils/{ => binder}/RefBase.cpp | 13 +- libutils/{ => binder}/RefBase_fuzz.cpp | 0 libutils/{ => binder}/RefBase_test.cpp | 0 libutils/{ => binder}/SharedBuffer.cpp | 0 libutils/{ => binder}/SharedBuffer.h | 0 libutils/{ => binder}/SharedBuffer_test.cpp | 0 libutils/{ => binder}/String16.cpp | 0 libutils/{ => binder}/String16_fuzz.cpp | 0 libutils/{ => binder}/String16_test.cpp | 0 libutils/{ => binder}/String8.cpp | 0 libutils/{ => binder}/String8_fuzz.cpp | 0 libutils/{ => binder}/String8_test.cpp | 0 libutils/{ => binder}/StrongPointer.cpp | 0 libutils/{ => binder}/StrongPointer_test.cpp | 0 libutils/{ => binder}/Unicode.cpp | 0 libutils/{ => binder}/Unicode_test.cpp | 0 libutils/{ => binder}/VectorImpl.cpp | 0 libutils/{ => binder}/Vector_benchmark.cpp | 0 libutils/{ => binder}/Vector_fuzz.cpp | 0 libutils/{ => binder}/Vector_test.cpp | 0 libutils/binder/include/utils/Errors.h | 77 ++ libutils/binder/include/utils/RefBase.h | 819 +++++++++++++++++ libutils/binder/include/utils/String16.h | 383 ++++++++ libutils/binder/include/utils/String8.h | 354 ++++++++ libutils/binder/include/utils/StrongPointer.h | 361 ++++++++ libutils/binder/include/utils/Unicode.h | 139 +++ libutils/binder/include/utils/Vector.h | 418 +++++++++ libutils/binder/include/utils/VectorImpl.h | 182 ++++ libutils/include/utils/Errors.h | 78 +- libutils/include/utils/RefBase.h | 820 +----------------- libutils/include/utils/String16.h | 384 +------- libutils/include/utils/String8.h | 355 +------- libutils/include/utils/StrongPointer.h | 362 +------- libutils/include/utils/Unicode.h | 140 +-- libutils/include/utils/Vector.h | 419 +-------- libutils/include/utils/VectorImpl.h | 183 +--- 42 files changed, 2878 insertions(+), 2786 deletions(-) create mode 100644 libutils/binder/Android.bp rename libutils/{ => binder}/Errors.cpp (100%) rename libutils/{ => binder}/Errors_test.cpp (100%) rename libutils/{ => binder}/FuzzFormatTypes.h (100%) rename libutils/{ => binder}/RefBase.cpp (99%) rename libutils/{ => binder}/RefBase_fuzz.cpp (100%) rename libutils/{ => binder}/RefBase_test.cpp (100%) rename libutils/{ => binder}/SharedBuffer.cpp (100%) rename libutils/{ => binder}/SharedBuffer.h (100%) rename libutils/{ => binder}/SharedBuffer_test.cpp (100%) rename libutils/{ => binder}/String16.cpp (100%) rename libutils/{ => binder}/String16_fuzz.cpp (100%) rename libutils/{ => binder}/String16_test.cpp (100%) rename libutils/{ => binder}/String8.cpp (100%) rename libutils/{ => binder}/String8_fuzz.cpp (100%) rename libutils/{ => binder}/String8_test.cpp (100%) rename libutils/{ => binder}/StrongPointer.cpp (100%) rename libutils/{ => binder}/StrongPointer_test.cpp (100%) rename libutils/{ => binder}/Unicode.cpp (100%) rename libutils/{ => binder}/Unicode_test.cpp (100%) rename libutils/{ => binder}/VectorImpl.cpp (100%) rename libutils/{ => binder}/Vector_benchmark.cpp (100%) rename libutils/{ => binder}/Vector_fuzz.cpp (100%) rename libutils/{ => binder}/Vector_test.cpp (100%) create mode 100644 libutils/binder/include/utils/Errors.h create mode 100644 libutils/binder/include/utils/RefBase.h create mode 100644 libutils/binder/include/utils/String16.h create mode 100644 libutils/binder/include/utils/String8.h create mode 100644 libutils/binder/include/utils/StrongPointer.h create mode 100644 libutils/binder/include/utils/Unicode.h create mode 100644 libutils/binder/include/utils/Vector.h create mode 100644 libutils/binder/include/utils/VectorImpl.h mode change 100644 => 120000 libutils/include/utils/Errors.h mode change 100644 => 120000 libutils/include/utils/RefBase.h mode change 100644 => 120000 libutils/include/utils/String16.h mode change 100644 => 120000 libutils/include/utils/String8.h mode change 100644 => 120000 libutils/include/utils/StrongPointer.h mode change 100644 => 120000 libutils/include/utils/Unicode.h mode change 100644 => 120000 libutils/include/utils/Vector.h mode change 100644 => 120000 libutils/include/utils/VectorImpl.h diff --git a/libutils/Android.bp b/libutils/Android.bp index 0f63df43d016..b3ddda3b372d 100644 --- a/libutils/Android.bp +++ b/libutils/Android.bp @@ -132,25 +132,19 @@ cc_defaults { ], native_bridge_supported: true, + whole_static_libs: ["libutils_binder"], + srcs: [ - "Errors.cpp", "FileMap.cpp", "JenkinsHash.cpp", "LightRefBase.cpp", "NativeHandle.cpp", "Printer.cpp", - "RefBase.cpp", - "SharedBuffer.cpp", "StopWatch.cpp", - "String8.cpp", - "String16.cpp", - "StrongPointer.cpp", "SystemClock.cpp", "Threads.cpp", "Timers.cpp", "Tokenizer.cpp", - "Unicode.cpp", - "VectorImpl.cpp", "misc.cpp", ], @@ -273,24 +267,6 @@ cc_fuzz { srcs: ["FileMap_fuzz.cpp"], } -cc_fuzz { - name: "libutils_fuzz_string8", - defaults: ["libutils_fuzz_defaults"], - srcs: ["String8_fuzz.cpp"], -} - -cc_fuzz { - name: "libutils_fuzz_string16", - defaults: ["libutils_fuzz_defaults"], - srcs: ["String16_fuzz.cpp"], -} - -cc_fuzz { - name: "libutils_fuzz_vector", - defaults: ["libutils_fuzz_defaults"], - srcs: ["Vector_fuzz.cpp"], -} - cc_fuzz { name: "libutils_fuzz_printer", defaults: ["libutils_fuzz_defaults"], @@ -315,12 +291,6 @@ cc_fuzz { ], } -cc_fuzz { - name: "libutils_fuzz_refbase", - defaults: ["libutils_fuzz_defaults"], - srcs: ["RefBase_fuzz.cpp"], -} - cc_fuzz { name: "libutils_fuzz_lrucache", defaults: ["libutils_fuzz_defaults"], @@ -340,18 +310,11 @@ cc_test { srcs: [ "BitSet_test.cpp", "CallStack_test.cpp", - "Errors_test.cpp", "FileMap_test.cpp", "LruCache_test.cpp", "Mutex_test.cpp", - "SharedBuffer_test.cpp", "Singleton_test.cpp", - "String16_test.cpp", - "String8_test.cpp", - "StrongPointer_test.cpp", "Timers_test.cpp", - "Unicode_test.cpp", - "Vector_test.cpp", ], target: { @@ -373,7 +336,6 @@ cc_test { linux: { srcs: [ "Looper_test.cpp", - "RefBase_test.cpp", ], }, host: { @@ -427,9 +389,3 @@ cc_test_library { shared_libs: ["libutils_test_singleton1"], header_libs: ["libutils_headers"], } - -cc_benchmark { - name: "libutils_benchmark", - srcs: ["Vector_benchmark.cpp"], - shared_libs: ["libutils"], -} diff --git a/libutils/TEST_MAPPING b/libutils/TEST_MAPPING index c8ef45cc3ba5..472146f139de 100644 --- a/libutils/TEST_MAPPING +++ b/libutils/TEST_MAPPING @@ -2,6 +2,9 @@ "presubmit": [ { "name": "libutils_test" + }, + { + "name": "libutils_binder_test" } ] } diff --git a/libutils/binder/Android.bp b/libutils/binder/Android.bp new file mode 100644 index 000000000000..e2eddb332f0d --- /dev/null +++ b/libutils/binder/Android.bp @@ -0,0 +1,126 @@ +package { + default_applicable_licenses: ["system_core_libutils_license"], +} + +cc_defaults { + name: "libutils_binder_impl_defaults", + defaults: [ + "libutils_defaults", + "apex-lowest-min-sdk-version", + ], + native_bridge_supported: true, + + srcs: [ + "Errors.cpp", + "RefBase.cpp", + "SharedBuffer.cpp", + "String16.cpp", + "String8.cpp", + "StrongPointer.cpp", + "Unicode.cpp", + "VectorImpl.cpp", + ], + + apex_available: [ + "//apex_available:anyapex", + "//apex_available:platform", + ], + + afdo: true, +} + +cc_library { + name: "libutils_binder", + defaults: ["libutils_binder_impl_defaults"], +} + +cc_library { + name: "libutils_binder_test_compile", + defaults: ["libutils_binder_impl_defaults"], + + cflags: [ + "-DDEBUG_REFS=1", + ], + + visibility: [":__subpackages__"], +} + +cc_fuzz { + name: "libutils_fuzz_string8", + defaults: ["libutils_fuzz_defaults"], + srcs: ["String8_fuzz.cpp"], +} + +cc_fuzz { + name: "libutils_fuzz_string16", + defaults: ["libutils_fuzz_defaults"], + srcs: ["String16_fuzz.cpp"], +} + +cc_fuzz { + name: "libutils_fuzz_vector", + defaults: ["libutils_fuzz_defaults"], + srcs: ["Vector_fuzz.cpp"], +} + +cc_fuzz { + name: "libutils_fuzz_refbase", + defaults: ["libutils_fuzz_defaults"], + srcs: ["RefBase_fuzz.cpp"], +} + +cc_test { + name: "libutils_binder_test", + host_supported: true, + + srcs: [ + "Errors_test.cpp", + "SharedBuffer_test.cpp", + "String16_test.cpp", + "String8_test.cpp", + "StrongPointer_test.cpp", + "Unicode_test.cpp", + "Vector_test.cpp", + ], + + target: { + android: { + shared_libs: [ + "libbase", + "libcutils", + "liblog", + "liblzma", + "libutils", // which includes libutils_binder + "libz", + ], + }, + linux: { + srcs: [ + "RefBase_test.cpp", + ], + }, + host: { + static_libs: [ + "libbase", + "liblog", + "liblzma", + "libutils", // which includes libutils_binder + ], + }, + }, + + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-Wthread-safety", + ], + + test_suites: ["device-tests"], +} + +cc_benchmark { + name: "libutils_binder_benchmark", + srcs: ["Vector_benchmark.cpp"], + shared_libs: ["libutils"], +} diff --git a/libutils/Errors.cpp b/libutils/binder/Errors.cpp similarity index 100% rename from libutils/Errors.cpp rename to libutils/binder/Errors.cpp diff --git a/libutils/Errors_test.cpp b/libutils/binder/Errors_test.cpp similarity index 100% rename from libutils/Errors_test.cpp rename to libutils/binder/Errors_test.cpp diff --git a/libutils/FuzzFormatTypes.h b/libutils/binder/FuzzFormatTypes.h similarity index 100% rename from libutils/FuzzFormatTypes.h rename to libutils/binder/FuzzFormatTypes.h diff --git a/libutils/RefBase.cpp b/libutils/binder/RefBase.cpp similarity index 99% rename from libutils/RefBase.cpp rename to libutils/binder/RefBase.cpp index e0a2846d4a7a..c7055fb48350 100644 --- a/libutils/RefBase.cpp +++ b/libutils/binder/RefBase.cpp @@ -18,6 +18,7 @@ // #define LOG_NDEBUG 0 #include +#include #include @@ -27,8 +28,6 @@ #include #include -#include - #ifndef __unused #define __unused __attribute__((__unused__)) #endif @@ -310,7 +309,7 @@ class RefBase::weakref_impl : public RefBase::weakref_type String8 text; { - Mutex::Autolock _l(mMutex); + std::lock_guard _l(mMutex); char buf[128]; snprintf(buf, sizeof(buf), "Strong references on RefBase %p (weakref_type %p):\n", @@ -353,7 +352,7 @@ class RefBase::weakref_impl : public RefBase::weakref_type void addRef(ref_entry** refs, const void* id, int32_t mRef) { if (mTrackEnabled) { - AutoMutex _l(mMutex); + std::lock_guard _l(mMutex); ref_entry* ref = new ref_entry; // Reference count at the time of the snapshot, but before the @@ -372,7 +371,7 @@ class RefBase::weakref_impl : public RefBase::weakref_type void removeRef(ref_entry** refs, const void* id) { if (mTrackEnabled) { - AutoMutex _l(mMutex); + std::lock_guard _l(mMutex); ref_entry* const head = *refs; ref_entry* ref = head; @@ -406,7 +405,7 @@ class RefBase::weakref_impl : public RefBase::weakref_type void renameRefsId(ref_entry* r, const void* old_id, const void* new_id) { if (mTrackEnabled) { - AutoMutex _l(mMutex); + std::lock_guard _l(mMutex); ref_entry* ref = r; while (ref != NULL) { if (ref->id == old_id) { @@ -434,7 +433,7 @@ class RefBase::weakref_impl : public RefBase::weakref_type } } - mutable Mutex mMutex; + mutable std::mutex mMutex; ref_entry* mStrongRefs; ref_entry* mWeakRefs; diff --git a/libutils/RefBase_fuzz.cpp b/libutils/binder/RefBase_fuzz.cpp similarity index 100% rename from libutils/RefBase_fuzz.cpp rename to libutils/binder/RefBase_fuzz.cpp diff --git a/libutils/RefBase_test.cpp b/libutils/binder/RefBase_test.cpp similarity index 100% rename from libutils/RefBase_test.cpp rename to libutils/binder/RefBase_test.cpp diff --git a/libutils/SharedBuffer.cpp b/libutils/binder/SharedBuffer.cpp similarity index 100% rename from libutils/SharedBuffer.cpp rename to libutils/binder/SharedBuffer.cpp diff --git a/libutils/SharedBuffer.h b/libutils/binder/SharedBuffer.h similarity index 100% rename from libutils/SharedBuffer.h rename to libutils/binder/SharedBuffer.h diff --git a/libutils/SharedBuffer_test.cpp b/libutils/binder/SharedBuffer_test.cpp similarity index 100% rename from libutils/SharedBuffer_test.cpp rename to libutils/binder/SharedBuffer_test.cpp diff --git a/libutils/String16.cpp b/libutils/binder/String16.cpp similarity index 100% rename from libutils/String16.cpp rename to libutils/binder/String16.cpp diff --git a/libutils/String16_fuzz.cpp b/libutils/binder/String16_fuzz.cpp similarity index 100% rename from libutils/String16_fuzz.cpp rename to libutils/binder/String16_fuzz.cpp diff --git a/libutils/String16_test.cpp b/libutils/binder/String16_test.cpp similarity index 100% rename from libutils/String16_test.cpp rename to libutils/binder/String16_test.cpp diff --git a/libutils/String8.cpp b/libutils/binder/String8.cpp similarity index 100% rename from libutils/String8.cpp rename to libutils/binder/String8.cpp diff --git a/libutils/String8_fuzz.cpp b/libutils/binder/String8_fuzz.cpp similarity index 100% rename from libutils/String8_fuzz.cpp rename to libutils/binder/String8_fuzz.cpp diff --git a/libutils/String8_test.cpp b/libutils/binder/String8_test.cpp similarity index 100% rename from libutils/String8_test.cpp rename to libutils/binder/String8_test.cpp diff --git a/libutils/StrongPointer.cpp b/libutils/binder/StrongPointer.cpp similarity index 100% rename from libutils/StrongPointer.cpp rename to libutils/binder/StrongPointer.cpp diff --git a/libutils/StrongPointer_test.cpp b/libutils/binder/StrongPointer_test.cpp similarity index 100% rename from libutils/StrongPointer_test.cpp rename to libutils/binder/StrongPointer_test.cpp diff --git a/libutils/Unicode.cpp b/libutils/binder/Unicode.cpp similarity index 100% rename from libutils/Unicode.cpp rename to libutils/binder/Unicode.cpp diff --git a/libutils/Unicode_test.cpp b/libutils/binder/Unicode_test.cpp similarity index 100% rename from libutils/Unicode_test.cpp rename to libutils/binder/Unicode_test.cpp diff --git a/libutils/VectorImpl.cpp b/libutils/binder/VectorImpl.cpp similarity index 100% rename from libutils/VectorImpl.cpp rename to libutils/binder/VectorImpl.cpp diff --git a/libutils/Vector_benchmark.cpp b/libutils/binder/Vector_benchmark.cpp similarity index 100% rename from libutils/Vector_benchmark.cpp rename to libutils/binder/Vector_benchmark.cpp diff --git a/libutils/Vector_fuzz.cpp b/libutils/binder/Vector_fuzz.cpp similarity index 100% rename from libutils/Vector_fuzz.cpp rename to libutils/binder/Vector_fuzz.cpp diff --git a/libutils/Vector_test.cpp b/libutils/binder/Vector_test.cpp similarity index 100% rename from libutils/Vector_test.cpp rename to libutils/binder/Vector_test.cpp diff --git a/libutils/binder/include/utils/Errors.h b/libutils/binder/include/utils/Errors.h new file mode 100644 index 000000000000..22fb36d2500e --- /dev/null +++ b/libutils/binder/include/utils/Errors.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2007 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. + */ + +#pragma once + +#include +#include +#include +#include + +namespace android { + +/** + * The type used to return success/failure from frameworks APIs. + * See the anonymous enum below for valid values. + */ +typedef int32_t status_t; + +/* + * Error codes. + * All error codes are negative values. + */ + +enum { + OK = 0, // Preferred constant for checking success. +#ifndef NO_ERROR + // Win32 #defines NO_ERROR as well. It has the same value, so there's no + // real conflict, though it's a bit awkward. + NO_ERROR = OK, // Deprecated synonym for `OK`. Prefer `OK` because it doesn't conflict with Windows. +#endif + + UNKNOWN_ERROR = (-2147483647-1), // INT32_MIN value + + NO_MEMORY = -ENOMEM, + INVALID_OPERATION = -ENOSYS, + BAD_VALUE = -EINVAL, + BAD_TYPE = (UNKNOWN_ERROR + 1), + NAME_NOT_FOUND = -ENOENT, + PERMISSION_DENIED = -EPERM, + NO_INIT = -ENODEV, + ALREADY_EXISTS = -EEXIST, + DEAD_OBJECT = -EPIPE, + FAILED_TRANSACTION = (UNKNOWN_ERROR + 2), +#if !defined(_WIN32) + BAD_INDEX = -EOVERFLOW, + NOT_ENOUGH_DATA = -ENODATA, + WOULD_BLOCK = -EWOULDBLOCK, + TIMED_OUT = -ETIMEDOUT, + UNKNOWN_TRANSACTION = -EBADMSG, +#else + BAD_INDEX = -E2BIG, + NOT_ENOUGH_DATA = (UNKNOWN_ERROR + 3), + WOULD_BLOCK = (UNKNOWN_ERROR + 4), + TIMED_OUT = (UNKNOWN_ERROR + 5), + UNKNOWN_TRANSACTION = (UNKNOWN_ERROR + 6), +#endif + FDS_NOT_ALLOWED = (UNKNOWN_ERROR + 7), + UNEXPECTED_NULL = (UNKNOWN_ERROR + 8), +}; + +// Human readable name of error +std::string statusToString(status_t status); + +} // namespace android diff --git a/libutils/binder/include/utils/RefBase.h b/libutils/binder/include/utils/RefBase.h new file mode 100644 index 000000000000..5e3fa7d13c8a --- /dev/null +++ b/libutils/binder/include/utils/RefBase.h @@ -0,0 +1,819 @@ +/* + * Copyright (C) 2016 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. + */ + + +// SOME COMMENTS ABOUT USAGE: + +// This provides primarily wp<> weak pointer types and RefBase, which work +// together with sp<> from . + +// sp<> (and wp<>) are a type of smart pointer that use a well defined protocol +// to operate. As long as the object they are templated with implements that +// protocol, these smart pointers work. In several places the platform +// instantiates sp<> with non-RefBase objects; the two are not tied to each +// other. + +// RefBase is such an implementation and it supports strong pointers, weak +// pointers and some magic features for the binder. + +// So, when using RefBase objects, you have the ability to use strong and weak +// pointers through sp<> and wp<>. + +// Normally, when the last strong pointer goes away, the object is destroyed, +// i.e. it's destructor is called. HOWEVER, parts of its associated memory is not +// freed until the last weak pointer is released. + +// Weak pointers are essentially "safe" pointers. They are always safe to +// access through promote(). They may return nullptr if the object was +// destroyed because it ran out of strong pointers. This makes them good candidates +// for keys in a cache for instance. + +// Weak pointers remain valid for comparison purposes even after the underlying +// object has been destroyed. Even if object A is destroyed and its memory reused +// for B, A remaining weak pointer to A will not compare equal to one to B. +// This again makes them attractive for use as keys. + +// How is this supposed / intended to be used? + +// Our recommendation is to use strong references (sp<>) when there is an +// ownership relation. e.g. when an object "owns" another one, use a strong +// ref. And of course use strong refs as arguments of functions (it's extremely +// rare that a function will take a wp<>). + +// Typically a newly allocated object will immediately be used to initialize +// a strong pointer, which may then be used to construct or assign to other +// strong and weak pointers. + +// Use weak references when there are no ownership relation. e.g. the keys in a +// cache (you cannot use plain pointers because there is no safe way to acquire +// a strong reference from a vanilla pointer). + +// This implies that two objects should never (or very rarely) have sp<> on +// each other, because they can't both own each other. + + +// Caveats with reference counting + +// Obviously, circular strong references are a big problem; this creates leaks +// and it's hard to debug -- except it's in fact really easy because RefBase has +// tons of debugging code for that. It can basically tell you exactly where the +// leak is. + +// Another problem has to do with destructors with side effects. You must +// assume that the destructor of reference counted objects can be called AT ANY +// TIME. For instance code as simple as this: + +// void setStuff(const sp& stuff) { +// std::lock_guard lock(mMutex); +// mStuff = stuff; +// } + +// is very dangerous. This code WILL deadlock one day or another. + +// What isn't obvious is that ~Stuff() can be called as a result of the +// assignment. And it gets called with the lock held. First of all, the lock is +// protecting mStuff, not ~Stuff(). Secondly, if ~Stuff() uses its own internal +// mutex, now you have mutex ordering issues. Even worse, if ~Stuff() is +// virtual, now you're calling into "user" code (potentially), by that, I mean, +// code you didn't even write. + +// A correct way to write this code is something like: + +// void setStuff(const sp& stuff) { +// std::unique_lock lock(mMutex); +// sp hold = mStuff; +// mStuff = stuff; +// lock.unlock(); +// } + +// More importantly, reference counted objects should do as little work as +// possible in their destructor, or at least be mindful that their destructor +// could be called from very weird and unintended places. + +// Other more specific restrictions for wp<> and sp<>: + +// Do not construct a strong pointer to "this" in an object's constructor. +// The onFirstRef() callback would be made on an incompletely constructed +// object. +// Construction of a weak pointer to "this" in an object's constructor is also +// discouraged. But the implementation was recently changed so that, in the +// absence of extendObjectLifetime() calls, weak pointers no longer impact +// object lifetime, and hence this no longer risks premature deallocation, +// and hence usually works correctly. + +// Such strong or weak pointers can be safely created in the RefBase onFirstRef() +// callback. + +// Use of wp::unsafe_get() for any purpose other than debugging is almost +// always wrong. Unless you somehow know that there is a longer-lived sp<> to +// the same object, it may well return a pointer to a deallocated object that +// has since been reallocated for a different purpose. (And if you know there +// is a longer-lived sp<>, why not use an sp<> directly?) A wp<> should only be +// dereferenced by using promote(). + +// Any object inheriting from RefBase should always be destroyed as the result +// of a reference count decrement, not via any other means. Such objects +// should never be stack allocated, or appear directly as data members in other +// objects. Objects inheriting from RefBase should have their strong reference +// count incremented as soon as possible after construction. Usually this +// will be done via construction of an sp<> to the object, but may instead +// involve other means of calling RefBase::incStrong(). +// Explicitly deleting or otherwise destroying a RefBase object with outstanding +// wp<> or sp<> pointers to it will result in an abort or heap corruption. + +// It is particularly important not to mix sp<> and direct storage management +// since the sp from raw pointer constructor is implicit. Thus if a RefBase- +// -derived object of type T is managed without ever incrementing its strong +// count, and accidentally passed to f(sp), a strong pointer to the object +// will be temporarily constructed and destroyed, prematurely deallocating the +// object, and resulting in heap corruption. None of this would be easily +// visible in the source. See below on +// ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION for a compile time +// option which helps avoid this case. + +// Extra Features: + +// RefBase::extendObjectLifetime() can be used to prevent destruction of the +// object while there are still weak references. This is really special purpose +// functionality to support Binder. + +// Wp::promote(), implemented via the attemptIncStrong() member function, is +// used to try to convert a weak pointer back to a strong pointer. It's the +// normal way to try to access the fields of an object referenced only through +// a wp<>. Binder code also sometimes uses attemptIncStrong() directly. + +// RefBase provides a number of additional callbacks for certain reference count +// events, as well as some debugging facilities. + +// Debugging support can be enabled by turning on DEBUG_REFS in RefBase.cpp. +// Otherwise little checking is provided. + +// Thread safety: + +// Like std::shared_ptr, sp<> and wp<> allow concurrent accesses to DIFFERENT +// sp<> and wp<> instances that happen to refer to the same underlying object. +// They do NOT support concurrent access (where at least one access is a write) +// to THE SAME sp<> or wp<>. In effect, their thread-safety properties are +// exactly like those of T*, NOT atomic. + +// Safety option: ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION +// +// This flag makes the semantics for using a RefBase object with wp<> and sp<> +// much stricter by disabling implicit conversion from raw pointers to these +// objects. In order to use this, apply this flag in Android.bp like so: +// +// cflags: [ +// "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION", +// ], +// +// REGARDLESS of whether this flag is on, best usage of sp<> is shown below. If +// this flag is on, no other usage is possible (directly calling RefBase methods +// is possible, but seeing code using 'incStrong' instead of 'sp<>', for +// instance, should already set off big alarm bells. With carefully constructed +// data structures, it should NEVER be necessary to directly use RefBase +// methods). Proper RefBase usage: +// +// class Foo : virtual public RefBase { ... }; +// +// // always construct an sp object with sp::make +// sp myFoo = sp::make(/*args*/); +// +// // if you need a weak pointer, it must be constructed from a strong +// // pointer +// wp weakFoo = myFoo; // NOT myFoo.get() +// +// // If you are inside of a method of Foo and need access to a strong +// // explicitly call this function. This documents your intention to code +// // readers, and it will give a runtime error for what otherwise would +// // be potential double ownership +// .... Foo::someMethod(...) { +// // asserts if there is a memory issue +// sp thiz = sp::fromExisting(this); +// } +// + +#ifndef ANDROID_REF_BASE_H +#define ANDROID_REF_BASE_H + +#include +#include +#include +#include // for common_type. + +#include +#include +#include +#include + +// LightRefBase used to be declared in this header, so we have to include it +#include + +#include +#include + +// --------------------------------------------------------------------------- +namespace android { + +// --------------------------------------------------------------------------- + +#define COMPARE_WEAK(_op_) \ +template \ +inline bool operator _op_ (const U* o) const { \ + return m_ptr _op_ o; \ +} \ +/* Needed to handle type inference for nullptr: */ \ +inline bool operator _op_ (const T* o) const { \ + return m_ptr _op_ o; \ +} + +template class comparator, typename T, typename U> +static inline bool _wp_compare_(T* a, U* b) { + return comparator::type>()(a, b); +} + +// Use std::less and friends to avoid undefined behavior when ordering pointers +// to different objects. +#define COMPARE_WEAK_FUNCTIONAL(_op_, _compare_) \ +template \ +inline bool operator _op_ (const U* o) const { \ + return _wp_compare_<_compare_>(m_ptr, o); \ +} + +// --------------------------------------------------------------------------- + +// RefererenceRenamer is pure abstract, there is no virtual method +// implementation to put in a translation unit in order to silence the +// weak vtables warning. +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +class ReferenceRenamer { +protected: + // destructor is purposely not virtual so we avoid code overhead from + // subclasses; we have to make it protected to guarantee that it + // cannot be called from this base class (and to make strict compilers + // happy). + ~ReferenceRenamer() { } +public: + virtual void operator()(size_t i) const = 0; +}; + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +// --------------------------------------------------------------------------- + +class RefBase +{ +public: + void incStrong(const void* id) const; + void incStrongRequireStrong(const void* id) const; + void decStrong(const void* id) const; + + void forceIncStrong(const void* id) const; + + //! DEBUGGING ONLY: Get current strong ref count. + int32_t getStrongCount() const; + + class weakref_type + { + public: + RefBase* refBase() const; + + void incWeak(const void* id); + void incWeakRequireWeak(const void* id); + void decWeak(const void* id); + + // acquires a strong reference if there is already one. + bool attemptIncStrong(const void* id); + + // acquires a weak reference if there is already one. + // This is not always safe. see ProcessState.cpp and BpBinder.cpp + // for proper use. + bool attemptIncWeak(const void* id); + + //! DEBUGGING ONLY: Get current weak ref count. + int32_t getWeakCount() const; + + //! DEBUGGING ONLY: Print references held on object. + void printRefs() const; + + //! DEBUGGING ONLY: Enable tracking for this object. + // enable -- enable/disable tracking + // retain -- when tracking is enable, if true, then we save a stack trace + // for each reference and dereference; when retain == false, we + // match up references and dereferences and keep only the + // outstanding ones. + + void trackMe(bool enable, bool retain); + }; + + weakref_type* createWeak(const void* id) const; + + weakref_type* getWeakRefs() const; + + //! DEBUGGING ONLY: Print references held on object. + inline void printRefs() const { getWeakRefs()->printRefs(); } + + //! DEBUGGING ONLY: Enable tracking of object. + inline void trackMe(bool enable, bool retain) + { + getWeakRefs()->trackMe(enable, retain); + } + +protected: + // When constructing these objects, prefer using sp::make<>. Using a RefBase + // object on the stack or with other refcount mechanisms (e.g. + // std::shared_ptr) is inherently wrong. RefBase types have an implicit + // ownership model and cannot be safely used with other ownership models. + + RefBase(); + virtual ~RefBase(); + + //! Flags for extendObjectLifetime() + enum { + OBJECT_LIFETIME_STRONG = 0x0000, + OBJECT_LIFETIME_WEAK = 0x0001, + OBJECT_LIFETIME_MASK = 0x0001 + }; + + void extendObjectLifetime(int32_t mode); + + //! Flags for onIncStrongAttempted() + enum { + FIRST_INC_STRONG = 0x0001 + }; + + // Invoked after creation of initial strong pointer/reference. + virtual void onFirstRef(); + // Invoked when either the last strong reference goes away, or we need to undo + // the effect of an unnecessary onIncStrongAttempted. + virtual void onLastStrongRef(const void* id); + // Only called in OBJECT_LIFETIME_WEAK case. Returns true if OK to promote to + // strong reference. May have side effects if it returns true. + // The first flags argument is always FIRST_INC_STRONG. + // TODO: Remove initial flag argument. + virtual bool onIncStrongAttempted(uint32_t flags, const void* id); + // Invoked in the OBJECT_LIFETIME_WEAK case when the last reference of either + // kind goes away. Unused. + // TODO: Remove. + virtual void onLastWeakRef(const void* id); + +private: + friend class weakref_type; + class weakref_impl; + + RefBase(const RefBase& o); + RefBase& operator=(const RefBase& o); + +private: + friend class ReferenceMover; + + static void renameRefs(size_t n, const ReferenceRenamer& renamer); + + static void renameRefId(weakref_type* ref, + const void* old_id, const void* new_id); + + static void renameRefId(RefBase* ref, + const void* old_id, const void* new_id); + + weakref_impl* const mRefs; +}; + +// --------------------------------------------------------------------------- + +template +class wp +{ +public: + typedef typename RefBase::weakref_type weakref_type; + + inline wp() : m_ptr(nullptr), m_refs(nullptr) { } + + // if nullptr, returns nullptr + // + // if a weak pointer is already available, this will retrieve it, + // otherwise, this will abort + static inline wp fromExisting(T* other); + + // for more information about this flag, see above +#if defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION) + wp(std::nullptr_t) : wp() {} +#else + wp(T* other); // NOLINT(implicit) + template + wp(U* other); // NOLINT(implicit) + wp& operator=(T* other); + template + wp& operator=(U* other); +#endif + + wp(const wp& other); + explicit wp(const sp& other); + + template wp(const sp& other); // NOLINT(implicit) + template wp(const wp& other); // NOLINT(implicit) + + ~wp(); + + // Assignment + + wp& operator = (const wp& other); + wp& operator = (const sp& other); + + template wp& operator = (const wp& other); + template wp& operator = (const sp& other); + + void set_object_and_refs(T* other, weakref_type* refs); + + // promotion to sp + + sp promote() const; + + // Reset + + void clear(); + + // Accessors + + inline weakref_type* get_refs() const { return m_refs; } + + inline T* unsafe_get() const { return m_ptr; } + + // Operators + + COMPARE_WEAK(==) + COMPARE_WEAK(!=) + COMPARE_WEAK_FUNCTIONAL(>, std::greater) + COMPARE_WEAK_FUNCTIONAL(<, std::less) + COMPARE_WEAK_FUNCTIONAL(<=, std::less_equal) + COMPARE_WEAK_FUNCTIONAL(>=, std::greater_equal) + + template + inline bool operator == (const wp& o) const { + return m_refs == o.m_refs; // Implies m_ptr == o.mptr; see invariants below. + } + + template + inline bool operator == (const sp& o) const { + // Just comparing m_ptr fields is often dangerous, since wp<> may refer to an older + // object at the same address. + if (o == nullptr) { + return m_ptr == nullptr; + } else { + return m_refs == o->getWeakRefs(); // Implies m_ptr == o.mptr. + } + } + + template + inline bool operator != (const sp& o) const { + return !(*this == o); + } + + template + inline bool operator > (const wp& o) const { + if (m_ptr == o.m_ptr) { + return _wp_compare_(m_refs, o.m_refs); + } else { + return _wp_compare_(m_ptr, o.m_ptr); + } + } + + template + inline bool operator < (const wp& o) const { + if (m_ptr == o.m_ptr) { + return _wp_compare_(m_refs, o.m_refs); + } else { + return _wp_compare_(m_ptr, o.m_ptr); + } + } + template inline bool operator != (const wp& o) const { return !operator == (o); } + template inline bool operator <= (const wp& o) const { return !operator > (o); } + template inline bool operator >= (const wp& o) const { return !operator < (o); } + +private: + template friend class sp; + template friend class wp; + + T* m_ptr; + weakref_type* m_refs; +}; + +#undef COMPARE_WEAK +#undef COMPARE_WEAK_FUNCTIONAL + +// --------------------------------------------------------------------------- +// No user serviceable parts below here. + +// Implementation invariants: +// Either +// 1) m_ptr and m_refs are both null, or +// 2) m_refs == m_ptr->mRefs, or +// 3) *m_ptr is no longer live, and m_refs points to the weakref_type object that corresponded +// to m_ptr while it was live. *m_refs remains live while a wp<> refers to it. +// +// The m_refs field in a RefBase object is allocated on construction, unique to that RefBase +// object, and never changes. Thus if two wp's have identical m_refs fields, they are either both +// null or point to the same object. If two wp's have identical m_ptr fields, they either both +// point to the same live object and thus have the same m_ref fields, or at least one of the +// objects is no longer live. +// +// Note that the above comparison operations go out of their way to provide an ordering consistent +// with ordinary pointer comparison; otherwise they could ignore m_ptr, and just compare m_refs. + +template +wp wp::fromExisting(T* other) { + if (!other) return nullptr; + + auto refs = other->getWeakRefs(); + refs->incWeakRequireWeak(other); + + wp ret; + ret.m_ptr = other; + ret.m_refs = refs; + return ret; +} + +#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION) +template +wp::wp(T* other) + : m_ptr(other) +{ + m_refs = other ? m_refs = other->createWeak(this) : nullptr; +} + +template +template +wp::wp(U* other) : m_ptr(other) { + m_refs = other ? other->createWeak(this) : nullptr; +} + +template +wp& wp::operator=(T* other) { + weakref_type* newRefs = other ? other->createWeak(this) : nullptr; + if (m_ptr) m_refs->decWeak(this); + m_ptr = other; + m_refs = newRefs; + return *this; +} + +template +template +wp& wp::operator=(U* other) { + weakref_type* newRefs = other ? other->createWeak(this) : 0; + if (m_ptr) m_refs->decWeak(this); + m_ptr = other; + m_refs = newRefs; + return *this; +} +#endif + +template +wp::wp(const wp& other) + : m_ptr(other.m_ptr), m_refs(other.m_refs) +{ + if (m_ptr) m_refs->incWeak(this); +} + +template +wp::wp(const sp& other) + : m_ptr(other.m_ptr) +{ + m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr; +} + +template template +wp::wp(const wp& other) + : m_ptr(other.m_ptr) +{ + if (m_ptr) { + m_refs = other.m_refs; + m_refs->incWeak(this); + } else { + m_refs = nullptr; + } +} + +template template +wp::wp(const sp& other) + : m_ptr(other.m_ptr) +{ + m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr; +} + +template +wp::~wp() +{ + if (m_ptr) m_refs->decWeak(this); +} + +template +wp& wp::operator = (const wp& other) +{ + weakref_type* otherRefs(other.m_refs); + T* otherPtr(other.m_ptr); + if (otherPtr) otherRefs->incWeak(this); + if (m_ptr) m_refs->decWeak(this); + m_ptr = otherPtr; + m_refs = otherRefs; + return *this; +} + +template +wp& wp::operator = (const sp& other) +{ + weakref_type* newRefs = + other != nullptr ? other->createWeak(this) : nullptr; + T* otherPtr(other.m_ptr); + if (m_ptr) m_refs->decWeak(this); + m_ptr = otherPtr; + m_refs = newRefs; + return *this; +} + +template template +wp& wp::operator = (const wp& other) +{ + weakref_type* otherRefs(other.m_refs); + U* otherPtr(other.m_ptr); + if (otherPtr) otherRefs->incWeak(this); + if (m_ptr) m_refs->decWeak(this); + m_ptr = otherPtr; + m_refs = otherRefs; + return *this; +} + +template template +wp& wp::operator = (const sp& other) +{ + weakref_type* newRefs = + other != nullptr ? other->createWeak(this) : 0; + U* otherPtr(other.m_ptr); + if (m_ptr) m_refs->decWeak(this); + m_ptr = otherPtr; + m_refs = newRefs; + return *this; +} + +template +void wp::set_object_and_refs(T* other, weakref_type* refs) +{ + if (other) refs->incWeak(this); + if (m_ptr) m_refs->decWeak(this); + m_ptr = other; + m_refs = refs; +} + +template +sp wp::promote() const +{ + sp result; + if (m_ptr && m_refs->attemptIncStrong(&result)) { + result.set_pointer(m_ptr); + } + return result; +} + +template +void wp::clear() +{ + if (m_ptr) { + m_refs->decWeak(this); + m_refs = 0; + m_ptr = 0; + } +} + +// --------------------------------------------------------------------------- + +// this class just serves as a namespace so TYPE::moveReferences can stay +// private. +class ReferenceMover { +public: + // it would be nice if we could make sure no extra code is generated + // for sp or wp when TYPE is a descendant of RefBase: + // Using a sp override doesn't work; it's a bit like we wanted + // a template template... + + template static inline + void move_references(sp* dest, sp const* src, size_t n) { + + class Renamer : public ReferenceRenamer { + sp* d_; + sp const* s_; + virtual void operator()(size_t i) const { + // The id are known to be the sp<>'s this pointer + TYPE::renameRefId(d_[i].get(), &s_[i], &d_[i]); + } + public: + Renamer(sp* d, sp const* s) : d_(d), s_(s) { } + virtual ~Renamer() { } + }; + + memmove(dest, src, n*sizeof(sp)); + TYPE::renameRefs(n, Renamer(dest, src)); + } + + + template static inline + void move_references(wp* dest, wp const* src, size_t n) { + + class Renamer : public ReferenceRenamer { + wp* d_; + wp const* s_; + virtual void operator()(size_t i) const { + // The id are known to be the wp<>'s this pointer + TYPE::renameRefId(d_[i].get_refs(), &s_[i], &d_[i]); + } + public: + Renamer(wp* rd, wp const* rs) : d_(rd), s_(rs) { } + virtual ~Renamer() { } + }; + + memmove(dest, src, n*sizeof(wp)); + TYPE::renameRefs(n, Renamer(dest, src)); + } +}; + +// specialization for moving sp<> and wp<> types. +// these are used by the [Sorted|Keyed]Vector<> implementations +// sp<> and wp<> need to be handled specially, because they do not +// have trivial copy operation in the general case (see RefBase.cpp +// when DEBUG ops are enabled), but can be implemented very +// efficiently in most cases. + +template inline +void move_forward_type(sp* d, sp const* s, size_t n) { + ReferenceMover::move_references(d, s, n); +} + +template inline +void move_backward_type(sp* d, sp const* s, size_t n) { + ReferenceMover::move_references(d, s, n); +} + +template inline +void move_forward_type(wp* d, wp const* s, size_t n) { + ReferenceMover::move_references(d, s, n); +} + +template inline +void move_backward_type(wp* d, wp const* s, size_t n) { + ReferenceMover::move_references(d, s, n); +} + +} // namespace android + +namespace libutilsinternal { +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; +} // namespace libutilsinternal + +namespace std { + +// Define `RefBase` specific versions of `std::make_shared` and +// `std::make_unique` to block people from using them. Using them to allocate +// `RefBase` objects results in double ownership. Use +// `sp::make(...)` instead. +// +// Note: We exclude incomplete types because `std::is_base_of` is undefined in +// that case. + +template ::value, bool>::value = true, + typename std::enable_if::value, bool>::value = true> +shared_ptr make_shared(Args...) { // SEE COMMENT ABOVE. + static_assert(!std::is_base_of::value, "Must use RefBase with sp<>"); +} + +template ::value, bool>::value = true, + typename std::enable_if::value, bool>::value = true> +unique_ptr make_unique(Args...) { // SEE COMMENT ABOVE. + static_assert(!std::is_base_of::value, "Must use RefBase with sp<>"); +} + +} // namespace std + +// --------------------------------------------------------------------------- + +#endif // ANDROID_REF_BASE_H diff --git a/libutils/binder/include/utils/String16.h b/libutils/binder/include/utils/String16.h new file mode 100644 index 000000000000..c7135766b097 --- /dev/null +++ b/libutils/binder/include/utils/String16.h @@ -0,0 +1,383 @@ +/* + * Copyright (C) 2005 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. + */ + +#ifndef ANDROID_STRING16_H +#define ANDROID_STRING16_H + +#include +#include + +#include +#include +#include + +#if __has_include() +#include +#define HAS_STRING_VIEW +#endif + +// --------------------------------------------------------------------------- + +namespace android { + +// --------------------------------------------------------------------------- + +template +class StaticString16; + +// DO NOT USE: please use std::u16string + +//! This is a string holding UTF-16 characters. +class String16 +{ +public: + String16(); + String16(const String16& o); + String16(String16&& o) noexcept; + String16(const String16& o, + size_t len, + size_t begin=0); + explicit String16(const char16_t* o); + explicit String16(const char16_t* o, size_t len); + explicit String16(const String8& o); + explicit String16(const char* o); + explicit String16(const char* o, size_t len); + + ~String16(); + + inline const char16_t* c_str() const; + + size_t size() const; + inline bool empty() const; + + inline size_t length() const; + + void setTo(const String16& other); + status_t setTo(const char16_t* other); + status_t setTo(const char16_t* other, size_t len); + status_t setTo(const String16& other, + size_t len, + size_t begin=0); + + status_t append(const String16& other); + status_t append(const char16_t* other, size_t len); + + inline String16& operator=(const String16& other); + String16& operator=(String16&& other) noexcept; + + inline String16& operator+=(const String16& other); + inline String16 operator+(const String16& other) const; + + status_t insert(size_t pos, const char16_t* chrs); + status_t insert(size_t pos, + const char16_t* chrs, size_t len); + + ssize_t findFirst(char16_t c) const; + ssize_t findLast(char16_t c) const; + + bool startsWith(const String16& prefix) const; + bool startsWith(const char16_t* prefix) const; + + bool contains(const char16_t* chrs) const; + inline bool contains(const String16& other) const; + + status_t replaceAll(char16_t replaceThis, + char16_t withThis); + + inline int compare(const String16& other) const; + + inline bool operator<(const String16& other) const; + inline bool operator<=(const String16& other) const; + inline bool operator==(const String16& other) const; + inline bool operator!=(const String16& other) const; + inline bool operator>=(const String16& other) const; + inline bool operator>(const String16& other) const; + + inline bool operator<(const char16_t* other) const; + inline bool operator<=(const char16_t* other) const; + inline bool operator==(const char16_t* other) const; + inline bool operator!=(const char16_t* other) const; + inline bool operator>=(const char16_t* other) const; + inline bool operator>(const char16_t* other) const; + + inline operator const char16_t*() const; + +#ifdef HAS_STRING_VIEW + // Implicit cast to std::u16string is not implemented on purpose - u16string_view is much + // lighter and if one needs, they can still create u16string from u16string_view. + inline operator std::u16string_view() const; +#endif + + // Static and non-static String16 behave the same for the users, so + // this method isn't of much use for the users. It is public for testing. + bool isStaticString() const; + + private: + /* + * A flag indicating the type of underlying buffer. + */ + static constexpr uint32_t kIsSharedBufferAllocated = 0x80000000; + + /* + * alloc() returns void* so that SharedBuffer class is not exposed. + */ + static void* alloc(size_t size); + static char16_t* allocFromUTF8(const char* u8str, size_t u8len); + static char16_t* allocFromUTF16(const char16_t* u16str, size_t u16len); + + /* + * edit() and editResize() return void* so that SharedBuffer class + * is not exposed. + */ + void* edit(); + void* editResize(size_t new_size); + + void acquire(); + void release(); + + size_t staticStringSize() const; + + const char16_t* mString; + +protected: + /* + * Data structure used to allocate static storage for static String16. + * + * Note that this data structure and SharedBuffer are used interchangably + * as the underlying data structure for a String16. Therefore, the layout + * of this data structure must match the part in SharedBuffer that is + * visible to String16. + */ + template + struct StaticData { + // The high bit of 'size' is used as a flag. + static_assert(N - 1 < kIsSharedBufferAllocated, "StaticString16 too long!"); + constexpr StaticData() : size(N - 1), data{0} {} + const uint32_t size; + char16_t data[N]; + + constexpr StaticData(const StaticData&) = default; + }; + + /* + * Helper function for constructing a StaticData object. + */ + template + static constexpr const StaticData makeStaticData(const char16_t (&s)[N]) { + StaticData r; + // The 'size' field is at the same location where mClientMetadata would + // be for a SharedBuffer. We do NOT set kIsSharedBufferAllocated flag + // here. + for (size_t i = 0; i < N - 1; ++i) r.data[i] = s[i]; + return r; + } + + template + explicit constexpr String16(const StaticData& s) : mString(s.data) {} + +// These symbols are for potential backward compatibility with prebuilts. To be removed. +#ifdef ENABLE_STRING16_OBSOLETE_METHODS +public: +#else +private: +#endif + inline const char16_t* string() const; +}; + +// String16 can be trivially moved using memcpy() because moving does not +// require any change to the underlying SharedBuffer contents or reference count. +ANDROID_TRIVIAL_MOVE_TRAIT(String16) + +static inline std::ostream& operator<<(std::ostream& os, const String16& str) { + os << String8(str); + return os; +} + +// --------------------------------------------------------------------------- + +/* + * A StaticString16 object is a specialized String16 object. Instead of holding + * the string data in a ref counted SharedBuffer object, it holds data in a + * buffer within StaticString16 itself. Note that this buffer is NOT ref + * counted and is assumed to be available for as long as there is at least a + * String16 object using it. Therefore, one must be extra careful to NEVER + * assign a StaticString16 to a String16 that outlives the StaticString16 + * object. + * + * THE SAFEST APPROACH IS TO USE StaticString16 ONLY AS GLOBAL VARIABLES. + * + * A StaticString16 SHOULD NEVER APPEAR IN APIs. USE String16 INSTEAD. + */ +template +class StaticString16 : public String16 { +public: + constexpr StaticString16(const char16_t (&s)[N]) : String16(mData), mData(makeStaticData(s)) {} + + constexpr StaticString16(const StaticString16& other) + : String16(mData), mData(other.mData) {} + + constexpr StaticString16(const StaticString16&&) = delete; + + // There is no reason why one would want to 'new' a StaticString16. Delete + // it to discourage misuse. + static void* operator new(std::size_t) = delete; + +private: + const StaticData mData; +}; + +template +StaticString16(const F&)->StaticString16; + +// --------------------------------------------------------------------------- +// No user servicable parts below. + +inline int compare_type(const String16& lhs, const String16& rhs) +{ + return lhs.compare(rhs); +} + +inline int strictly_order_type(const String16& lhs, const String16& rhs) +{ + return compare_type(lhs, rhs) < 0; +} + +inline const char16_t* String16::c_str() const +{ + return mString; +} + +inline const char16_t* String16::string() const +{ + return mString; +} + +inline bool String16::empty() const +{ + return length() == 0; +} + +inline size_t String16::length() const +{ + return size(); +} + +inline bool String16::contains(const String16& other) const +{ + return contains(other.c_str()); +} + +inline String16& String16::operator=(const String16& other) +{ + setTo(other); + return *this; +} + +inline String16& String16::operator+=(const String16& other) +{ + append(other); + return *this; +} + +inline String16 String16::operator+(const String16& other) const +{ + String16 tmp(*this); + tmp += other; + return tmp; +} + +inline int String16::compare(const String16& other) const +{ + return strzcmp16(mString, size(), other.mString, other.size()); +} + +inline bool String16::operator<(const String16& other) const +{ + return strzcmp16(mString, size(), other.mString, other.size()) < 0; +} + +inline bool String16::operator<=(const String16& other) const +{ + return strzcmp16(mString, size(), other.mString, other.size()) <= 0; +} + +inline bool String16::operator==(const String16& other) const +{ + return strzcmp16(mString, size(), other.mString, other.size()) == 0; +} + +inline bool String16::operator!=(const String16& other) const +{ + return strzcmp16(mString, size(), other.mString, other.size()) != 0; +} + +inline bool String16::operator>=(const String16& other) const +{ + return strzcmp16(mString, size(), other.mString, other.size()) >= 0; +} + +inline bool String16::operator>(const String16& other) const +{ + return strzcmp16(mString, size(), other.mString, other.size()) > 0; +} + +inline bool String16::operator<(const char16_t* other) const +{ + return strcmp16(mString, other) < 0; +} + +inline bool String16::operator<=(const char16_t* other) const +{ + return strcmp16(mString, other) <= 0; +} + +inline bool String16::operator==(const char16_t* other) const +{ + return strcmp16(mString, other) == 0; +} + +inline bool String16::operator!=(const char16_t* other) const +{ + return strcmp16(mString, other) != 0; +} + +inline bool String16::operator>=(const char16_t* other) const +{ + return strcmp16(mString, other) >= 0; +} + +inline bool String16::operator>(const char16_t* other) const +{ + return strcmp16(mString, other) > 0; +} + +inline String16::operator const char16_t*() const +{ + return mString; +} + +inline String16::operator std::u16string_view() const +{ + return {mString, length()}; +} + +} // namespace android + +// --------------------------------------------------------------------------- + +#undef HAS_STRING_VIEW + +#endif // ANDROID_STRING16_H diff --git a/libutils/binder/include/utils/String8.h b/libutils/binder/include/utils/String8.h new file mode 100644 index 000000000000..6d250723b628 --- /dev/null +++ b/libutils/binder/include/utils/String8.h @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2005 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. + */ + +#ifndef ANDROID_STRING8_H +#define ANDROID_STRING8_H + +#include + +#include +#include +#include + +#include // for strcmp +#include + +#if __has_include() +#include +#define HAS_STRING +#endif + +#if __has_include() +#include +#define HAS_STRING_VIEW +#endif + +// --------------------------------------------------------------------------- + +namespace android { + +class String16; + +// DO NOT USE: please use std::string + +//! This is a string holding UTF-8 characters. Does not allow the value more +// than 0x10FFFF, which is not valid unicode codepoint. +class String8 +{ +public: + String8(); + String8(const String8& o); + explicit String8(const char* o); + explicit String8(const char* o, size_t numChars); + + explicit String8(const String16& o); + explicit String8(const char16_t* o); + explicit String8(const char16_t* o, size_t numChars); + explicit String8(const char32_t* o); + explicit String8(const char32_t* o, size_t numChars); + ~String8(); + + static String8 format(const char* fmt, ...) __attribute__((format (printf, 1, 2))); + static String8 formatV(const char* fmt, va_list args); + + inline const char* c_str() const; + + inline size_t size() const; + inline size_t bytes() const; + inline bool empty() const; + + size_t length() const; + + void clear(); + + void setTo(const String8& other); + status_t setTo(const char* other); + status_t setTo(const char* other, size_t numChars); + status_t setTo(const char16_t* other, size_t numChars); + status_t setTo(const char32_t* other, + size_t length); + + status_t append(const String8& other); + status_t append(const char* other); + status_t append(const char* other, size_t numChars); + + status_t appendFormat(const char* fmt, ...) + __attribute__((format (printf, 2, 3))); + status_t appendFormatV(const char* fmt, va_list args); + + inline String8& operator=(const String8& other); + inline String8& operator=(const char* other); + + inline String8& operator+=(const String8& other); + inline String8 operator+(const String8& other) const; + + inline String8& operator+=(const char* other); + inline String8 operator+(const char* other) const; + + inline int compare(const String8& other) const; + + inline bool operator<(const String8& other) const; + inline bool operator<=(const String8& other) const; + inline bool operator==(const String8& other) const; + inline bool operator!=(const String8& other) const; + inline bool operator>=(const String8& other) const; + inline bool operator>(const String8& other) const; + + inline bool operator<(const char* other) const; + inline bool operator<=(const char* other) const; + inline bool operator==(const char* other) const; + inline bool operator!=(const char* other) const; + inline bool operator>=(const char* other) const; + inline bool operator>(const char* other) const; + + inline operator const char*() const; + +#ifdef HAS_STRING_VIEW + inline explicit operator std::string_view() const; +#endif + + char* lockBuffer(size_t size); + void unlockBuffer(); + status_t unlockBuffer(size_t size); + + // return the index of the first byte of other in this at or after + // start, or -1 if not found + ssize_t find(const char* other, size_t start = 0) const; + inline ssize_t find(const String8& other, size_t start = 0) const; + + // return true if this string contains the specified substring + inline bool contains(const char* other) const; + inline bool contains(const String8& other) const; + + // removes all occurrence of the specified substring + // returns true if any were found and removed + bool removeAll(const char* other); + inline bool removeAll(const String8& other); + + void toLower(); + +private: + String8 getPathDir(void) const; + String8 getPathExtension(void) const; + + status_t real_append(const char* other, size_t numChars); + + const char* mString; + +// These symbols are for potential backward compatibility with prebuilts. To be removed. +#ifdef ENABLE_STRING8_OBSOLETE_METHODS +public: +#else +private: +#endif + inline const char* string() const; + inline bool isEmpty() const; +}; + +// String8 can be trivially moved using memcpy() because moving does not +// require any change to the underlying SharedBuffer contents or reference count. +ANDROID_TRIVIAL_MOVE_TRAIT(String8) + +static inline std::ostream& operator<<(std::ostream& os, const String8& str) { + os << str.c_str(); + return os; +} + +// --------------------------------------------------------------------------- +// No user servicable parts below. + +inline int compare_type(const String8& lhs, const String8& rhs) +{ + return lhs.compare(rhs); +} + +inline int strictly_order_type(const String8& lhs, const String8& rhs) +{ + return compare_type(lhs, rhs) < 0; +} + +inline const char* String8::c_str() const +{ + return mString; +} +inline const char* String8::string() const +{ + return mString; +} + +inline size_t String8::size() const +{ + return length(); +} + +inline bool String8::empty() const +{ + return length() == 0; +} + +inline bool String8::isEmpty() const +{ + return length() == 0; +} + +inline size_t String8::bytes() const +{ + return length(); +} + +inline ssize_t String8::find(const String8& other, size_t start) const +{ + return find(other.c_str(), start); +} + +inline bool String8::contains(const char* other) const +{ + return find(other) >= 0; +} + +inline bool String8::contains(const String8& other) const +{ + return contains(other.c_str()); +} + +inline bool String8::removeAll(const String8& other) +{ + return removeAll(other.c_str()); +} + +inline String8& String8::operator=(const String8& other) +{ + setTo(other); + return *this; +} + +inline String8& String8::operator=(const char* other) +{ + setTo(other); + return *this; +} + +inline String8& String8::operator+=(const String8& other) +{ + append(other); + return *this; +} + +inline String8 String8::operator+(const String8& other) const +{ + String8 tmp(*this); + tmp += other; + return tmp; +} + +inline String8& String8::operator+=(const char* other) +{ + append(other); + return *this; +} + +inline String8 String8::operator+(const char* other) const +{ + String8 tmp(*this); + tmp += other; + return tmp; +} + +inline int String8::compare(const String8& other) const +{ + return strcmp(mString, other.mString); +} + +inline bool String8::operator<(const String8& other) const +{ + return strcmp(mString, other.mString) < 0; +} + +inline bool String8::operator<=(const String8& other) const +{ + return strcmp(mString, other.mString) <= 0; +} + +inline bool String8::operator==(const String8& other) const +{ + return strcmp(mString, other.mString) == 0; +} + +inline bool String8::operator!=(const String8& other) const +{ + return strcmp(mString, other.mString) != 0; +} + +inline bool String8::operator>=(const String8& other) const +{ + return strcmp(mString, other.mString) >= 0; +} + +inline bool String8::operator>(const String8& other) const +{ + return strcmp(mString, other.mString) > 0; +} + +inline bool String8::operator<(const char* other) const +{ + return strcmp(mString, other) < 0; +} + +inline bool String8::operator<=(const char* other) const +{ + return strcmp(mString, other) <= 0; +} + +inline bool String8::operator==(const char* other) const +{ + return strcmp(mString, other) == 0; +} + +inline bool String8::operator!=(const char* other) const +{ + return strcmp(mString, other) != 0; +} + +inline bool String8::operator>=(const char* other) const +{ + return strcmp(mString, other) >= 0; +} + +inline bool String8::operator>(const char* other) const +{ + return strcmp(mString, other) > 0; +} + +inline String8::operator const char*() const +{ + return mString; +} + +#ifdef HAS_STRING_VIEW +inline String8::operator std::string_view() const +{ + return {mString, length()}; +} +#endif + +} // namespace android + +// --------------------------------------------------------------------------- + +#undef HAS_STRING +#undef HAS_STRING_VIEW + +#endif // ANDROID_STRING8_H diff --git a/libutils/binder/include/utils/StrongPointer.h b/libutils/binder/include/utils/StrongPointer.h new file mode 100644 index 000000000000..54aa691e03c2 --- /dev/null +++ b/libutils/binder/include/utils/StrongPointer.h @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2005 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. + */ + +#ifndef ANDROID_STRONG_POINTER_H +#define ANDROID_STRONG_POINTER_H + +#include +#include // for common_type. + +// --------------------------------------------------------------------------- +namespace android { + +template class wp; + +// --------------------------------------------------------------------------- + +template +class sp { +public: + inline sp() : m_ptr(nullptr) { } + + // The old way of using sp<> was like this. This is bad because it relies + // on implicit conversion to sp<>, which we would like to remove (if an + // object is being managed some other way, this is double-ownership). We + // want to move away from this: + // + // sp foo = new Foo(...); // DO NOT DO THIS + // + // Instead, prefer to do this: + // + // sp foo = sp::make(...); // DO THIS + // + // Sometimes, in order to use this, when a constructor is marked as private, + // you may need to add this to your class: + // + // friend class sp; + template + static inline sp make(Args&&... args); + + // if nullptr, returns nullptr + // + // if a strong pointer is already available, this will retrieve it, + // otherwise, this will abort + static inline sp fromExisting(T* other); + + // for more information about this macro and correct RefBase usage, see + // the comment at the top of utils/RefBase.h +#if defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION) + sp(std::nullptr_t) : sp() {} +#else + sp(T* other); // NOLINT(implicit) + template + sp(U* other); // NOLINT(implicit) + sp& operator=(T* other); + template + sp& operator=(U* other); +#endif + + sp(const sp& other); + sp(sp&& other) noexcept; + + template sp(const sp& other); // NOLINT(implicit) + template sp(sp&& other); // NOLINT(implicit) + + // Cast a strong pointer directly from one type to another. Constructors + // allow changing types, but only if they are pointer-compatible. This does + // a static_cast internally. + template + static inline sp cast(const sp& other); + + ~sp(); + + // Assignment + + sp& operator = (const sp& other); + sp& operator=(sp&& other) noexcept; + + template sp& operator = (const sp& other); + template sp& operator = (sp&& other); + + //! Special optimization for use by ProcessState (and nobody else). + void force_set(T* other); + + // Reset + + void clear(); + + // Accessors + + inline T& operator* () const { return *m_ptr; } + inline T* operator-> () const { return m_ptr; } + inline T* get() const { return m_ptr; } + inline explicit operator bool () const { return m_ptr != nullptr; } + + // Punt these to the wp<> implementation. + template + inline bool operator == (const wp& o) const { + return o == *this; + } + + template + inline bool operator != (const wp& o) const { + return o != *this; + } + +private: + template friend class sp; + template friend class wp; + void set_pointer(T* ptr); + T* m_ptr; +}; + +#define COMPARE_STRONG(_op_) \ + template \ + static inline bool operator _op_(const sp& t, const sp& u) { \ + return t.get() _op_ u.get(); \ + } \ + template \ + static inline bool operator _op_(const T* t, const sp& u) { \ + return t _op_ u.get(); \ + } \ + template \ + static inline bool operator _op_(const sp& t, const U* u) { \ + return t.get() _op_ u; \ + } \ + template \ + static inline bool operator _op_(const sp& t, std::nullptr_t) { \ + return t.get() _op_ nullptr; \ + } \ + template \ + static inline bool operator _op_(std::nullptr_t, const sp& t) { \ + return nullptr _op_ t.get(); \ + } + +template