Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 16d7c90f authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "add IInstalld.controlDexOptBlocking call"

parents 3e0755fd 65578d6a
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -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();

@@ -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);
@@ -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,
+4 −1
Original line number Diff line number Diff line
@@ -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);
+5 −1
Original line number Diff line number Diff line
@@ -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,
@@ -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);

+157 −20
Original line number Diff line number Diff line
@@ -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>
@@ -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>
@@ -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"
@@ -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 {

@@ -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];
@@ -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);
@@ -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.
@@ -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) {
@@ -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;
@@ -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.";
@@ -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.
@@ -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);
@@ -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;
}

+8 −1
Original line number Diff line number Diff line
@@ -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