Handle multidex in LocationIsOnSystemFramework.

bug: 79111915
Test: art_dex_file_loader_test.cc

(cherry picked from commit 0d0f3164160e50ddb78022f662c5438fc167f50d)

Change-Id: I1ee65e6a410f2a7610d0bf210eacd3cf3df13b18
diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc
index 1e0f5ac..457addf 100644
--- a/libdexfile/dex/dex_file_loader.cc
+++ b/libdexfile/dex/dex_file_loader.cc
@@ -191,6 +191,8 @@
   std::string base_location = GetBaseLocation(dex_location);
   const char* suffix = dex_location + base_location.size();
   DCHECK(suffix[0] == 0 || suffix[0] == kMultiDexSeparator);
+  // Warning: Bionic implementation of realpath() allocates > 12KB on the stack.
+  // Do not run this code on a small stack, e.g. in signal handler.
   UniqueCPtr<const char[]> path(realpath(base_location.c_str(), nullptr));
   if (path != nullptr && path.get() != base_location) {
     return std::string(path.get()) + suffix;
diff --git a/libdexfile/dex/dex_file_loader.h b/libdexfile/dex/dex_file_loader.h
index 28cdfc1..0153220 100644
--- a/libdexfile/dex/dex_file_loader.h
+++ b/libdexfile/dex/dex_file_loader.h
@@ -71,7 +71,7 @@
   //     of the dex file. In the second case (oat) it will include the file name
   //     and possibly some multidex annotation to uniquely identify it.
   // canonical_dex_location:
-  //     the dex_location where it's file name part has been made canonical.
+  //     the dex_location where its file name part has been made canonical.
   static std::string GetDexCanonicalLocation(const char* dex_location);
 
   // For normal dex files, location and base location coincide. If a dex file is part of a multidex
diff --git a/runtime/base/file_utils.cc b/runtime/base/file_utils.cc
index 09a9b97..462ee76 100644
--- a/runtime/base/file_utils.cc
+++ b/runtime/base/file_utils.cc
@@ -314,12 +314,12 @@
   }
 }
 
