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

Commit 77ec238f authored by David Brazdil's avatar David Brazdil Committed by Gerrit Code Review
Browse files

Merge "dexopt: Open class loader context dex files for dex2oat"

parents 2d8e815a 4f6027a7
Loading
Loading
Loading
Loading
+153 −12
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@
using android::base::EndsWith;
using android::base::GetBoolProperty;
using android::base::GetProperty;
using android::base::ReadFdToString;
using android::base::ReadFully;
using android::base::StringPrintf;
using android::base::WriteFully;
@@ -319,6 +320,7 @@ class RunDex2Oat : public ExecVHelper {
               bool background_job_compile,
               int profile_fd,
               const char* class_loader_context,
               const std::string& class_loader_context_fds,
               int target_sdk_version,
               bool enable_hidden_api_checks,
               bool generate_compact_dex,
@@ -423,9 +425,14 @@ class RunDex2Oat : public ExecVHelper {
            target_sdk_version_arg = StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
        }
        std::string class_loader_context_arg;
        std::string class_loader_context_fds_arg;
        if (class_loader_context != nullptr) {
            class_loader_context_arg = StringPrintf("--class-loader-context=%s",
                                                    class_loader_context);
            if (!class_loader_context_fds.empty()) {
                class_loader_context_fds_arg = StringPrintf("--class-loader-context-fds=%s",
                                                            class_loader_context_fds.c_str());
            }
        }

        if (swap_fd >= 0) {
@@ -518,6 +525,7 @@ class RunDex2Oat : public ExecVHelper {
        AddArg(profile_arg);
        AddArg(base_dir);
        AddArg(class_loader_context_arg);
        AddArg(class_loader_context_fds_arg);
        if (generate_minidebug_info) {
            AddArg(kMinidebugDex2oatFlag);
        }
@@ -1521,7 +1529,8 @@ class RunDexoptAnalyzer : public ExecVHelper {
                      const std::string& compiler_filter,
                      bool profile_was_updated,
                      bool downgrade,
                    const char* class_loader_context) {
                      const char* class_loader_context,
                      const std::string& class_loader_context_fds) {
        CHECK_GE(zip_fd, 0);

        // We always run the analyzer in the background job.
@@ -1540,6 +1549,10 @@ class RunDexoptAnalyzer : public ExecVHelper {
        if (class_loader_context != nullptr) {
            class_loader_context_arg += class_loader_context;
        }
        std::string class_loader_context_fds_arg = "--class-loader-context-fds=";
        if (!class_loader_context_fds.empty()) {
            class_loader_context_fds_arg += class_loader_context_fds;
        }

        // program name, dex file, isa, filter
        AddArg(dex_file_arg);
@@ -1560,8 +1573,25 @@ class RunDexoptAnalyzer : public ExecVHelper {
        }
        if (class_loader_context != nullptr) {
            AddArg(class_loader_context_arg.c_str());
            if (!class_loader_context_fds.empty()) {
                AddArg(class_loader_context_fds_arg.c_str());
            }
        }

        PrepareArgs(dexoptanalyzer_bin);
    }

    // Dexoptanalyzer mode which flattens the given class loader context and
    // prints a list of its dex files in that flattened order.
    RunDexoptAnalyzer(const char* class_loader_context) {
        CHECK(class_loader_context != nullptr);

        // We always run the analyzer in the background job.
        const char* dexoptanalyzer_bin = select_execution_binary(
             kDexoptanalyzerPath, kDexoptanalyzerDebugPath, /*background_job_compile=*/ true);

        AddArg("--flatten-class-loader-context");
        AddArg(std::string("--class-loader-context=") + class_loader_context);
        PrepareArgs(dexoptanalyzer_bin);
    }
};
@@ -1743,6 +1773,95 @@ static bool validate_dexopt_storage_flags(int dexopt_flags,
    return true;
}

static bool get_class_loader_context_dex_paths(const char* class_loader_context, int uid,
        /* out */ std::vector<std::string>* context_dex_paths) {
    if (class_loader_context == nullptr) {
      return true;
    }

    LOG(DEBUG) << "Getting dex paths for context " << class_loader_context;

    // Pipe to get the hash result back from our child process.
    unique_fd pipe_read, pipe_write;
    if (!Pipe(&pipe_read, &pipe_write)) {
        PLOG(ERROR) << "Failed to create pipe";
        return false;
    }

    pid_t pid = fork();
    if (pid == 0) {
        // child -- drop privileges before continuing.
        drop_capabilities(uid);

        // Route stdout to `pipe_write`
        while ((dup2(pipe_write, STDOUT_FILENO) == -1) && (errno == EINTR)) {}
        pipe_write.reset();
        pipe_read.reset();

        RunDexoptAnalyzer run_dexopt_analyzer(class_loader_context);
        run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec);
    }

    /* parent */
    pipe_write.reset();

    std::string str_dex_paths;
    if (!ReadFdToString(pipe_read, &str_dex_paths)) {
        PLOG(ERROR) << "Failed to read from pipe";
        return false;
    }
    pipe_read.reset();

    int return_code = wait_child(pid);
    if (!WIFEXITED(return_code)) {
        PLOG(ERROR) << "Error waiting for child dexoptanalyzer process";
        return false;
    }

    constexpr int kFlattenClassLoaderContextSuccess = 50;
    return_code = WEXITSTATUS(return_code);
    if (return_code != kFlattenClassLoaderContextSuccess) {
        LOG(ERROR) << "Dexoptanalyzer could not flatten class loader context, code=" << return_code;
        return false;
    }

    if (!str_dex_paths.empty()) {
        *context_dex_paths = android::base::Split(str_dex_paths, ":");
    }
    return true;
}

static int open_dex_paths(const std::vector<std::string>& dex_paths,
        /* out */ std::vector<unique_fd>* zip_fds, /* out */ std::string* error_msg) {
    for (const std::string& dex_path : dex_paths) {
        zip_fds->emplace_back(open(dex_path.c_str(), O_RDONLY));
        if (zip_fds->back().get() < 0) {
            *error_msg = StringPrintf(
                    "installd cannot open '%s' for input during dexopt", dex_path.c_str());
            if (errno == ENOENT) {
                return kSecondaryDexDexoptAnalyzerSkippedNoFile;
            } else {
                return kSecondaryDexDexoptAnalyzerSkippedOpenZip;
            }
        }
    }
    return 0;
}

static std::string join_fds(const std::vector<unique_fd>& fds) {
    std::stringstream ss;
    bool is_first = true;
    for (const unique_fd& fd : fds) {
        if (is_first) {
            is_first = false;
        } else {
            ss << ":";
        }
        ss << fd.get();
    }
    return ss.str();
}

// 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.
@@ -1754,7 +1873,7 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char
        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,
        /* out */ std::string* error_msg) {
        const std::vector<std::string>& context_dex_paths, /* out */ std::string* error_msg) {
    LOG(DEBUG) << "Processing secondary dex path " << dex_path;
    int storage_flag;
    if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag, error_msg)) {
@@ -1794,6 +1913,13 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char
            }
        }

        // Open class loader context dex files.
        std::vector<unique_fd> context_zip_fds;
        int open_dex_paths_rc = open_dex_paths(context_dex_paths, &context_zip_fds, error_msg);
        if (open_dex_paths_rc != 0) {
            _exit(open_dex_paths_rc);
        }

        // Prepare the oat directories.
        if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set)) {
            _exit(kSecondaryDexDexoptAnalyzerSkippedPrepareDir);
@@ -1825,7 +1951,8 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char
                                              instruction_set,
                                              compiler_filter, profile_was_updated,
                                              downgrade,
                                              class_loader_context);
                                              class_loader_context,
                                              join_fds(context_zip_fds));
        run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec);
    }

