std::string GetAndroidRootSafe(std::string* error_msg) { #ifdef _WIN32
UNUSED(kAndroidRootEnvVar, kAndroidRootDefaultPath);
*error_msg = "GetAndroidRootSafe unsupported for Windows."; return""; #else
std::string local_error_msg; constchar* dir = GetAndroidDirSafe(kAndroidRootEnvVar,
kAndroidRootDefaultPath, /*must_exist=*/true,
&local_error_msg); if (dir == nullptr) { if (!kIsTargetBuild) { // On host we assume the gtest binaries are in subdirectories like // .../host/testcases/art_runtime_tests/x86_64/art_runtime_tests/, so // determine the root by going two levels up from that.
std::string argv; if (android::base::ReadFileToString("/proc/self/cmdline", &argv)) { // /proc/self/cmdline is the programs 'argv' with elements delimited by '\0'.
std::filesystem::path path(argv.substr(0, argv.find('\0')));
path = std::filesystem::absolute(path).parent_path(); if (path.has_relative_path()) { return path.parent_path();
}
}
}
*error_msg = std::move(local_error_msg); return"";
}
std::string GetArtRoot() {
std::string error_msg;
std::string ret = GetArtRootSafe(&error_msg); if (ret.empty()) {
LOG(FATAL) << error_msg;
UNREACHABLE();
} return ret;
}
std::string GetArtBinDir() { // Environment variable `ANDROID_ART_ROOT` is defined as // `$ANDROID_HOST_OUT/com.android.art` on host. However, host ART binaries are // still installed in `$ANDROID_HOST_OUT/bin` (i.e. outside the ART Root). The // situation is cleaner on target, where `ANDROID_ART_ROOT` is // `$ANDROID_ROOT/apex/com.android.art` and ART binaries are installed in // `$ANDROID_ROOT/apex/com.android.art/bin`.
std::string android_art_root = kIsTargetBuild ? GetArtRoot() : GetAndroidRoot(); return android_art_root + "/bin";
}
std::string GetFirstMainlineFrameworkLibraryFilename(std::string* error_msg) { constchar* env_bcp = getenv("BOOTCLASSPATH"); constchar* env_dex2oat_bcp = getenv("DEX2OATBOOTCLASSPATH"); if (env_bcp == nullptr || env_dex2oat_bcp == nullptr) {
*error_msg = "BOOTCLASSPATH and DEX2OATBOOTCLASSPATH must not be empty"; return"";
}
// DEX2OATBOOTCLASSPATH contains core libraries and framework libraries. We used to only compile // those libraries. Now we compile mainline framework libraries as well, and we have repurposed // DEX2OATBOOTCLASSPATH to indicate the separation between mainline framework libraries and other // libraries.
std::string_view mainline_bcp(env_bcp); if (!android::base::ConsumePrefix(&mainline_bcp, env_dex2oat_bcp)) {
*error_msg = "DEX2OATBOOTCLASSPATH must be a prefix of BOOTCLASSPATH"; return"";
}
std::vector<std::string_view> mainline_bcp_jars;
Split(mainline_bcp, ':', &mainline_bcp_jars); if (mainline_bcp_jars.empty()) {
*error_msg = "No mainline framework library found"; return"";
}
// Returns true when no error occurs, even if the extension doesn't exist. staticbool MaybeAppendBootImageMainlineExtension(const std::string& android_root, bool deny_system_files, bool deny_art_apex_data_files, /*inout*/ std::string* location, /*out*/ std::string* error_msg) { if (!kIsTargetAndroid || RunningOnVM() || RunningOnSBC()) { returntrue;
} // Due to how the runtime determines the mapping between boot images and bootclasspath jars, the // name of the boot image extension must be in the format of // `<primary-boot-image-stem>-<first-library-name>.art`.
std::string library_name = GetFirstMainlineFrameworkLibraryName(error_msg); if (library_name.empty()) { returnfalse;
}
if (!deny_system_files) {
std::string mainline_extension_location = StringPrintf( "%s/framework/%s-%s.art", android_root.c_str(), kBootImageStem, library_name.c_str());
std::string mainline_extension_path =
GetSystemImageFilename(mainline_extension_location.c_str(), kRuntimeISA); // It is expected that the file doesn't exist when the ART module is preloaded on an old source // tree that doesn't dexpreopt mainline BCP jars, so it shouldn't be considered as an error. if (OS::FileExists(mainline_extension_path.c_str(), /*check_file_type=*/true)) {
*location += ":" + mainline_extension_location; returntrue;
}
}
// If an update for the ART module has been been installed, a single boot image for the entire // bootclasspath is in the ART APEX data directory. if (kIsTargetBuild && !deny_art_apex_data_files) { const std::string boot_image = GetApexDataDalvikCacheDirectory(InstructionSet::kNone) + "/" +
kBootImageStem + kArtExtension; const std::string boot_image_filename = GetSystemImageFilename(boot_image.c_str(), kRuntimeISA); if (OS::FileExists(boot_image_filename.c_str(), /*check_file_type=*/true)) { // Boot image consists of two parts: // - the primary boot image (contains the Core Libraries and framework libraries) // - the boot image mainline extension (contains mainline framework libraries) // Typically // "/data/misc/apexdata/com.android.art/dalvik-cache/boot.art!/apex/com.android.art // /etc/boot-image.prof!/system/etc/boot-image.prof: // /data/misc/apexdata/com.android.art/dalvik-cache/boot-framework-adservices.art".
std::string location = StringPrintf("%s!%s/%s!%s/%s",
boot_image.c_str(),
kAndroidArtApexDefaultPath,
kEtcBootImageProf,
android_root.c_str(),
kEtcBootImageProf); if (!MaybeAppendBootImageMainlineExtension(android_root, /*deny_system_files=*/true,
deny_art_apex_data_files,
&location,
error_msg)) { return"";
} return location;
} elseif (errno == EACCES) { // Additional warning for potential SELinux misconfiguration.
PLOG(ERROR) << "Default boot image check failed, could not stat: " << boot_image_filename;
}
// odrefresh can generate a minimal boot image, which only includes code from BCP jars in the // ART module, when it fails to generate a single boot image for the entire bootclasspath (i.e., // full boot image). Use it if it exists. const std::string minimal_boot_image = GetApexDataDalvikCacheDirectory(InstructionSet::kNone) + "/" + kMinimalBootImageStem + kArtExtension; const std::string minimal_boot_image_filename =
GetSystemImageFilename(minimal_boot_image.c_str(), kRuntimeISA); if (OS::FileExists(minimal_boot_image_filename.c_str(), /*check_file_type=*/true)) { // Typically "/data/misc/apexdata/com.android.art/dalvik-cache/boot_minimal.art!/apex // /com.android.art/etc/boot-image.prof:/nonx/boot_minimal-framework.art!/system/etc // /boot-image.prof". return StringPrintf("%s!%s/%s:/nonx/%s-framework.art!%s/%s",
minimal_boot_image.c_str(),
kAndroidArtApexDefaultPath,
kEtcBootImageProf,
kMinimalBootImageStem,
android_root.c_str(),
kEtcBootImageProf);
} elseif (errno == EACCES) { // Additional warning for potential SELinux misconfiguration.
PLOG(ERROR) << "Minimal boot image check failed, could not stat: " << boot_image_filename;
}
}
// Boot image consists of two parts: // - the primary boot image (contains the Core Libraries and framework libraries) // - the boot image mainline extension (contains mainline framework libraries) // Typically "/system/framework/boot.art // !/apex/com.android.art/etc/boot-image.prof!/system/etc/boot-image.prof: // /system/framework/boot-framework-adservices.art".
#ifdef ART_TARGET_ANDROID // Prior to U, there was a framework extension. if (!android::modules::sdklevel::IsAtLeastU()) {
location = StringPrintf("%s/%s.art!%s/%s:%s/framework/%s-framework.art!%s/%s",
GetPrebuiltPrimaryBootImageDir(android_root).c_str(),
kBootImageStem,
kAndroidArtApexDefaultPath,
kEtcBootImageProf,
android_root.c_str(),
kBootImageStem,
android_root.c_str(),
kEtcBootImageProf);
} #endif
std::string GetJitZygoteBootImageLocation() { // Intentionally use a non-existing location so that the runtime will fail to find the boot image // and JIT bootclasspath with the given profiles. return"/nonx/boot.art!/apex/com.android.art/etc/boot-image.prof!/system/etc/boot-image.prof";
}
// Returns a path formed by encoding the dex location into the filename. The path returned will be // rooted at `cache_location`. staticbool GetLocationEncodedFilename(std::string_view location,
std::string_view cache_location,
std::string* filename,
std::string* error_msg) { if (!location.starts_with('/')) {
*error_msg = "Expected path in location to be absolute: " + std::string(location); returnfalse;
}
*filename = cache_location;
*filename += location; // Including the leading slash.
size_t replace_start = cache_location.length() + /* skip the leading slash from `location` */ 1u;
std::replace(filename->begin() + replace_start, filename->end(), '/', '@'); if (!location.ends_with(".dex") && !location.ends_with(kArtExtension) &&
!location.ends_with(kOatExtension)) {
*filename += "@";
*filename += kClassesDex;
} returntrue;
}
// check for the file in /system, followed by /system_ext
std::string GetSystemOdexFilenameForApex(std::string_view location, InstructionSet isa) {
DCHECK(LocationIsOnApex(location));
std::string dir = GetAndroidRoot() + "/framework/oat/" + GetInstructionSetString(isa);
std::string result, error_msg; bool ret = GetLocationEncodedFilename(location, dir, &result, &error_msg); // This should never fail. The function fails only if the location is not absolute, and a location // on /apex is always absolute.
DCHECK(ret) << error_msg;
std::string path = ReplaceFileExtension(result, kOdexExtension); if (OS::FileExists(path.c_str(), /*check_file_type=*/true)) { return path;
} // check in /system_ext
dir = GetSystemExtRoot() + "/framework/oat/" + GetInstructionSetString(isa);
ret = GetLocationEncodedFilename(location, dir, &result, &error_msg); // This should never fail. The function fails only if the location is not absolute, and a location // on /apex is always absolute.
DCHECK(ret) << error_msg; return ReplaceFileExtension(result, kOdexExtension);
}
// Returns true if full_path starts with <prefix>/<subdir>, where subdir is optional. staticbool PathStartsWith(std::string_view full_path, constchar* prefix, constchar* subdir) { // Build the path which we will check is a prefix of `full_path`. The prefix must // end with a slash, so that "/foo/bar" does not match "/foo/barz".
DCHECK(StartsWithSlash(prefix)) << prefix;
std::string path_prefix(prefix); if (!EndsWithSlash(path_prefix.c_str())) {
path_prefix.append("/");
} if (subdir != nullptr) { // If `subdir` is provided, we assume it is provided without a starting slash // but ending with one, e.g. "sub/dir/". `path_prefix` ends with a slash at // this point, so we simply append `subdir`.
DCHECK(!StartsWithSlash(subdir) && EndsWithSlash(subdir)) << subdir;
path_prefix.append(subdir);
}
std::string_view ApexNameFromLocation(std::string_view dex_location) {
std::string apex_root = GetApexRoot(); if (!dex_location.starts_with(apex_root)) { return {};
}
size_t start = apex_root.length();
size_t end = dex_location.find('/', start); if (end == std::string_view::npos) { return {};
} return dex_location.substr(start, end - start);
}
#ifndef _WIN32 // Returns true if `full_path` is located in folder either provided with `env_var` // or in `default_path` otherwise. The caller may optionally provide a `subdir` // which will be appended to the tested prefix. // `default_path` and the value of environment variable `env_var` // are expected to begin with a slash and not end with one. If this ever changes, // the path-building logic should be updated. staticbool IsLocationOn(std::string_view full_path, constchar* env_var, constchar* default_path, constchar* subdir = nullptr) {
std::string unused_error_msg; constchar* path = GetAndroidDirSafe(env_var,
default_path, /* must_exist= */ kIsTargetBuild,
&unused_error_msg); if (path == nullptr) { returnfalse;
} return PathStartsWith(full_path, path, subdir);
} #endif
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.