/* * 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 "path_utils.h" #include #include #include #include "aidl/com/android/server/art/BnArtd.h" #include "android-base/errors.h" #include "android-base/result.h" #include "arch/instruction_set.h" #include "base/file_utils.h" #include "base/macros.h" #include "file_utils.h" #include "oat/oat_file_assistant.h" #include "runtime_image.h" #include "service.h" #include "tools/tools.h" namespace art { namespace artd { namespace { using ::aidl::com::android::server::art::ArtifactsPath; using ::aidl::com::android::server::art::DexMetadataPath; using ::aidl::com::android::server::art::OutputArtifacts; using ::aidl::com::android::server::art::OutputProfile; using ::aidl::com::android::server::art::ProfilePath; using ::aidl::com::android::server::art::RuntimeArtifactsPath; using ::aidl::com::android::server::art::VdexPath; using ::android::base::Error; using ::android::base::Result; using ::art::service::ValidateDexPath; using ::art::service::ValidatePathElement; using ::art::service::ValidatePathElementSubstring; using PrebuiltProfilePath = ProfilePath::PrebuiltProfilePath; using PrimaryCurProfilePath = ProfilePath::PrimaryCurProfilePath; using PrimaryRefProfilePath = ProfilePath::PrimaryRefProfilePath; using SecondaryCurProfilePath = ProfilePath::SecondaryCurProfilePath; using SecondaryRefProfilePath = ProfilePath::SecondaryRefProfilePath; using TmpProfilePath = ProfilePath::TmpProfilePath; using WritableProfilePath = ProfilePath::WritableProfilePath; constexpr const char* kPreRebootSuffix = ".staged"; // Only to be changed for testing. std::string_view gListRootDir = "/"; } // namespace Result GetAndroidDataOrError() { std::string error_msg; std::string result = GetAndroidDataSafe(&error_msg); if (!error_msg.empty()) { return Error() << error_msg; } return result; } Result GetAndroidExpandOrError() { std::string error_msg; std::string result = GetAndroidExpandSafe(&error_msg); if (!error_msg.empty()) { return Error() << error_msg; } return result; } Result GetArtRootOrError() { std::string error_msg; std::string result = GetArtRootSafe(&error_msg); if (!error_msg.empty()) { return Error() << error_msg; } return result; } std::vector ListManagedFiles(const std::string& android_data, const std::string& android_expand) { // See `art::tools::Glob` for the syntax. std::vector patterns = { // Profiles for primary dex files. android_data + "/misc/profiles/**", // Artifacts for primary dex files. android_data + "/dalvik-cache/**", }; for (const std::string& data_root : {android_data, android_expand + "/*"}) { // Artifacts for primary dex files. patterns.push_back(data_root + "/app/*/*/oat/**"); for (const char* user_dir : {"/user", "/user_de"}) { std::string data_dir = data_root + user_dir + "/*/*"; // Profiles and artifacts for secondary dex files. Those files are in app data directories, so // we use more granular patterns to avoid accidentally deleting apps' files. std::string secondary_oat_dir = data_dir + "/**/oat"; for (const char* suffix : {"", ".*.tmp", kPreRebootSuffix}) { patterns.push_back(secondary_oat_dir + "/*.prof" + suffix); patterns.push_back(secondary_oat_dir + "/*/*.odex" + suffix); patterns.push_back(secondary_oat_dir + "/*/*.vdex" + suffix); patterns.push_back(secondary_oat_dir + "/*/*.art" + suffix); } // Runtime image files. patterns.push_back(RuntimeImage::GetRuntimeImageDir(data_dir) + "**"); } } return tools::Glob(patterns, gListRootDir); } std::vector ListRuntimeArtifactsFiles( const std::string& android_data, const std::string& android_expand, const RuntimeArtifactsPath& runtime_artifacts_path) { // See `art::tools::Glob` for the syntax. std::vector patterns; for (const std::string& data_root : {android_data, android_expand + "/*"}) { for (const char* user_dir : {"/user", "/user_de"}) { std::string data_dir = data_root + user_dir + "/*/" + tools::EscapeGlob(runtime_artifacts_path.packageName); patterns.push_back( RuntimeImage::GetRuntimeImagePath(data_dir, tools::EscapeGlob(runtime_artifacts_path.dexPath), tools::EscapeGlob(runtime_artifacts_path.isa))); } } return tools::Glob(patterns, gListRootDir); } Result ValidateRuntimeArtifactsPath(const RuntimeArtifactsPath& runtime_artifacts_path) { OR_RETURN(ValidatePathElement(runtime_artifacts_path.packageName, "packageName")); OR_RETURN(ValidatePathElement(runtime_artifacts_path.isa, "isa")); OR_RETURN(ValidateDexPath(runtime_artifacts_path.dexPath)); return {}; } Result BuildArtBinPath(const std::string& binary_name) { return ART_FORMAT("{}/bin/{}", OR_RETURN(GetArtRootOrError()), binary_name); } Result BuildArtifactsPath(const ArtifactsPath& artifacts_path) { OR_RETURN(ValidateDexPath(artifacts_path.dexPath)); InstructionSet isa = GetInstructionSetFromString(artifacts_path.isa.c_str()); if (isa == InstructionSet::kNone) { return Errorf("Instruction set '{}' is invalid", artifacts_path.isa); } std::string error_msg; RawArtifactsPath path; if (artifacts_path.isInDalvikCache) { // Apps' OAT files are never in ART APEX data. if (!OatFileAssistant::DexLocationToOatFilename(artifacts_path.dexPath, isa, /*deny_art_apex_data_files=*/true, &path.oat_path, &error_msg)) { return Error() << error_msg; } } else { if (!OatFileAssistant::DexLocationToOdexFilename( artifacts_path.dexPath, isa, &path.oat_path, &error_msg)) { return Error() << error_msg; } } path.vdex_path = ReplaceFileExtension(path.oat_path, "vdex"); path.art_path = ReplaceFileExtension(path.oat_path, "art"); if (artifacts_path.isPreReboot) { path.oat_path += kPreRebootSuffix; path.vdex_path += kPreRebootSuffix; path.art_path += kPreRebootSuffix; } return path; } Result BuildPrimaryRefProfilePath( const PrimaryRefProfilePath& primary_ref_profile_path) { OR_RETURN(ValidatePathElement(primary_ref_profile_path.packageName, "packageName")); OR_RETURN(ValidatePathElementSubstring(primary_ref_profile_path.profileName, "profileName")); return ART_FORMAT("{}/misc/profiles/ref/{}/{}.prof{}", OR_RETURN(GetAndroidDataOrError()), primary_ref_profile_path.packageName, primary_ref_profile_path.profileName, primary_ref_profile_path.isPreReboot ? kPreRebootSuffix : ""); } Result BuildPrebuiltProfilePath(const PrebuiltProfilePath& prebuilt_profile_path) { OR_RETURN(ValidateDexPath(prebuilt_profile_path.dexPath)); return prebuilt_profile_path.dexPath + ".prof"; } Result BuildPrimaryCurProfilePath( const PrimaryCurProfilePath& primary_cur_profile_path) { OR_RETURN(ValidatePathElement(primary_cur_profile_path.packageName, "packageName")); OR_RETURN(ValidatePathElementSubstring(primary_cur_profile_path.profileName, "profileName")); return ART_FORMAT("{}/misc/profiles/cur/{}/{}/{}.prof", OR_RETURN(GetAndroidDataOrError()), primary_cur_profile_path.userId, primary_cur_profile_path.packageName, primary_cur_profile_path.profileName); } Result BuildSecondaryRefProfilePath( const SecondaryRefProfilePath& secondary_ref_profile_path) { OR_RETURN(ValidateDexPath(secondary_ref_profile_path.dexPath)); std::filesystem::path dex_path(secondary_ref_profile_path.dexPath); return ART_FORMAT("{}/oat/{}.prof{}", dex_path.parent_path().string(), dex_path.filename().string(), secondary_ref_profile_path.isPreReboot ? kPreRebootSuffix : ""); } Result BuildSecondaryCurProfilePath( const SecondaryCurProfilePath& secondary_cur_profile_path) { OR_RETURN(ValidateDexPath(secondary_cur_profile_path.dexPath)); std::filesystem::path dex_path(secondary_cur_profile_path.dexPath); return ART_FORMAT( "{}/oat/{}.cur.prof", dex_path.parent_path().string(), dex_path.filename().string()); } Result BuildWritableProfilePath(const WritableProfilePath& profile_path) { switch (profile_path.getTag()) { case WritableProfilePath::forPrimary: return BuildPrimaryRefProfilePath(profile_path.get()); case WritableProfilePath::forSecondary: return BuildSecondaryRefProfilePath(profile_path.get()); // No default. All cases should be explicitly handled, or the compilation will fail. } // This should never happen. Just in case we get a non-enumerator value. LOG(FATAL) << ART_FORMAT("Unexpected writable profile path type {}", fmt::underlying(profile_path.getTag())); } Result BuildFinalProfilePath(const TmpProfilePath& tmp_profile_path) { return BuildWritableProfilePath(tmp_profile_path.finalPath); } Result BuildTmpProfilePath(const TmpProfilePath& tmp_profile_path) { OR_RETURN(ValidatePathElementSubstring(tmp_profile_path.id, "id")); return NewFile::BuildTempPath(OR_RETURN(BuildFinalProfilePath(tmp_profile_path)), tmp_profile_path.id); } Result BuildDexMetadataPath(const DexMetadataPath& dex_metadata_path) { OR_RETURN(ValidateDexPath(dex_metadata_path.dexPath)); return ReplaceFileExtension(dex_metadata_path.dexPath, "dm"); } Result BuildProfileOrDmPath(const ProfilePath& profile_path) { switch (profile_path.getTag()) { case ProfilePath::primaryRefProfilePath: return BuildPrimaryRefProfilePath(profile_path.get()); case ProfilePath::prebuiltProfilePath: return BuildPrebuiltProfilePath(profile_path.get()); case ProfilePath::primaryCurProfilePath: return BuildPrimaryCurProfilePath(profile_path.get()); case ProfilePath::secondaryRefProfilePath: return BuildSecondaryRefProfilePath(profile_path.get()); case ProfilePath::secondaryCurProfilePath: return BuildSecondaryCurProfilePath(profile_path.get()); case ProfilePath::tmpProfilePath: return BuildTmpProfilePath(profile_path.get()); case ProfilePath::dexMetadataPath: return BuildDexMetadataPath(profile_path.get()); // No default. All cases should be explicitly handled, or the compilation will fail. } // This should never happen. Just in case we get a non-enumerator value. LOG(FATAL) << ART_FORMAT("Unexpected profile path type {}", fmt::underlying(profile_path.getTag())); } Result BuildVdexPath(const VdexPath& vdex_path) { DCHECK(vdex_path.getTag() == VdexPath::artifactsPath); return OR_RETURN(BuildArtifactsPath(vdex_path.get())).vdex_path; } bool PreRebootFlag(const ProfilePath& profile_path) { switch (profile_path.getTag()) { case ProfilePath::primaryRefProfilePath: return profile_path.get().isPreReboot; case ProfilePath::secondaryRefProfilePath: return profile_path.get().isPreReboot; case ProfilePath::tmpProfilePath: return PreRebootFlag(profile_path.get()); case ProfilePath::prebuiltProfilePath: case ProfilePath::primaryCurProfilePath: case ProfilePath::secondaryCurProfilePath: case ProfilePath::dexMetadataPath: return false; // No default. All cases should be explicitly handled, or the compilation will fail. } // This should never happen. Just in case we get a non-enumerator value. LOG(FATAL) << ART_FORMAT("Unexpected profile path type {}", fmt::underlying(profile_path.getTag())); } bool PreRebootFlag(const TmpProfilePath& tmp_profile_path) { return PreRebootFlag(tmp_profile_path.finalPath); } bool PreRebootFlag(const OutputProfile& profile) { return PreRebootFlag(profile.profilePath); } bool PreRebootFlag(const ArtifactsPath& artifacts_path) { return artifacts_path.isPreReboot; } bool PreRebootFlag(const OutputArtifacts& artifacts) { return PreRebootFlag(artifacts.artifactsPath); } bool PreRebootFlag(const VdexPath& vdex_path) { return PreRebootFlag(vdex_path.get()); } bool IsPreRebootStagedFile(std::string_view filename) { return filename.ends_with(kPreRebootSuffix); } void TestOnlySetListRootDir(std::string_view root_dir) { gListRootDir = root_dir; } } // namespace artd } // namespace art