@@ -1913,10 +2040,16 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins

    // Check if we're dealing with a secondary dex file and if we need to compile it.
    std::string oat_dir_str;
    std::vector<std::string> context_dex_paths;
    if (is_secondary_dex) {
        if (!get_class_loader_context_dex_paths(class_loader_context, uid, &context_dex_paths)) {
            *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, error_msg)) {
                downgrade, class_loader_context, context_dex_paths, error_msg)) {
            oat_dir = oat_dir_str.c_str();
            if (dexopt_needed == NO_DEXOPT_NEEDED) {
                return 0;  // Nothing to do, report success.
@@ -1928,7 +2061,7 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins
            return -1;  // We had an error, logged in the process method.
        }
    } else {
        // Currently these flags are only use for secondary dex files.
        // Currently these flags are only used for secondary dex files.
        // Verify that they are not set for primary apks.
        CHECK((dexopt_flags & DEXOPT_STORAGE_CE) == 0);
        CHECK((dexopt_flags & DEXOPT_STORAGE_DE) == 0);
@@ -1942,6 +2075,13 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins
        return -1;
    }

    // Open class loader context dex files.
    std::vector<unique_fd> context_input_fds;
    if (open_dex_paths(context_dex_paths, &context_input_fds, error_msg) != 0) {
        LOG(ERROR) << *error_msg;
        return -1;
    }

    // Create the output OAT file.
    char out_oat_path[PKG_PATH_MAX];
    Dex2oatFileWrapper out_oat_fd = open_oat_out_file(dex_path, oat_dir, is_public, uid,
@@ -2010,6 +2150,7 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins
                      background_job_compile,
                      reference_profile_fd.get(),
                      class_loader_context,
                      join_fds(context_input_fds),
                      target_sdk_version,
                      enable_hidden_api_checks,
                      generate_compact_dex,
+21 −2
Original line number Diff line number Diff line
@@ -327,16 +327,21 @@ protected:

    void CompileSecondaryDex(const std::string& path, int32_t dex_storage_flag,
            bool should_binder_call_succeed, bool should_dex_be_compiled = true,
            /*out */ binder::Status* binder_result = nullptr, int32_t uid = -1) {
            /*out */ binder::Status* binder_result = nullptr, int32_t uid = -1,
            const char* class_loader_context = nullptr) {
        if (uid == -1) {
            uid = kTestAppUid;
        }
        if (class_loader_context == nullptr) {
            class_loader_context = "&";
        }
        std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
        int32_t dexopt_needed = 0;  // does not matter;
        std::unique_ptr<std::string> out_path = nullptr;  // does not matter
        int32_t dex_flags = DEXOPT_SECONDARY_DEX | dex_storage_flag;
        std::string compiler_filter = "speed-profile";
        std::unique_ptr<std::string> class_loader_context_ptr(new std::string("&"));
        std::unique_ptr<std::string> class_loader_context_ptr(
                new std::string(class_loader_context));
        std::unique_ptr<std::string> se_info_ptr(new std::string(se_info_));
        bool downgrade = false;
        int32_t target_sdk_version = 0;  // default
@@ -555,12 +560,26 @@ TEST_F(DexoptTest, DexoptSecondaryCeLink) {
        /*binder_ok*/ true, /*compile_ok*/ true);
}

TEST_F(DexoptTest, DexoptSecondaryCeWithContext) {
    LOG(INFO) << "DexoptSecondaryCeWithContext";
    std::string class_loader_context = "PCL[" + secondary_dex_ce_ + "]";
    CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
        /*binder_ok*/ true, /*compile_ok*/ true, nullptr, -1, class_loader_context.c_str());
}

TEST_F(DexoptTest, DexoptSecondaryDe) {
    LOG(INFO) << "DexoptSecondaryDe";
    CompileSecondaryDex(secondary_dex_de_, DEXOPT_STORAGE_DE,
        /*binder_ok*/ true, /*compile_ok*/ true);
}

TEST_F(DexoptTest, DexoptSecondaryDeWithContext) {
    LOG(INFO) << "DexoptSecondaryDeWithContext";
    std::string class_loader_context = "PCL[" + secondary_dex_de_ + "]";
    CompileSecondaryDex(secondary_dex_de_, DEXOPT_STORAGE_DE,
        /*binder_ok*/ true, /*compile_ok*/ true, nullptr, -1, class_loader_context.c_str());
}

TEST_F(DexoptTest, DexoptSecondaryDoesNotExist) {
    LOG(INFO) << "DexoptSecondaryDoesNotExist";
    // If the file validates but does not exist we do not treat it as an error.