-bool LocationIsOnSystem(const char* location) {
-  UniqueCPtr<const char[]> path(realpath(location, nullptr));
-  return path != nullptr && android::base::StartsWith(path.get(), GetAndroidRoot().c_str());
+bool LocationIsOnSystem(const char* path) {
+  UniqueCPtr<const char[]> full_path(realpath(path, nullptr));
+  return path != nullptr && android::base::StartsWith(full_path.get(), GetAndroidRoot().c_str());
 }
 
-bool LocationIsOnSystemFramework(const char* location) {
+bool LocationIsOnSystemFramework(const char* full_path) {
   std::string error_msg;
   std::string root_path = GetAndroidRootSafe(&error_msg);
   if (root_path.empty()) {
@@ -328,12 +328,7 @@
     return false;
   }
   std::string framework_path = root_path + "/framework/";
-
-  // Warning: Bionic implementation of realpath() allocates > 12KB on the stack.
-  // Do not run this code on a small stack, e.g. in signal handler.
-  UniqueCPtr<const char[]> path(realpath(location, nullptr));
-  return path != nullptr &&
-         android::base::StartsWith(path.get(), framework_path.c_str());
+  return android::base::StartsWith(full_path, framework_path);
 }
 
 }  // namespace art
diff --git a/runtime/dex/art_dex_file_loader.cc b/runtime/dex/art_dex_file_loader.cc
index f3e6a69..16d26dc 100644
--- a/runtime/dex/art_dex_file_loader.cc
+++ b/runtime/dex/art_dex_file_loader.cc
@@ -534,7 +534,10 @@
   // Check if this dex file is located in the framework directory.
   // If it is, set a flag on the dex file. This is used by hidden API
   // policy decision logic.
-  if (dex_file != nullptr && LocationIsOnSystemFramework(location.c_str())) {
+  // Location can contain multidex suffix, so fetch its canonical version. Note
+  // that this will call `realpath`.
+  std::string path = DexFileLoader::GetDexCanonicalLocation(location.c_str());
+  if (dex_file != nullptr && LocationIsOnSystemFramework(path.c_str())) {
     dex_file->SetIsPlatformDexFile();
   }
 
diff --git a/runtime/dex/art_dex_file_loader_test.cc b/runtime/dex/art_dex_file_loader_test.cc
index 3e0d666..555fe5c 100644
--- a/runtime/dex/art_dex_file_loader_test.cc
+++ b/runtime/dex/art_dex_file_loader_test.cc
@@ -49,20 +49,31 @@
     CommonRuntimeTest::SetUp();
 
     std::string dex_location = GetTestDexFileName("Main");
+    std::string multidex_location = GetTestDexFileName("MultiDex");
 
     data_location_path_ = android_data_ + "/foo.jar";
     system_location_path_ = GetAndroidRoot() + "/foo.jar";
     system_framework_location_path_ = GetAndroidRoot() + "/framework/foo.jar";
+    data_multi_location_path_ = android_data_ + "/multifoo.jar";
+    system_multi_location_path_ = GetAndroidRoot() + "/multifoo.jar";
+    system_framework_multi_location_path_ = GetAndroidRoot() + "/framework/multifoo.jar";
 
     Copy(dex_location, data_location_path_);
     Copy(dex_location, system_location_path_);
     Copy(dex_location, system_framework_location_path_);
+
+    Copy(multidex_location, data_multi_location_path_);
+    Copy(multidex_location, system_multi_location_path_);
+    Copy(multidex_location, system_framework_multi_location_path_);
   }
 
   virtual void TearDown() {
     remove(data_location_path_.c_str());
     remove(system_location_path_.c_str());
     remove(system_framework_location_path_.c_str());
+    remove(data_multi_location_path_.c_str());
+    remove(system_multi_location_path_.c_str());
+    remove(system_framework_multi_location_path_.c_str());
     CommonRuntimeTest::TearDown();
   }
 
@@ -70,6 +81,9 @@
   std::string data_location_path_;
   std::string system_location_path_;
   std::string system_framework_location_path_;
+  std::string data_multi_location_path_;
+  std::string system_multi_location_path_;
+  std::string system_framework_multi_location_path_;
 };
 
 // TODO: Port OpenTestDexFile(s) need to be ported to use non-ART utilities, and
@@ -390,6 +404,53 @@
   for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
     ASSERT_TRUE(dex_file->IsPlatformDexFile());
   }
+
+  dex_files.clear();
+
+  // Load multidex file from a non-system directory and check that it is not flagged as framework.
+  success = loader.Open(data_multi_location_path_.c_str(),
+                        data_multi_location_path_,
+                        /* verify */ false,
+                        /* verify_checksum */ false,
+                        &error_msg,
+                        &dex_files);
+  ASSERT_TRUE(success) << error_msg;
+  ASSERT_GT(dex_files.size(), 1u);
+  for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
+    ASSERT_FALSE(dex_file->IsPlatformDexFile());
+  }
+
+  dex_files.clear();
+
+  // Load multidex file from a system, non-framework directory and check that it is not flagged
+  // as framework.
+  success = loader.Open(system_multi_location_path_.c_str(),
+                        system_multi_location_path_,
+                        /* verify */ false,
+                        /* verify_checksum */ false,
+                        &error_msg,
+                        &dex_files);
+  ASSERT_TRUE(success);
+  ASSERT_GT(dex_files.size(), 1u);
+  for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
+    ASSERT_FALSE(dex_file->IsPlatformDexFile());
+  }
+
+  dex_files.clear();
+
+  // Load multidex file from a system/framework directory and check that it is flagged as a
+  // framework dex.
+  success = loader.Open(system_framework_multi_location_path_.c_str(),
+                        system_framework_multi_location_path_,
+                        /* verify */ false,
+                        /* verify_checksum */ false,
+                        &error_msg,
+                        &dex_files);
+  ASSERT_TRUE(success);
+  ASSERT_GT(dex_files.size(), 1u);
+  for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
+    ASSERT_TRUE(dex_file->IsPlatformDexFile());
+  }
 }
 
 }  // namespace art