diff options
author | 2024-03-05 11:02:56 +0000 | |
---|---|---|
committer | 2024-03-07 14:24:14 +0000 | |
commit | 7d595b494b55eeb65aac828fba26ce861efb9ae1 (patch) | |
tree | ff91ff1f2a8e791a87db87a52890057617a1fc93 | |
parent | f66031b556c386f582eab39b5c616104d77fc375 (diff) |
Move common code from artd to libarttools.
The code will be shared with dexopt_chroot_setup.
Bug: 311377497
Test: m com.android.art
Change-Id: I2b320e0d4effa7e7a1c75ab5fe40fe8c4ff170ba
-rw-r--r-- | artd/Android.bp | 1 | ||||
-rw-r--r-- | artd/artd.cc | 48 | ||||
-rw-r--r-- | artd/artd_test.cc | 4 | ||||
-rw-r--r-- | artd/path_utils.cc | 35 | ||||
-rw-r--r-- | artd/path_utils.h | 9 | ||||
-rw-r--r-- | artd/path_utils_test.cc | 16 | ||||
-rw-r--r-- | libarttools/Android.bp | 30 | ||||
-rw-r--r-- | libarttools/binder_utils_test.cc | 17 | ||||
-rw-r--r-- | libarttools/include/tools/tools.h | 16 | ||||
-rw-r--r-- | libarttools/include_binder_utils/tools/binder_utils.h | 76 | ||||
-rw-r--r-- | libarttools/tools.cc | 51 | ||||
-rw-r--r-- | libarttools/tools_test.cc | 16 |
12 files changed, 215 insertions, 104 deletions
diff --git a/artd/Android.bp b/artd/Android.bp index 50f5428435..dadb394c57 100644 --- a/artd/Android.bp +++ b/artd/Android.bp @@ -32,6 +32,7 @@ cc_defaults { ], header_libs: [ "art_cmdlineparser_headers", + "libarttools_binder_utils", "profman_headers", ], shared_libs: [ diff --git a/artd/artd.cc b/artd/artd.cc index c44013b740..c351b837bc 100644 --- a/artd/artd.cc +++ b/artd/artd.cc @@ -78,6 +78,7 @@ #include "profman/profman_result.h" #include "selinux/android.h" #include "service.h" +#include "tools/binder_utils.h" #include "tools/cmdline_builder.h" #include "tools/tools.h" @@ -118,6 +119,9 @@ using ::android::base::WriteStringToFd; using ::android::fs_mgr::FstabEntry; using ::art::service::ValidateDexPath; using ::art::tools::CmdlineBuilder; +using ::art::tools::Fatal; +using ::art::tools::GetProcMountsAncestorsOfPath; +using ::art::tools::NonFatal; using ::ndk::ScopedAStatus; using TmpProfilePath = ProfilePath::TmpProfilePath; @@ -165,29 +169,6 @@ int64_t GetSizeAndDeleteFile(const std::string& path) { return size.value(); } -std::string EscapeErrorMessage(const std::string& message) { - return StringReplace(message, std::string("\0", /*n=*/1), "\\0", /*all=*/true); -} - -// Indicates an error that should never happen (e.g., illegal arguments passed by service-art -// internally). System server should crash if this kind of error happens. -ScopedAStatus Fatal(const std::string& message) { - return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, - EscapeErrorMessage(message).c_str()); -} - -// Indicates an error that service-art should handle (e.g., I/O errors, sub-process crashes). -// The scope of the error depends on the function that throws it, so service-art should catch the -// error at every call site and take different actions. -// Ideally, this should be a checked exception or an additional return value that forces service-art -// to handle it, but `ServiceSpecificException` (a separate runtime exception type) is the best -// approximate we have given the limitation of Java and Binder. -ScopedAStatus NonFatal(const std::string& message) { - constexpr int32_t kArtdNonFatalErrorCode = 1; - return ScopedAStatus::fromServiceSpecificErrorWithMessage(kArtdNonFatalErrorCode, - EscapeErrorMessage(message).c_str()); -} - Result<CompilerFilter::Filter> ParseCompilerFilter(const std::string& compiler_filter_str) { CompilerFilter::Filter compiler_filter; if (!CompilerFilter::ParseCompilerFilter(compiler_filter_str.c_str(), &compiler_filter)) { @@ -511,25 +492,6 @@ std::ostream& operator<<(std::ostream& os, const FdLogger& fd_logger) { } // namespace -#define OR_RETURN_ERROR(func, expr) \ - ({ \ - decltype(expr)&& __or_return_error_tmp = (expr); \ - if (!__or_return_error_tmp.ok()) { \ - return (func)(__or_return_error_tmp.error().message()); \ - } \ - std::move(__or_return_error_tmp).value(); \ - }) - -#define OR_RETURN_FATAL(expr) OR_RETURN_ERROR(Fatal, expr) -#define OR_RETURN_NON_FATAL(expr) OR_RETURN_ERROR(NonFatal, expr) -#define OR_LOG_AND_RETURN_OK(expr) \ - OR_RETURN_ERROR( \ - [](const std::string& message) { \ - LOG(ERROR) << message; \ - return ScopedAStatus::ok(); \ - }, \ - expr) - ScopedAStatus Artd::isAlive(bool* _aidl_return) { *_aidl_return = true; return ScopedAStatus::ok(); @@ -1270,7 +1232,7 @@ ScopedAStatus Artd::isInDalvikCache(const std::string& in_dexFile, bool* _aidl_r OR_RETURN_FATAL(ValidateDexPath(in_dexFile)); - std::vector<FstabEntry> entries = OR_RETURN_NON_FATAL(GetProcMountsEntriesForPath(in_dexFile)); + std::vector<FstabEntry> entries = OR_RETURN_NON_FATAL(GetProcMountsAncestorsOfPath(in_dexFile)); // The last one controls because `/proc/mounts` reflects the sequence of `mount`. for (auto it = entries.rbegin(); it != entries.rend(); it++) { if (it->fs_type == "overlay") { diff --git a/artd/artd_test.cc b/artd/artd_test.cc index 8a704464ea..7458ebda4c 100644 --- a/artd/artd_test.cc +++ b/artd/artd_test.cc @@ -63,6 +63,7 @@ #include "profman/profman_result.h" #include "testing.h" #include "tools/system_properties.h" +#include "tools/tools.h" #include "ziparchive/zip_writer.h" namespace art { @@ -96,6 +97,7 @@ using ::android::base::Split; using ::android::base::WriteStringToFd; using ::android::base::WriteStringToFile; using ::android::base::testing::HasValue; +using ::art::tools::GetProcMountsAncestorsOfPath; using ::testing::_; using ::testing::AllOf; using ::testing::AnyNumber; @@ -2217,7 +2219,7 @@ TEST_F(ArtdTest, cleanup) { TEST_F(ArtdTest, isInDalvikCache) { TEST_DISABLED_FOR_HOST(); - if (GetProcMountsEntriesForPath("/")->empty()) { + if (GetProcMountsAncestorsOfPath("/")->empty()) { GTEST_SKIP() << "Skipped for chroot"; } diff --git a/artd/path_utils.cc b/artd/path_utils.cc index 3d3a92f60c..1be75b9358 100644 --- a/artd/path_utils.cc +++ b/artd/path_utils.cc @@ -23,12 +23,10 @@ #include "aidl/com/android/server/art/BnArtd.h" #include "android-base/errors.h" #include "android-base/result.h" -#include "android-base/strings.h" #include "arch/instruction_set.h" #include "base/file_utils.h" #include "base/macros.h" #include "file_utils.h" -#include "fstab/fstab.h" #include "oat/oat_file_assistant.h" #include "runtime_image.h" #include "service.h" @@ -46,10 +44,6 @@ using ::aidl::com::android::server::art::RuntimeArtifactsPath; using ::aidl::com::android::server::art::VdexPath; using ::android::base::Error; using ::android::base::Result; -using ::android::base::StartsWith; -using ::android::fs_mgr::Fstab; -using ::android::fs_mgr::FstabEntry; -using ::android::fs_mgr::ReadFstabFromProcMounts; using ::art::service::ValidateDexPath; using ::art::service::ValidatePathElement; using ::art::service::ValidatePathElementSubstring; @@ -280,35 +274,6 @@ Result<std::string> BuildVdexPath(const VdexPath& vdex_path) { return OatPathToVdexPath(OR_RETURN(BuildOatPath(vdex_path.get<VdexPath::artifactsPath>()))); } -bool PathStartsWith(std::string_view path, std::string_view prefix) { - CHECK(!prefix.empty() && !path.empty() && prefix[0] == '/' && path[0] == '/') - << ART_FORMAT("path={}, prefix={}", path, prefix); - android::base::ConsumeSuffix(&prefix, "/"); - return StartsWith(path, prefix) && - (path.length() == prefix.length() || path[prefix.length()] == '/'); -} - -Result<std::vector<FstabEntry>> GetProcMountsEntriesForPath(const std::string& path) { - Fstab fstab; - if (!ReadFstabFromProcMounts(&fstab)) { - return Errorf("Failed to read fstab from /proc/mounts"); - } - std::vector<FstabEntry> entries; - for (FstabEntry& entry : fstab) { - // Ignore swap areas as a swap area doesn't have a meaningful `mount_point` (a.k.a., `fs_file`) - // field, according to fstab(5). In addition, ignore any other entries whose mount points are - // not absolute paths, just in case there are other fs types that also have an meaningless mount - // point. - if (entry.fs_type == "swap" || !StartsWith(entry.mount_point, '/')) { - continue; - } - if (PathStartsWith(path, entry.mount_point)) { - entries.push_back(std::move(entry)); - } - } - return entries; -} - void TestOnlySetListRootDir(std::string_view root_dir) { gListRootDir = root_dir; } } // namespace artd diff --git a/artd/path_utils.h b/artd/path_utils.h index b42b6391c1..9cbec2351a 100644 --- a/artd/path_utils.h +++ b/artd/path_utils.h @@ -96,15 +96,6 @@ android::base::Result<std::string> BuildProfileOrDmPath( android::base::Result<std::string> BuildVdexPath( const aidl::com::android::server::art::VdexPath& vdex_path); -// Returns true if `path` starts with `prefix` (i.e., if `prefix` represents a directory that -// contains a file/directory at `path`, or if `prefix` and `path` represents the same -// file/directory). Only supports absolute paths. -bool PathStartsWith(std::string_view path, std::string_view prefix); - -// Returns the fstab entries in /proc/mounts for the given path. -android::base::Result<std::vector<android::fs_mgr::FstabEntry>> GetProcMountsEntriesForPath( - const std::string& path); - // Sets the root dir for `ListManagedFiles` and `ListRuntimeImageFiles`. // The passed string must be alive until the test ends. // For testing use only. diff --git a/artd/path_utils_test.cc b/artd/path_utils_test.cc index 47b503f982..5851245eac 100644 --- a/artd/path_utils_test.cc +++ b/artd/path_utils_test.cc @@ -207,22 +207,6 @@ TEST_F(PathUtilsTest, BuildVdexPath) { HasValue("/a/oat/arm64/b.vdex")); } -TEST_F(PathUtilsTest, PathStartsWith) { - EXPECT_TRUE(PathStartsWith("/a/b", "/a")); - EXPECT_TRUE(PathStartsWith("/a/b", "/a/")); - - EXPECT_FALSE(PathStartsWith("/a/c", "/a/b")); - EXPECT_FALSE(PathStartsWith("/ab", "/a")); - - EXPECT_TRUE(PathStartsWith("/a", "/a")); - EXPECT_TRUE(PathStartsWith("/a/", "/a")); - EXPECT_TRUE(PathStartsWith("/a", "/a/")); - - EXPECT_TRUE(PathStartsWith("/a", "/")); - EXPECT_TRUE(PathStartsWith("/", "/")); - EXPECT_FALSE(PathStartsWith("/", "/a")); -} - } // namespace } // namespace artd } // namespace art diff --git a/libarttools/Android.bp b/libarttools/Android.bp index 2c036fb96b..0b1790770e 100644 --- a/libarttools/Android.bp +++ b/libarttools/Android.bp @@ -40,6 +40,12 @@ cc_library { export_shared_lib_headers: [ "libbase", ], + static_libs: [ + "libfstab", + ], + export_static_lib_headers: [ + "libfstab", + ], whole_static_libs: [ // TODO(b/270049598): Investigate the cost of libc++fs compared to its utility. "libc++fs", @@ -50,6 +56,20 @@ cc_library { ], } +cc_library_headers { + name: "libarttools_binder_utils", + defaults: ["art_defaults"], + host_supported: true, + export_include_dirs: ["include_binder_utils"], + shared_libs: [ + "libbinder_ndk", + ], + apex_available: [ + "com.android.art", + "com.android.art.debug", + ], +} + art_cc_defaults { name: "art_libarttools_tests_defaults", srcs: [ @@ -92,8 +112,18 @@ art_cc_test { "art_standalone_gtest_defaults", "art_libarttools_tests_defaults", ], + srcs: [ + "binder_utils_test.cc", + ], + header_libs: [ + "libarttools_binder_utils", + ], + shared_libs: [ + "libbinder_ndk", + ], static_libs: [ "libarttools", + "libfstab", ], } diff --git a/libarttools/binder_utils_test.cc b/libarttools/binder_utils_test.cc new file mode 100644 index 0000000000..ee67c118a1 --- /dev/null +++ b/libarttools/binder_utils_test.cc @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2024 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 "tools/binder_utils.h" diff --git a/libarttools/include/tools/tools.h b/libarttools/include/tools/tools.h index 1bf47e4f6b..f536e030c4 100644 --- a/libarttools/include/tools/tools.h +++ b/libarttools/include/tools/tools.h @@ -21,6 +21,9 @@ #include <string_view> #include <vector> +#include "android-base/result.h" +#include "fstab/fstab.h" + namespace art { namespace tools { @@ -40,6 +43,19 @@ std::vector<std::string> Glob(const std::vector<std::string>& patterns, // Escapes a string so that it's not recognized as a wildcard pattern for `Glob`. std::string EscapeGlob(const std::string& str); +// Returns true if `path` starts with `prefix` (i.e., if `prefix` represents a directory that +// contains a file/directory at `path`, or if `prefix` and `path` represents the same +// file/directory). Only supports absolute paths. +bool PathStartsWith(std::string_view path, std::string_view prefix); + +// Returns the fstab entries in /proc/mounts where the mount point is a prefix of the given path. +android::base::Result<std::vector<android::fs_mgr::FstabEntry>> GetProcMountsAncestorsOfPath( + std::string_view path); + +// Returns the fstab entries in /proc/mounts where the given path is a prefix of the mount point. +android::base::Result<std::vector<android::fs_mgr::FstabEntry>> GetProcMountsDescendantsOfPath( + std::string_view path); + } // namespace tools } // namespace art diff --git a/libarttools/include_binder_utils/tools/binder_utils.h b/libarttools/include_binder_utils/tools/binder_utils.h new file mode 100644 index 0000000000..342cdb48dd --- /dev/null +++ b/libarttools/include_binder_utils/tools/binder_utils.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +/** Binder utilities. Consumers of this library must link to "libbinder_ndk". */ + +#ifndef ART_LIBARTTOOLS_INCLUDE_BINDER_UTILS_TOOLS_BINDER_UTILS_H_ +#define ART_LIBARTTOOLS_INCLUDE_BINDER_UTILS_TOOLS_BINDER_UTILS_H_ + +#include <string> + +#include "android-base/result.h" +#include "android-base/strings.h" +#include "android/binder_auto_utils.h" + +namespace art { +namespace tools { + +static std::string EscapeErrorMessage(const std::string& message) { + return android::base::StringReplace(message, std::string("\0", /*n=*/1), "\\0", /*all=*/true); +} + +// Indicates an error that should never happen (e.g., illegal arguments passed by service-art +// internally). System server should crash if this kind of error happens. +[[maybe_unused]] static ndk::ScopedAStatus Fatal(const std::string& message) { + return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, + EscapeErrorMessage(message).c_str()); +} + +// Indicates an error that service-art should handle (e.g., I/O errors, sub-process crashes). +// The scope of the error depends on the function that throws it, so service-art should catch the +// error at every call site and take different actions. +// Ideally, this should be a checked exception or an additional return value that forces service-art +// to handle it, but `ServiceSpecificException` (a separate runtime exception type) is the best +// approximate we have given the limitation of Java and Binder. +[[maybe_unused]] static ndk::ScopedAStatus NonFatal(const std::string& message) { + constexpr int32_t kServiceArtNonFatalErrorCode = 1; + return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage( + kServiceArtNonFatalErrorCode, EscapeErrorMessage(message).c_str()); +} + +} // namespace tools +} // namespace art + +#define OR_RETURN_ERROR(func, expr) \ + ({ \ + decltype(expr)&& __or_return_error_tmp = (expr); \ + if (!__or_return_error_tmp.ok()) { \ + return (func)(__or_return_error_tmp.error().message()); \ + } \ + std::move(__or_return_error_tmp).value(); \ + }) + +#define OR_RETURN_FATAL(expr) OR_RETURN_ERROR(Fatal, expr) +#define OR_RETURN_NON_FATAL(expr) OR_RETURN_ERROR(NonFatal, expr) +#define OR_LOG_AND_RETURN_OK(expr) \ + OR_RETURN_ERROR( \ + [](const std::string& message) { \ + LOG(ERROR) << message; \ + return ScopedAStatus::ok(); \ + }, \ + expr) + +#endif // ART_LIBARTTOOLS_INCLUDE_BINDER_UTILS_TOOLS_BINDER_UTILS_H_ diff --git a/libarttools/tools.cc b/libarttools/tools.cc index a72217e6ef..e355f6d1fa 100644 --- a/libarttools/tools.cc +++ b/libarttools/tools.cc @@ -28,14 +28,25 @@ #include <system_error> #include <vector> +#include "android-base/function_ref.h" #include "android-base/logging.h" +#include "android-base/result.h" +#include "android-base/strings.h" #include "base/macros.h" +#include "fstab/fstab.h" namespace art { namespace tools { namespace { +using ::android::base::ConsumeSuffix; +using ::android::base::function_ref; +using ::android::base::Result; +using ::android::base::StartsWith; +using ::android::fs_mgr::Fstab; +using ::android::fs_mgr::FstabEntry; +using ::android::fs_mgr::ReadFstabFromProcMounts; using ::std::placeholders::_1; // Returns true if `path_prefix` matches `pattern` or can be a prefix of a path that matches @@ -143,5 +154,45 @@ std::string EscapeGlob(const std::string& str) { return std::regex_replace(str, std::regex(R"re(\*|\?|\[)re"), "[$&]"); } +bool PathStartsWith(std::string_view path, std::string_view prefix) { + CHECK(!prefix.empty() && !path.empty() && prefix[0] == '/' && path[0] == '/') + << ART_FORMAT("path={}, prefix={}", path, prefix); + ConsumeSuffix(&prefix, "/"); + return StartsWith(path, prefix) && + (path.length() == prefix.length() || path[prefix.length()] == '/'); +} + +static Result<std::vector<FstabEntry>> GetProcMountsMatches( + function_ref<bool(std::string_view)> predicate) { + Fstab fstab; + if (!ReadFstabFromProcMounts(&fstab)) { + return Errorf("Failed to read fstab from /proc/mounts"); + } + std::vector<FstabEntry> entries; + for (FstabEntry& entry : fstab) { + // Ignore swap areas as a swap area doesn't have a meaningful `mount_point` (a.k.a., `fs_file`) + // field, according to fstab(5). In addition, ignore any other entries whose mount points are + // not absolute paths, just in case there are other fs types that also have an meaningless mount + // point. + if (entry.fs_type == "swap" || !StartsWith(entry.mount_point, '/')) { + continue; + } + if (predicate(entry.mount_point)) { + entries.push_back(std::move(entry)); + } + } + return entries; +} + +Result<std::vector<FstabEntry>> GetProcMountsAncestorsOfPath(std::string_view path) { + return GetProcMountsMatches( + [&](std::string_view mount_point) { return PathStartsWith(path, mount_point); }); +} + +Result<std::vector<FstabEntry>> GetProcMountsDescendantsOfPath(std::string_view path) { + return GetProcMountsMatches( + [&](std::string_view mount_point) { return PathStartsWith(mount_point, path); }); +} + } // namespace tools } // namespace art diff --git a/libarttools/tools_test.cc b/libarttools/tools_test.cc index ca39c947a6..43fa3f42c4 100644 --- a/libarttools/tools_test.cc +++ b/libarttools/tools_test.cc @@ -141,6 +141,22 @@ TEST_F(ArtToolsTest, EscapeGlob) { verify_escape(scratch_path_ + "/[a-z[a-z]][a-z].txt"); } +TEST_F(ArtToolsTest, PathStartsWith) { + EXPECT_TRUE(PathStartsWith("/a/b", "/a")); + EXPECT_TRUE(PathStartsWith("/a/b", "/a/")); + + EXPECT_FALSE(PathStartsWith("/a/c", "/a/b")); + EXPECT_FALSE(PathStartsWith("/ab", "/a")); + + EXPECT_TRUE(PathStartsWith("/a", "/a")); + EXPECT_TRUE(PathStartsWith("/a/", "/a")); + EXPECT_TRUE(PathStartsWith("/a", "/a/")); + + EXPECT_TRUE(PathStartsWith("/a", "/")); + EXPECT_TRUE(PathStartsWith("/", "/")); + EXPECT_FALSE(PathStartsWith("/", "/a")); +} + } // namespace } // namespace tools } // namespace art |