Allow dex2oat to handle relative paths.
During installation at compile time, the PackageManager is passing
shared libraries to dex2oat with -classpath. For split apps, we want the
splits to have the proper dependencies, and are now passing previous
parts of the split apk as shared libraries as we compile them all. These
apks are staged in a temp dir during compilation, so we pass a relative
path for them instead.
Since PackageManager can now pass relative paths to dex2oat as shared
libraries, dex2oat has an added --classpath-dir switch to specify the
directory to use for relative class paths. At runtime when checking
shared libraries, we use oat file functionality to resolve relative paths
to determine if the paths match.
Bug: 34169257
Test: cts-tradefed run singleCommand cts -d --module
CtsAppSecurityHostTestCases -t android.appsecurity.cts.SplitTests
Change-Id: I9667f0069c8d12e94598f8a78888d3855d870824
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index b4ea20b..ee76b63 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -385,6 +385,8 @@
UsageError(" This option is incompatible with read barriers (e.g., if dex2oat has been");
UsageError(" built with the environment variable `ART_USE_READ_BARRIER` set to `true`).");
UsageError("");
+ UsageError(" --classpath-dir=<directory-path>: directory used to resolve relative class paths.");
+ UsageError("");
std::cerr << "See log for usage error information\n";
exit(EXIT_FAILURE);
}
@@ -1234,6 +1236,8 @@
Usage("Cannot use --force-determinism with read barriers or non-CMS garbage collector");
}
force_determinism_ = true;
+ } else if (option.starts_with("--classpath-dir=")) {
+ classpath_dir_ = option.substr(strlen("--classpath-dir=")).data();
} else if (!compiler_options_->ParseCompilerOption(option, Usage)) {
Usage("Unknown argument %s", option.data());
}
@@ -1486,12 +1490,13 @@
}
// Open dex files for class path.
- const std::vector<std::string> class_path_locations =
+ std::vector<std::string> class_path_locations =
GetClassPathLocations(runtime_->GetClassPathString());
OpenClassPathFiles(class_path_locations,
&class_path_files_,
&opened_oat_files_,
- runtime_->GetInstructionSet());
+ runtime_->GetInstructionSet(),
+ classpath_dir_);
// Store the classpath we have right now.
std::vector<const DexFile*> class_path_files = MakeNonOwningPointerVector(class_path_files_);
@@ -1501,7 +1506,7 @@
// When passing the special shared library as the classpath, it is the only path.
encoded_class_path = OatFile::kSpecialSharedLibrary;
} else {
- encoded_class_path = OatFile::EncodeDexFileDependencies(class_path_files);
+ encoded_class_path = OatFile::EncodeDexFileDependencies(class_path_files, classpath_dir_);
}
key_value_store_->Put(OatHeader::kClassPathKey, encoded_class_path);
}
@@ -2180,18 +2185,23 @@
// Opens requested class path files and appends them to opened_dex_files. If the dex files have
// been stripped, this opens them from their oat files and appends them to opened_oat_files.
- static void OpenClassPathFiles(const std::vector<std::string>& class_path_locations,
+ static void OpenClassPathFiles(std::vector<std::string>& class_path_locations,
std::vector<std::unique_ptr<const DexFile>>* opened_dex_files,
std::vector<std::unique_ptr<OatFile>>* opened_oat_files,
- InstructionSet isa) {
+ InstructionSet isa,
+ std::string& classpath_dir) {
DCHECK(opened_dex_files != nullptr) << "OpenClassPathFiles dex out-param is nullptr";
DCHECK(opened_oat_files != nullptr) << "OpenClassPathFiles oat out-param is nullptr";
- for (const std::string& location : class_path_locations) {
+ for (std::string& location : class_path_locations) {
// Stop early if we detect the special shared library, which may be passed as the classpath
// for dex2oat when we want to skip the shared libraries check.
if (location == OatFile::kSpecialSharedLibrary) {
break;
}
+ // If path is relative, append it to the provided base directory.
+ if (!classpath_dir.empty() && location[0] != '/') {
+ location = classpath_dir + '/' + location;
+ }
static constexpr bool kVerifyChecksum = true;
std::string error_msg;
if (!DexFile::Open(
@@ -2743,6 +2753,9 @@
// See CompilerOptions.force_determinism_.
bool force_determinism_;
+ // Directory of relative classpaths.
+ std::string classpath_dir_;
+
// Whether the given input vdex is also the output.
bool update_input_vdex_ = false;
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 493da27..a00674a 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1497,11 +1497,18 @@
static constexpr char kDexClassPathEncodingSeparator = '*';
-std::string OatFile::EncodeDexFileDependencies(const std::vector<const DexFile*>& dex_files) {
+std::string OatFile::EncodeDexFileDependencies(const std::vector<const DexFile*>& dex_files,
+ std::string& base_dir) {
std::ostringstream out;
for (const DexFile* dex_file : dex_files) {
- out << dex_file->GetLocation().c_str();
+ const std::string& location = dex_file->GetLocation();
+ // Find paths that were relative and convert them back from absolute.
+ if (!base_dir.empty() && location.substr(0, base_dir.length()) == base_dir) {
+ out << location.substr(base_dir.length() + 1).c_str();
+ } else {
+ out << dex_file->GetLocation().c_str();
+ }
out << kDexClassPathEncodingSeparator;
out << dex_file->GetLocationChecksum();
out << kDexClassPathEncodingSeparator;
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index d24283a..06c76b5 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -288,7 +288,9 @@
const char* abs_dex_location, const std::string& rel_dex_location);
// Create a dependency list (dex locations and checksums) for the given dex files.
- static std::string EncodeDexFileDependencies(const std::vector<const DexFile*>& dex_files);
+ // Removes dex file paths prefixed with base_dir to convert them back to relative paths.
+ static std::string EncodeDexFileDependencies(const std::vector<const DexFile*>& dex_files,
+ std::string& base_dir);
// Finds the associated oat class for a dex_file and descriptor. Returns an invalid OatClass on
// error and sets found to false.
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index a950980..1390222 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -440,8 +440,12 @@
return false;
}
+ // Check that the loaded dex files have the same order and checksums as the shared libraries.
for (size_t i = 0; i < dex_files.size(); ++i) {
- if (dex_files[i]->GetLocation() != shared_libraries_split[i * 2]) {
+ std::string absolute_library_path =
+ OatFile::ResolveRelativeEncodedDexLocation(dex_files[i]->GetLocation().c_str(),
+ shared_libraries_split[i * 2]);
+ if (dex_files[i]->GetLocation() != absolute_library_path) {
return false;
}
char* end;