summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author David Brazdil <dbrazdil@google.com> 2019-03-22 07:00:26 -0700
committer android-build-merger <android-build-merger@google.com> 2019-03-22 07:00:26 -0700
commitb0c2c266b6b2d738559d4136512d66d3eea957fc (patch)
tree522a1104f9d739b082b8ebee0bf02ff3d4026b13
parent85d0dd11ffe9f1dc28b7c2a55a71137ec6b41478 (diff)
parent77ec238fdaa68207ed9965d8274e573f494842aa (diff)
Merge "dexopt: Open class loader context dex files for dex2oat"
am: 77ec238fda Change-Id: Iaf42b8186c2fea4878256c45cc48d74d24ae1345
-rw-r--r--cmds/installd/dexopt.cpp165
-rw-r--r--cmds/installd/tests/installd_dexopt_test.cpp23
2 files changed, 174 insertions, 14 deletions
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 72571cf622..20142aab3b 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -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);
}
@@ -1514,14 +1522,15 @@ void update_out_oat_access_times(const char* apk_path, const char* out_oat_path)
class RunDexoptAnalyzer : public ExecVHelper {
public:
RunDexoptAnalyzer(const std::string& dex_file,
- int vdex_fd,
- int oat_fd,
- int zip_fd,
- const std::string& instruction_set,
- const std::string& compiler_filter,
- bool profile_was_updated,
- bool downgrade,
- const char* class_loader_context) {
+ int vdex_fd,
+ int oat_fd,
+ int zip_fd,
+ const std::string& instruction_set,
+ const std::string& compiler_filter,
+ bool profile_was_updated,
+ bool downgrade,
+ 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,10 +1573,27 @@ 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);
+ }
};
// Prepares the oat dir for the secondary dex files.
@@ -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,
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 1d4a2f0e5e..36d5a600b2 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -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.