summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jiakai Zhang <jiakaiz@google.com> 2024-03-05 11:02:56 +0000
committer Jiakai Zhang <jiakaiz@google.com> 2024-03-07 14:24:14 +0000
commit7d595b494b55eeb65aac828fba26ce861efb9ae1 (patch)
treeff91ff1f2a8e791a87db87a52890057617a1fc93
parentf66031b556c386f582eab39b5c616104d77fc375 (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.bp1
-rw-r--r--artd/artd.cc48
-rw-r--r--artd/artd_test.cc4
-rw-r--r--artd/path_utils.cc35
-rw-r--r--artd/path_utils.h9
-rw-r--r--artd/path_utils_test.cc16
-rw-r--r--libarttools/Android.bp30
-rw-r--r--libarttools/binder_utils_test.cc17
-rw-r--r--libarttools/include/tools/tools.h16
-rw-r--r--libarttools/include_binder_utils/tools/binder_utils.h76
-rw-r--r--libarttools/tools.cc51
-rw-r--r--libarttools/tools_test.cc16
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