using ::android::base::ConsumePrefix; using ::android::base::Join; using ::android::base::ParseInt; using ::android::base::Result; using ::android::base::Split; using ::art::OS;
constexpr constchar* kUsage =
R"(A wrapper binary that configures the process and executes a command.
By default, it closes all open file descriptors except stdin, stdout, and stderr. `--keep-fds` can
be passed to keep some more file descriptors open.
Usage: art_exec [OPTIONS]... -- [COMMAND]...
Supported options:
--help: Print this text.
--set-task-profile=PROFILES: Apply a set of task profiles (see
https://source.android.com/devices/tech/perf/cgroups). Requires root access. PROFILES can be a
comma-separated list of task profile names.
--set-priority=PRIORITY: Apply the process priority. Currently, the only supported value of
PRIORITY is "background".
--drop-capabilities: Drop all root capabilities. Note that this has effect only if `art_exec` runs
with some root capabilities but not as the root user.
--keep-fds=FILE_DESCRIPTORS: A semicolon-separated list of file descriptors to keep open.
--env=KEY=VALUE: Set an environment variable. This flag can be passed multiple times to set
multiple environment variables.
--process-name-suffix=SUFFIX: Add a suffix in parentheses to argv[0] when calling `execv`. This
suffix will show up as part of the process name in tombstone when the process crashes.
--redirect-stderr-to-fd=FILE_DESCRIPTOR: Redirect stderr to the specified file descriptor. This
descriptor is dup'ed to stderr and should be closed after then, so it should not be included
in --keep-fds.
)";
constexpr int kErrorUsage = 100;
constexpr int kErrorOther = 101;
Result<void> DropInheritableCaps() {
art::ScopedCap cap(cap_get_proc()); if (cap.Get() == nullptr) { return ErrnoErrorf("Failed to call cap_get_proc");
} if (cap_clear_flag(cap.Get(), CAP_INHERITABLE) != 0) { return ErrnoErrorf("Failed to call cap_clear_flag");
} if (cap_set_proc(cap.Get()) != 0) { return ErrnoErrorf("Failed to call cap_set_proc");
} return {};
}
Result<void> CloseFds(const std::unordered_set<int>& keep_fds) {
std::vector<int> open_fds;
std::error_code ec; for (const std::filesystem::directory_entry& dir_entry :
std::filesystem::directory_iterator("/proc/self/fd", ec)) { int fd; if (!ParseInt(dir_entry.path().filename(), &fd)) { return Errorf("Invalid entry in /proc/self/fd {}", dir_entry.path().filename());
}
open_fds.push_back(fd);
} if (ec) { return Errorf("Failed to list open FDs: {}", ec.message());
} for (int fd : open_fds) { if (keep_fds.find(fd) == keep_fds.end()) { if (close(fd) != 0) {
Result<void> error = ErrnoErrorf("Failed to close FD {}", fd); if (std::filesystem::exists(ART_FORMAT("/proc/self/fd/{}", fd))) { return error;
}
}
}
} return {};
}
} // namespace
int main(int argc, char** argv) {
android::base::InitLogging(argv);
Options options = ParseOptions(argc, argv);
if (options.redirect_stderr_to_fd >= 0) { if (dup2(options.redirect_stderr_to_fd, fileno(stderr)) < 0) {
PLOG(ERROR) << "Failed to redirect stderr to FD " << options.redirect_stderr_to_fd;
}
}
if (auto result = CloseFds(options.keep_fds); !result.ok()) {
LOG(ERROR) << "Failed to close open FDs: " << result.error(); return kErrorOther;
}
if (!options.task_profiles.empty()) { if (int ret = PaletteSetTaskProfiles(/*tid=*/0, options.task_profiles);
ret != PALETTE_STATUS_OK) {
LOG(ERROR) << "Failed to set task profile: " << ret; return kErrorOther;
}
}
if (options.priority.has_value()) { if (setpriority(PRIO_PROCESS, /*who=*/0, options.priority.value()) != 0) {
PLOG(ERROR) << "Failed to setpriority"; return kErrorOther;
}
}
if (options.drop_capabilities) { if (auto result = DropInheritableCaps(); !result.ok()) {
LOG(ERROR) << "Failed to drop inheritable capabilities: " << result.error(); return kErrorOther;
}
}
if (!options.chroot.empty()) { if (chroot(options.chroot.c_str()) != 0) {
PLOG(ERROR) << ART_FORMAT("Failed to chroot to '{}'", options.chroot); return kErrorOther;
}
}
// `argv[argc]` is `nullptr`, which `execv` needs.
std::vector<char*> command_args(&argv[options.command_pos], &argv[argc + 1]);
std::string program_path = argv[options.command_pos]; // "/mnt/compat_env" is prepared by dexopt_chroot_setup on Android V.
constexpr constchar* kCompatArtdPath = "/mnt/compat_env/apex/com.android.art/bin/artd"; if (program_path == "/apex/com.android.art/bin/artd" && OS::FileExists(kCompatArtdPath)) {
LOG(INFO) << "Overriding program path to " << kCompatArtdPath;
program_path = kCompatArtdPath;
command_args[0] = program_path.data();
}
std::string override_program_name; if (!options.process_name_suffix.empty()) {
override_program_name = ART_FORMAT("{} ({})", command_args[0], options.process_name_suffix);
command_args[0] = override_program_name.data();
}
execv(program_path.c_str(), command_args.data());
// Remove the trialing `nullptr`.
command_args.resize(command_args.size() - 1);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.