Loading cmds/installd/InstalldNativeService.cpp +13 −2 Original line number Diff line number Diff line Loading @@ -307,6 +307,8 @@ status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */ } } out << "is_dexopt_blocked:" << android::installd::is_dexopt_blocked() << endl; out << endl; out.flush(); Loading Loading @@ -2399,7 +2401,8 @@ binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t const std::optional<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion, const std::optional<std::string>& profileName, const std::optional<std::string>& dexMetadataPath, const std::optional<std::string>& compilationReason) { const std::optional<std::string>& compilationReason, bool* aidl_return) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PATH(apkPath); Loading Loading @@ -2427,12 +2430,20 @@ binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t const char* dm_path = getCStr(dexMetadataPath); const char* compilation_reason = getCStr(compilationReason); std::string error_msg; bool completed = false; // not necessary but for compiler int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded, oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info, downgrade, targetSdkVersion, profile_name, dm_path, compilation_reason, &error_msg); downgrade, targetSdkVersion, profile_name, dm_path, compilation_reason, &error_msg, &completed); *aidl_return = completed; return res ? error(res, error_msg) : ok(); } binder::Status InstalldNativeService::controlDexOptBlocking(bool block) { android::installd::control_dexopt_blocking(block); return ok(); } binder::Status InstalldNativeService::compileLayouts(const std::string& apkPath, const std::string& packageName, const std ::string& outDexFile, int uid, Loading cmds/installd/InstalldNativeService.h +4 −1 Original line number Diff line number Diff line Loading @@ -114,7 +114,10 @@ public: const std::optional<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion, const std::optional<std::string>& profileName, const std::optional<std::string>& dexMetadataPath, const std::optional<std::string>& compilationReason); const std::optional<std::string>& compilationReason, bool* aidl_return); binder::Status controlDexOptBlocking(bool block); binder::Status compileLayouts(const std::string& apkPath, const std::string& packageName, const std::string& outDexFile, int uid, bool* _aidl_return); Loading cmds/installd/binder/android/os/IInstalld.aidl +5 −1 Original line number Diff line number Diff line Loading @@ -57,7 +57,8 @@ interface IInstalld { @utf8InCpp String packageName, int appId, @utf8InCpp String seInfo, int targetSdkVersion, @utf8InCpp String fromCodePath); void dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName, // Returns false if it is cancelled. Returns true if it is completed or have other errors. boolean dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName, @utf8InCpp String instructionSet, int dexoptNeeded, @nullable @utf8InCpp String outputPath, int dexFlags, @utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid, Loading @@ -66,6 +67,9 @@ interface IInstalld { @nullable @utf8InCpp String profileName, @nullable @utf8InCpp String dexMetadataPath, @nullable @utf8InCpp String compilationReason); // Blocks (when block is true) or unblock (when block is false) dexopt. // Blocking also invloves cancelling the currently running dexopt. void controlDexOptBlocking(boolean block); boolean compileLayouts(@utf8InCpp String apkPath, @utf8InCpp String packageName, @utf8InCpp String outDexFile, int uid); Loading cmds/installd/dexopt.cpp +157 −20 Original line number Diff line number Diff line Loading @@ -15,8 +15,8 @@ */ #define LOG_TAG "installd" #include <array> #include <fcntl.h> #include <signal.h> #include <stdlib.h> #include <string.h> #include <sys/capability.h> Loading @@ -28,10 +28,14 @@ #include <sys/wait.h> #include <unistd.h> #include <array> #include <iomanip> #include <mutex> #include <unordered_set> #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/no_destructor.h> #include <android-base/properties.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> Loading @@ -47,6 +51,7 @@ #include <selinux/android.h> #include <server_configurable_flags/get_flags.h> #include <system/thread_defs.h> #include <utils/Mutex.h> #include "dexopt.h" #include "dexopt_return_codes.h" Loading @@ -69,6 +74,76 @@ using android::base::StringPrintf; using android::base::WriteFully; using android::base::unique_fd; namespace { class DexOptStatus { public: // Check if dexopt is cancelled and fork if it is not cancelled. // cancelled is set to true if cancelled. Otherwise it will be set to false. // If it is not cancelled, it will return the return value of fork() call. // If cancelled, fork will not happen and it will return -1. pid_t check_cancellation_and_fork(/* out */ bool *cancelled) { std::lock_guard<std::mutex> lock(dexopt_lock_); if (dexopt_blocked_) { *cancelled = true; return -1; } pid_t pid = fork(); *cancelled = false; if (pid > 0) { // parent dexopt_pids_.insert(pid); } return pid; } // Returns true if pid was killed (is in killed list). It could have finished if killing // happened after the process is finished. bool check_if_killed_and_remove_dexopt_pid(pid_t pid) { std::lock_guard<std::mutex> lock(dexopt_lock_); dexopt_pids_.erase(pid); if (dexopt_killed_pids_.erase(pid) == 1) { return true; } return false; } // Tells whether dexopt is blocked or not. bool is_dexopt_blocked() { std::lock_guard<std::mutex> lock(dexopt_lock_); return dexopt_blocked_; } // Enable or disable dexopt blocking. void control_dexopt_blocking(bool block) { std::lock_guard<std::mutex> lock(dexopt_lock_); dexopt_blocked_ = block; if (!block) { return; } // Blocked, also kill currently running tasks for (auto pid : dexopt_pids_) { LOG(INFO) << "control_dexopt_blocking kill pid:" << pid; kill(pid, SIGKILL); dexopt_killed_pids_.insert(pid); } dexopt_pids_.clear(); } private: std::mutex dexopt_lock_; // when true, dexopt is blocked and will not run. bool dexopt_blocked_ GUARDED_BY(dexopt_lock_) = false; // PIDs of child process while runinng dexopt. // If the child process is finished, it should be removed. std::unordered_set<pid_t> dexopt_pids_ GUARDED_BY(dexopt_lock_); // PIDs of child processes killed by cancellation. std::unordered_set<pid_t> dexopt_killed_pids_ GUARDED_BY(dexopt_lock_); }; android::base::NoDestructor<DexOptStatus> dexopt_status_; } // namespace namespace android { namespace installd { Loading Loading @@ -1525,23 +1600,46 @@ static std::string join_fds(const std::vector<unique_fd>& fds) { return ss.str(); } void control_dexopt_blocking(bool block) { dexopt_status_->control_dexopt_blocking(block); } bool is_dexopt_blocked() { return dexopt_status_->is_dexopt_blocked(); } enum SecondaryDexOptProcessResult { kSecondaryDexOptProcessOk = 0, kSecondaryDexOptProcessCancelled = 1, kSecondaryDexOptProcessError = 2 }; // Processes the dex_path as a secondary dex files and return true if the path dex file should // be compiled. Returns false for errors (logged) or true if the secondary dex path was process // successfully. // When returning true, the output parameters will be: // be compiled. // Returns: kSecondaryDexOptProcessError for errors (logged). // kSecondaryDexOptProcessOk if the secondary dex path was process successfully. // kSecondaryDexOptProcessCancelled if the processing was cancelled. // // When returning kSecondaryDexOptProcessOk, the output parameters will be: // - is_public_out: whether or not the oat file should not be made public // - dexopt_needed_out: valid OatFileAsssitant::DexOptNeeded // - oat_dir_out: the oat dir path where the oat file should be stored static bool process_secondary_dex_dexopt(const std::string& dex_path, const char* pkgname, int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set, const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out, std::string* oat_dir_out, bool downgrade, const char* class_loader_context, const std::vector<std::string>& context_dex_paths, /* out */ std::string* error_msg) { static SecondaryDexOptProcessResult process_secondary_dex_dexopt(const std::string& dex_path, const char* pkgname, int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set, const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out, std::string* oat_dir_out, bool downgrade, const char* class_loader_context, const std::vector<std::string>& context_dex_paths, /* out */ std::string* error_msg) { LOG(DEBUG) << "Processing secondary dex path " << dex_path; if (dexopt_status_->is_dexopt_blocked()) { return kSecondaryDexOptProcessCancelled; } int storage_flag; if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag, error_msg)) { LOG(ERROR) << *error_msg; return false; return kSecondaryDexOptProcessError; } // Compute the oat dir as it's not easy to extract it from the child computation. char oat_path[PKG_PATH_MAX]; Loading @@ -1550,11 +1648,15 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char if (!create_secondary_dex_oat_layout( dex_path, instruction_set, oat_dir, oat_isa_dir, oat_path, error_msg)) { LOG(ERROR) << "Could not create secondary odex layout: " << *error_msg; return false; return kSecondaryDexOptProcessError; } oat_dir_out->assign(oat_dir); pid_t pid = fork(); bool cancelled = false; pid_t pid = dexopt_status_->check_cancellation_and_fork(&cancelled); if (cancelled) { return kSecondaryDexOptProcessCancelled; } if (pid == 0) { // child -- drop privileges before continuing. drop_capabilities(uid); Loading Loading @@ -1623,12 +1725,17 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char /* parent */ int result = wait_child(pid); cancelled = dexopt_status_->check_if_killed_and_remove_dexopt_pid(pid); if (!WIFEXITED(result)) { if ((WTERMSIG(result) == SIGKILL) && cancelled) { LOG(INFO) << "dexoptanalyzer cancelled for path:" << dex_path; return kSecondaryDexOptProcessCancelled; } *error_msg = StringPrintf("dexoptanalyzer failed for path %s: 0x%04x", dex_path.c_str(), result); LOG(ERROR) << *error_msg; return false; return kSecondaryDexOptProcessError; } result = WEXITSTATUS(result); // Check that we successfully executed dexoptanalyzer. Loading Loading @@ -1656,7 +1763,7 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char // It is ok to check this flag outside in the parent process. *is_public_out = ((dexopt_flags & DEXOPT_PUBLIC) != 0) && is_file_public(dex_path); return success; return success ? kSecondaryDexOptProcessOk : kSecondaryDexOptProcessError; } static std::string format_dexopt_error(int status, const char* dex_path) { Loading @@ -1670,17 +1777,29 @@ static std::string format_dexopt_error(int status, const char* dex_path) { return StringPrintf("Dex2oat invocation for %s failed with 0x%04x", dex_path, status); } int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set, int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter, const char* volume_uuid, const char* class_loader_context, const char* se_info, bool downgrade, int target_sdk_version, const char* profile_name, const char* dex_metadata_path, const char* compilation_reason, std::string* error_msg) { const char* dex_metadata_path, const char* compilation_reason, std::string* error_msg, /* out */ bool* completed) { CHECK(pkgname != nullptr); CHECK(pkgname[0] != 0); CHECK(error_msg != nullptr); CHECK_EQ(dexopt_flags & ~DEXOPT_MASK, 0) << "dexopt flags contains unknown fields: " << dexopt_flags; bool local_completed; // local placeholder for nullptr case if (completed == nullptr) { completed = &local_completed; } *completed = true; if (dexopt_status_->is_dexopt_blocked()) { *completed = false; return 0; } if (!validate_dex_path_size(dex_path)) { *error_msg = StringPrintf("Failed to validate %s", dex_path); return -1; Loading Loading @@ -1712,14 +1831,19 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins *error_msg = "Failed acquiring context dex paths"; return -1; // We had an error, logged in the process method. } if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid, instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str, downgrade, class_loader_context, context_dex_paths, error_msg)) { SecondaryDexOptProcessResult sec_dex_result = process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str, downgrade, class_loader_context, context_dex_paths, error_msg); if (sec_dex_result == kSecondaryDexOptProcessOk) { oat_dir = oat_dir_str.c_str(); if (dexopt_needed == NO_DEXOPT_NEEDED) { return 0; // Nothing to do, report success. } } else if (sec_dex_result == kSecondaryDexOptProcessCancelled) { // cancelled, not an error. *completed = false; return 0; } else { if (error_msg->empty()) { // TODO: Make this a CHECK. *error_msg = "Failed processing secondary."; Loading Loading @@ -1849,7 +1973,11 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins use_jitzygote_image, compilation_reason); pid_t pid = fork(); bool cancelled = false; pid_t pid = dexopt_status_->check_cancellation_and_fork(&cancelled); if (cancelled) { return 0; } if (pid == 0) { // Need to set schedpolicy before dropping privileges // for cgroup migration. See details at b/175178520. Loading @@ -1867,9 +1995,16 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins runner.Exec(DexoptReturnCodes::kDex2oatExec); } else { int res = wait_child(pid); bool cancelled = dexopt_status_->check_if_killed_and_remove_dexopt_pid(pid); if (res == 0) { LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' (success) ---"; } else { if ((WTERMSIG(res) == SIGKILL) && cancelled) { LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- cancelled"; // cancelled, not an error *completed = false; return 0; } LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- status=0x" << std::hex << std::setw(4) << res << ", process failed"; *error_msg = format_dexopt_error(res, dex_path); Loading @@ -1877,12 +2012,14 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins } } // TODO(b/156537504) Implement SWAP of completed files // We've been successful, don't delete output. out_oat.DisableCleanup(); out_vdex.DisableCleanup(); out_image.DisableCleanup(); reference_profile.DisableCleanup(); *completed = true; return 0; } Loading cmds/installd/dexopt.h +8 −1 Original line number Diff line number Diff line Loading @@ -121,11 +121,18 @@ bool hash_secondary_dex_file(const std::string& dex_path, const std::string& pkgname, int uid, const std::optional<std::string>& volume_uuid, int storage_flag, std::vector<uint8_t>* out_secondary_dex_hash); // completed pass false if it is canceled. Otherwise it will be true even if there is other // error. int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set, int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter, const char* volume_uuid, const char* class_loader_context, const char* se_info, bool downgrade, int target_sdk_version, const char* profile_name, const char* dexMetadataPath, const char* compilation_reason, std::string* error_msg); const char* dexMetadataPath, const char* compilation_reason, std::string* error_msg, /* out */ bool* completed = nullptr); bool is_dexopt_blocked(); void control_dexopt_blocking(bool block); bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path, const char *instruction_set); Loading Loading
cmds/installd/InstalldNativeService.cpp +13 −2 Original line number Diff line number Diff line Loading @@ -307,6 +307,8 @@ status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */ } } out << "is_dexopt_blocked:" << android::installd::is_dexopt_blocked() << endl; out << endl; out.flush(); Loading Loading @@ -2399,7 +2401,8 @@ binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t const std::optional<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion, const std::optional<std::string>& profileName, const std::optional<std::string>& dexMetadataPath, const std::optional<std::string>& compilationReason) { const std::optional<std::string>& compilationReason, bool* aidl_return) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PATH(apkPath); Loading Loading @@ -2427,12 +2430,20 @@ binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t const char* dm_path = getCStr(dexMetadataPath); const char* compilation_reason = getCStr(compilationReason); std::string error_msg; bool completed = false; // not necessary but for compiler int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded, oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info, downgrade, targetSdkVersion, profile_name, dm_path, compilation_reason, &error_msg); downgrade, targetSdkVersion, profile_name, dm_path, compilation_reason, &error_msg, &completed); *aidl_return = completed; return res ? error(res, error_msg) : ok(); } binder::Status InstalldNativeService::controlDexOptBlocking(bool block) { android::installd::control_dexopt_blocking(block); return ok(); } binder::Status InstalldNativeService::compileLayouts(const std::string& apkPath, const std::string& packageName, const std ::string& outDexFile, int uid, Loading
cmds/installd/InstalldNativeService.h +4 −1 Original line number Diff line number Diff line Loading @@ -114,7 +114,10 @@ public: const std::optional<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion, const std::optional<std::string>& profileName, const std::optional<std::string>& dexMetadataPath, const std::optional<std::string>& compilationReason); const std::optional<std::string>& compilationReason, bool* aidl_return); binder::Status controlDexOptBlocking(bool block); binder::Status compileLayouts(const std::string& apkPath, const std::string& packageName, const std::string& outDexFile, int uid, bool* _aidl_return); Loading
cmds/installd/binder/android/os/IInstalld.aidl +5 −1 Original line number Diff line number Diff line Loading @@ -57,7 +57,8 @@ interface IInstalld { @utf8InCpp String packageName, int appId, @utf8InCpp String seInfo, int targetSdkVersion, @utf8InCpp String fromCodePath); void dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName, // Returns false if it is cancelled. Returns true if it is completed or have other errors. boolean dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName, @utf8InCpp String instructionSet, int dexoptNeeded, @nullable @utf8InCpp String outputPath, int dexFlags, @utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid, Loading @@ -66,6 +67,9 @@ interface IInstalld { @nullable @utf8InCpp String profileName, @nullable @utf8InCpp String dexMetadataPath, @nullable @utf8InCpp String compilationReason); // Blocks (when block is true) or unblock (when block is false) dexopt. // Blocking also invloves cancelling the currently running dexopt. void controlDexOptBlocking(boolean block); boolean compileLayouts(@utf8InCpp String apkPath, @utf8InCpp String packageName, @utf8InCpp String outDexFile, int uid); Loading
cmds/installd/dexopt.cpp +157 −20 Original line number Diff line number Diff line Loading @@ -15,8 +15,8 @@ */ #define LOG_TAG "installd" #include <array> #include <fcntl.h> #include <signal.h> #include <stdlib.h> #include <string.h> #include <sys/capability.h> Loading @@ -28,10 +28,14 @@ #include <sys/wait.h> #include <unistd.h> #include <array> #include <iomanip> #include <mutex> #include <unordered_set> #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/no_destructor.h> #include <android-base/properties.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> Loading @@ -47,6 +51,7 @@ #include <selinux/android.h> #include <server_configurable_flags/get_flags.h> #include <system/thread_defs.h> #include <utils/Mutex.h> #include "dexopt.h" #include "dexopt_return_codes.h" Loading @@ -69,6 +74,76 @@ using android::base::StringPrintf; using android::base::WriteFully; using android::base::unique_fd; namespace { class DexOptStatus { public: // Check if dexopt is cancelled and fork if it is not cancelled. // cancelled is set to true if cancelled. Otherwise it will be set to false. // If it is not cancelled, it will return the return value of fork() call. // If cancelled, fork will not happen and it will return -1. pid_t check_cancellation_and_fork(/* out */ bool *cancelled) { std::lock_guard<std::mutex> lock(dexopt_lock_); if (dexopt_blocked_) { *cancelled = true; return -1; } pid_t pid = fork(); *cancelled = false; if (pid > 0) { // parent dexopt_pids_.insert(pid); } return pid; } // Returns true if pid was killed (is in killed list). It could have finished if killing // happened after the process is finished. bool check_if_killed_and_remove_dexopt_pid(pid_t pid) { std::lock_guard<std::mutex> lock(dexopt_lock_); dexopt_pids_.erase(pid); if (dexopt_killed_pids_.erase(pid) == 1) { return true; } return false; } // Tells whether dexopt is blocked or not. bool is_dexopt_blocked() { std::lock_guard<std::mutex> lock(dexopt_lock_); return dexopt_blocked_; } // Enable or disable dexopt blocking. void control_dexopt_blocking(bool block) { std::lock_guard<std::mutex> lock(dexopt_lock_); dexopt_blocked_ = block; if (!block) { return; } // Blocked, also kill currently running tasks for (auto pid : dexopt_pids_) { LOG(INFO) << "control_dexopt_blocking kill pid:" << pid; kill(pid, SIGKILL); dexopt_killed_pids_.insert(pid); } dexopt_pids_.clear(); } private: std::mutex dexopt_lock_; // when true, dexopt is blocked and will not run. bool dexopt_blocked_ GUARDED_BY(dexopt_lock_) = false; // PIDs of child process while runinng dexopt. // If the child process is finished, it should be removed. std::unordered_set<pid_t> dexopt_pids_ GUARDED_BY(dexopt_lock_); // PIDs of child processes killed by cancellation. std::unordered_set<pid_t> dexopt_killed_pids_ GUARDED_BY(dexopt_lock_); }; android::base::NoDestructor<DexOptStatus> dexopt_status_; } // namespace namespace android { namespace installd { Loading Loading @@ -1525,23 +1600,46 @@ static std::string join_fds(const std::vector<unique_fd>& fds) { return ss.str(); } void control_dexopt_blocking(bool block) { dexopt_status_->control_dexopt_blocking(block); } bool is_dexopt_blocked() { return dexopt_status_->is_dexopt_blocked(); } enum SecondaryDexOptProcessResult { kSecondaryDexOptProcessOk = 0, kSecondaryDexOptProcessCancelled = 1, kSecondaryDexOptProcessError = 2 }; // Processes the dex_path as a secondary dex files and return true if the path dex file should // be compiled. Returns false for errors (logged) or true if the secondary dex path was process // successfully. // When returning true, the output parameters will be: // be compiled. // Returns: kSecondaryDexOptProcessError for errors (logged). // kSecondaryDexOptProcessOk if the secondary dex path was process successfully. // kSecondaryDexOptProcessCancelled if the processing was cancelled. // // When returning kSecondaryDexOptProcessOk, the output parameters will be: // - is_public_out: whether or not the oat file should not be made public // - dexopt_needed_out: valid OatFileAsssitant::DexOptNeeded // - oat_dir_out: the oat dir path where the oat file should be stored static bool process_secondary_dex_dexopt(const std::string& dex_path, const char* pkgname, int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set, const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out, std::string* oat_dir_out, bool downgrade, const char* class_loader_context, const std::vector<std::string>& context_dex_paths, /* out */ std::string* error_msg) { static SecondaryDexOptProcessResult process_secondary_dex_dexopt(const std::string& dex_path, const char* pkgname, int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set, const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out, std::string* oat_dir_out, bool downgrade, const char* class_loader_context, const std::vector<std::string>& context_dex_paths, /* out */ std::string* error_msg) { LOG(DEBUG) << "Processing secondary dex path " << dex_path; if (dexopt_status_->is_dexopt_blocked()) { return kSecondaryDexOptProcessCancelled; } int storage_flag; if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag, error_msg)) { LOG(ERROR) << *error_msg; return false; return kSecondaryDexOptProcessError; } // Compute the oat dir as it's not easy to extract it from the child computation. char oat_path[PKG_PATH_MAX]; Loading @@ -1550,11 +1648,15 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char if (!create_secondary_dex_oat_layout( dex_path, instruction_set, oat_dir, oat_isa_dir, oat_path, error_msg)) { LOG(ERROR) << "Could not create secondary odex layout: " << *error_msg; return false; return kSecondaryDexOptProcessError; } oat_dir_out->assign(oat_dir); pid_t pid = fork(); bool cancelled = false; pid_t pid = dexopt_status_->check_cancellation_and_fork(&cancelled); if (cancelled) { return kSecondaryDexOptProcessCancelled; } if (pid == 0) { // child -- drop privileges before continuing. drop_capabilities(uid); Loading Loading @@ -1623,12 +1725,17 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char /* parent */ int result = wait_child(pid); cancelled = dexopt_status_->check_if_killed_and_remove_dexopt_pid(pid); if (!WIFEXITED(result)) { if ((WTERMSIG(result) == SIGKILL) && cancelled) { LOG(INFO) << "dexoptanalyzer cancelled for path:" << dex_path; return kSecondaryDexOptProcessCancelled; } *error_msg = StringPrintf("dexoptanalyzer failed for path %s: 0x%04x", dex_path.c_str(), result); LOG(ERROR) << *error_msg; return false; return kSecondaryDexOptProcessError; } result = WEXITSTATUS(result); // Check that we successfully executed dexoptanalyzer. Loading Loading @@ -1656,7 +1763,7 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char // It is ok to check this flag outside in the parent process. *is_public_out = ((dexopt_flags & DEXOPT_PUBLIC) != 0) && is_file_public(dex_path); return success; return success ? kSecondaryDexOptProcessOk : kSecondaryDexOptProcessError; } static std::string format_dexopt_error(int status, const char* dex_path) { Loading @@ -1670,17 +1777,29 @@ static std::string format_dexopt_error(int status, const char* dex_path) { return StringPrintf("Dex2oat invocation for %s failed with 0x%04x", dex_path, status); } int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set, int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter, const char* volume_uuid, const char* class_loader_context, const char* se_info, bool downgrade, int target_sdk_version, const char* profile_name, const char* dex_metadata_path, const char* compilation_reason, std::string* error_msg) { const char* dex_metadata_path, const char* compilation_reason, std::string* error_msg, /* out */ bool* completed) { CHECK(pkgname != nullptr); CHECK(pkgname[0] != 0); CHECK(error_msg != nullptr); CHECK_EQ(dexopt_flags & ~DEXOPT_MASK, 0) << "dexopt flags contains unknown fields: " << dexopt_flags; bool local_completed; // local placeholder for nullptr case if (completed == nullptr) { completed = &local_completed; } *completed = true; if (dexopt_status_->is_dexopt_blocked()) { *completed = false; return 0; } if (!validate_dex_path_size(dex_path)) { *error_msg = StringPrintf("Failed to validate %s", dex_path); return -1; Loading Loading @@ -1712,14 +1831,19 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins *error_msg = "Failed acquiring context dex paths"; return -1; // We had an error, logged in the process method. } if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid, instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str, downgrade, class_loader_context, context_dex_paths, error_msg)) { SecondaryDexOptProcessResult sec_dex_result = process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str, downgrade, class_loader_context, context_dex_paths, error_msg); if (sec_dex_result == kSecondaryDexOptProcessOk) { oat_dir = oat_dir_str.c_str(); if (dexopt_needed == NO_DEXOPT_NEEDED) { return 0; // Nothing to do, report success. } } else if (sec_dex_result == kSecondaryDexOptProcessCancelled) { // cancelled, not an error. *completed = false; return 0; } else { if (error_msg->empty()) { // TODO: Make this a CHECK. *error_msg = "Failed processing secondary."; Loading Loading @@ -1849,7 +1973,11 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins use_jitzygote_image, compilation_reason); pid_t pid = fork(); bool cancelled = false; pid_t pid = dexopt_status_->check_cancellation_and_fork(&cancelled); if (cancelled) { return 0; } if (pid == 0) { // Need to set schedpolicy before dropping privileges // for cgroup migration. See details at b/175178520. Loading @@ -1867,9 +1995,16 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins runner.Exec(DexoptReturnCodes::kDex2oatExec); } else { int res = wait_child(pid); bool cancelled = dexopt_status_->check_if_killed_and_remove_dexopt_pid(pid); if (res == 0) { LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' (success) ---"; } else { if ((WTERMSIG(res) == SIGKILL) && cancelled) { LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- cancelled"; // cancelled, not an error *completed = false; return 0; } LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- status=0x" << std::hex << std::setw(4) << res << ", process failed"; *error_msg = format_dexopt_error(res, dex_path); Loading @@ -1877,12 +2012,14 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins } } // TODO(b/156537504) Implement SWAP of completed files // We've been successful, don't delete output. out_oat.DisableCleanup(); out_vdex.DisableCleanup(); out_image.DisableCleanup(); reference_profile.DisableCleanup(); *completed = true; return 0; } Loading
cmds/installd/dexopt.h +8 −1 Original line number Diff line number Diff line Loading @@ -121,11 +121,18 @@ bool hash_secondary_dex_file(const std::string& dex_path, const std::string& pkgname, int uid, const std::optional<std::string>& volume_uuid, int storage_flag, std::vector<uint8_t>* out_secondary_dex_hash); // completed pass false if it is canceled. Otherwise it will be true even if there is other // error. int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set, int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter, const char* volume_uuid, const char* class_loader_context, const char* se_info, bool downgrade, int target_sdk_version, const char* profile_name, const char* dexMetadataPath, const char* compilation_reason, std::string* error_msg); const char* dexMetadataPath, const char* compilation_reason, std::string* error_msg, /* out */ bool* completed = nullptr); bool is_dexopt_blocked(); void control_dexopt_blocking(bool block); bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path, const char *instruction_set); Loading