OSDN Git Service

Allow dex2oat to handle relative paths.
authorJeff Hao <jeffhao@google.com>
Thu, 6 Apr 2017 00:05:46 +0000 (17:05 -0700)
committerJeff Hao <jeffhao@google.com>
Wed, 19 Apr 2017 17:59:12 +0000 (10:59 -0700)
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

(cherry-picked from commit f79ac83a8c18b0bd81aafc9c8823f6bed35d8847)

Change-Id: Ib1f93b6920474d4ed008492da67d3a63174c5397

dex2oat/dex2oat.cc
runtime/oat_file.cc
runtime/oat_file.h
runtime/oat_file_manager.cc

index b4ea20b..ee76b63 100644 (file)
@@ -385,6 +385,8 @@ NO_RETURN static void Usage(const char* fmt, ...) {
   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 @@ class Dex2Oat FINAL {
           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 @@ class Dex2Oat FINAL {
       }
 
       // 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 @@ class Dex2Oat FINAL {
         // 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 @@ class Dex2Oat FINAL {
 
   // 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 @@ class Dex2Oat FINAL {
   // 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;
 
index 493da27..a00674a 100644 (file)
@@ -1497,11 +1497,18 @@ CompilerFilter::Filter OatFile::GetCompilerFilter() const {
 
 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;
index d24283a..06c76b5 100644 (file)
@@ -288,7 +288,9 @@ class OatFile {
       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.
index d04dbbe..085e2a9 100644 (file)
@@ -440,8 +440,12 @@ static bool AreSharedLibrariesOk(const std::string& shared_libraries,
     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;