Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/art/art/libarttools/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 9 kB image not shown  

Quelle  art_exec.cc

  Sprache: C
 

/*
 * 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 <stdlib.h>
#include <sys/capability.h>
#include <sys/resource.h>
#include <unistd.h>

#include <filesystem>
#include <iostream>
#include <iterator>
#include <optional>
#include <string>
#include <string_view>
#include <system_error>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include "android-base/logging.h"
#include "android-base/parseint.h"
#include "android-base/result.h"
#include "android-base/strings.h"
#include "base/macros.h"
#include "base/os.h"
#include "base/scoped_cap.h"
#include "palette/palette.h"
#include "system/thread_defs.h"

namespace {

using ::android::base::ConsumePrefix;
using ::android::base::Join;
using ::android::base::ParseInt;
using ::android::base::Result;
using ::android::base::Split;
using ::art::OS;

constexpr const char* 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;

struct Options {
  int command_pos = -1;
  std::vector<std::string> task_profiles;
  std::optional<int> priority = std::nullopt;
  bool drop_capabilities = false;
  std::unordered_set<int> keep_fds{fileno(stdin), fileno(stdout), fileno(stderr)};
  std::unordered_map<std::string, std::string> envs;
  std::string chroot;
  std::string process_name_suffix;
  int redirect_stderr_to_fd = -1;
};

[[noreturn]] void Usage(const std::string& error_msg) {
  LOG(ERROR) << error_msg;
  std::cerr << error_msg << "\n" << kUsage << "\n";
  exit(kErrorUsage);
}

Options ParseOptions(int argc, char** argv) {
  Options options;
  for (int i = 1; i < argc; i++) {
    std::string_view arg = argv[i];
    if (arg == "--help") {
      std::cerr << kUsage << "\n";
      exit(0);
    } else if (ConsumePrefix(&arg, "--set-task-profile=")) {
      options.task_profiles = Split(std::string(arg), ",");
      if (options.task_profiles.empty()) {
        Usage("Empty task profile list");
      }
    } else if (ConsumePrefix(&arg, "--set-priority=")) {
      if (arg == "background") {
        options.priority = ANDROID_PRIORITY_BACKGROUND;
      } else {
        Usage("Unknown priority " + std::string(arg));
      }
    } else if (arg == "--drop-capabilities") {
      options.drop_capabilities = true;
    } else if (ConsumePrefix(&arg, "--keep-fds=")) {
      for (const std::string& fd_str : Split(std::string(arg), ":")) {
        int fd;
        if (!ParseInt(fd_str, &fd)) {
          Usage("Invalid fd " + fd_str);
        }
        options.keep_fds.insert(fd);
      }
    } else if (ConsumePrefix(&arg, "--env=")) {
      size_t pos = arg.find('=');
      if (pos == std::string_view::npos) {
        Usage("Malformed environment variable. Must contain '='");
      }
      options.envs[std::string(arg.substr(/*pos=*/0, /*n=*/pos))] =
          std::string(arg.substr(pos + 1));
    } else if (ConsumePrefix(&arg, "--chroot=")) {
      options.chroot = arg;
    } else if (ConsumePrefix(&arg, "--process-name-suffix=")) {
      options.process_name_suffix = arg;
    } else if (ConsumePrefix(&arg, "--redirect-stderr-to-fd=")) {
      auto fd_str = std::string(arg);
      int fd;
      if (!ParseInt(fd_str, &fd)) {
        Usage("Invalid fd " + fd_str);
      }
      options.redirect_stderr_to_fd = fd;
    } else if (arg == "--") {
      if (i + 1 >= argc) {
        Usage("Missing command after '--'");
      }
      options.command_pos = i + 1;
      return options;
    } else {
      Usage("Unknown option " + std::string(arg));
    }
  }
  Usage("Missing '--'");
}

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;
    }
  }

  for (const auto& [key, value] : options.envs) {
    setenv(key.c_str(), value.c_str(), /*overwrite=*/1);
  }

  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 const char* 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);

  PLOG(FATAL) << "Failed to execute (" << Join(command_args, ' ') << ")";
  UNREACHABLE();
}

Messung V0.5 in Prozent
C=89 H=93 G=90

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

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.