Allow bootjars in system_ext.

Bug: 148385042
Test: Built and booted Pixel 3a both with and without a boot jar in system_ext.
Test: m test-art-host-gtest-hidden_api_test32
Test: m test-art-host-gtest-hidden_api_test64
Change-Id: I10ef0340b92aa60579ff39f888cb556dc2953f2a
diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc
index 62535a4..537d992 100644
--- a/libartbase/base/common_art_test.cc
+++ b/libartbase/base/common_art_test.cc
@@ -256,9 +256,21 @@
 void CommonArtTestImpl::SetUp() {
   SetUpAndroidRootEnvVars();
   SetUpAndroidDataDir(android_data_);
+
+  // Re-use the data temporary directory for /system_ext tests
+  android_system_ext_.append(android_data_.c_str());
+  android_system_ext_.append("/system_ext");
+  int mkdir_result = mkdir(android_system_ext_.c_str(), 0700);
+  ASSERT_EQ(mkdir_result, 0);
+  setenv("ANDROID_SYSTEM_EXT", android_system_ext_.c_str(), 1);
+
+  std::string system_ext_framework = android_system_ext_ + "/framework";
+  mkdir_result = mkdir(system_ext_framework.c_str(), 0700);
+  ASSERT_EQ(mkdir_result, 0);
+
   dalvik_cache_.append(android_data_.c_str());
   dalvik_cache_.append("/dalvik-cache");
-  int mkdir_result = mkdir(dalvik_cache_.c_str(), 0700);
+  mkdir_result = mkdir(dalvik_cache_.c_str(), 0700);
   ASSERT_EQ(mkdir_result, 0);
 
   static bool gSlowDebugTestFlag = false;
@@ -394,8 +406,12 @@
   ClearDirectory(dalvik_cache_.c_str());
   int rmdir_cache_result = rmdir(dalvik_cache_.c_str());
   ASSERT_EQ(0, rmdir_cache_result);
+  ClearDirectory(android_system_ext_.c_str(), true);
+  rmdir_cache_result = rmdir(android_system_ext_.c_str());
+  ASSERT_EQ(0, rmdir_cache_result);
   TearDownAndroidDataDir(android_data_, true);
   dalvik_cache_.clear();
+  android_system_ext_.clear();
 }
 
 static std::string GetDexFileName(const std::string& jar_prefix, bool host) {
diff --git a/libartbase/base/common_art_test.h b/libartbase/base/common_art_test.h
index 07d32d6..1db67e8 100644
--- a/libartbase/base/common_art_test.h
+++ b/libartbase/base/common_art_test.h
@@ -285,6 +285,7 @@
 
 
   std::string android_data_;
+  std::string android_system_ext_;
   std::string dalvik_cache_;
 
   virtual void SetUp();
diff --git a/libartbase/base/file_utils.cc b/libartbase/base/file_utils.cc
index 98b69f3..91cf5f7 100644
--- a/libartbase/base/file_utils.cc
+++ b/libartbase/base/file_utils.cc
@@ -68,6 +68,8 @@
 static constexpr const char* kApexDefaultPath = "/apex/";
 static constexpr const char* kAndroidRootEnvVar = "ANDROID_ROOT";
 static constexpr const char* kAndroidRootDefaultPath = "/system";
+static constexpr const char* kAndroidSystemExtRootEnvVar = "ANDROID_SYSTEM_EXT";
+static constexpr const char* kAndroidSystemExtRootDefaultPath = "/system_ext";
 static constexpr const char* kAndroidDataEnvVar = "ANDROID_DATA";
 static constexpr const char* kAndroidDataDefaultPath = "/data";
 static constexpr const char* kAndroidArtRootEnvVar = "ANDROID_ART_ROOT";
@@ -448,6 +450,13 @@
                             /* subdir= */ "framework/");
 }
 
+bool LocationIsOnSystemExtFramework(const char* full_path) {
+  return IsLocationOnModule(full_path,
+                            kAndroidSystemExtRootEnvVar,
+                            kAndroidSystemExtRootDefaultPath,
+                            /* subdir= */ "framework/");
+}
+
 bool LocationIsOnConscryptModule(const char* full_path) {
   return IsLocationOnModule(
       full_path, kAndroidConscryptRootEnvVar, kAndroidConscryptApexDefaultPath);
diff --git a/libartbase/base/file_utils.h b/libartbase/base/file_utils.h
index b1d044a..941a623 100644
--- a/libartbase/base/file_utils.h
+++ b/libartbase/base/file_utils.h
@@ -109,6 +109,9 @@
 // Return whether the location is on system/framework (i.e. android_root/framework).
 bool LocationIsOnSystemFramework(const char* location);
 
+// Return whether the location is on system_ext/framework
+bool LocationIsOnSystemExtFramework(const char* location);
+
 // Return whether the location is on /apex/.
 bool LocationIsOnApex(const char* location);
 
diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc
index 6ac57b6..86c38c2 100644
--- a/runtime/hidden_api.cc
+++ b/runtime/hidden_api.cc
@@ -107,6 +107,10 @@
     return Domain::kPlatform;
   }
 
+  if (LocationIsOnSystemExtFramework(dex_location.c_str())) {
+    return Domain::kPlatform;
+  }
+
   if (class_loader.IsNull()) {
     LOG(WARNING) << "DexFile " << dex_location
         << " is in boot class path but is not in a known location";
diff --git a/runtime/hidden_api_test.cc b/runtime/hidden_api_test.cc
index b9214ff..5a948d1 100644
--- a/runtime/hidden_api_test.cc
+++ b/runtime/hidden_api_test.cc
@@ -586,6 +586,29 @@
   ASSERT_EQ(0, remove(system_location_path.c_str()));
 }
 
+TEST_F(HiddenApiTest, DexDomain_SystemExtDir) {
+  // Load file from a system_ext, non-framework directory and check that it is not flagged as framework.
+  std::string system_ext_location_path = android_system_ext_ + "/foo.jar";
+  ASSERT_FALSE(LocationIsOnSystemExtFramework(system_ext_location_path.c_str()));
+
+  ScopedObjectAccess soa(Thread::Current());
+  std::vector<std::unique_ptr<const DexFile>> dex_files;
+  std::string error_msg;
+  ObjPtr<mirror::ClassLoader> class_loader;
+
+  ASSERT_TRUE(Copy(GetTestDexFileName("Main"), system_ext_location_path, &error_msg)) << error_msg;
+  ASSERT_TRUE(LoadDexFiles(system_ext_location_path, soa, &dex_files, &class_loader, &error_msg))
+      << error_msg;
+  ASSERT_GE(dex_files.size(), 1u);
+  ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader,
+                                       dex_files,
+                                       hiddenapi::Domain::kApplication,
+                                       &error_msg)) << error_msg;
+
+  dex_files.clear();
+  ASSERT_EQ(0, remove(system_ext_location_path.c_str()));
+}
+
 TEST_F(HiddenApiTest, DexDomain_SystemFrameworkDir) {
   // Load file from a system/framework directory and check that it is flagged as a framework dex.
   std::string system_framework_location_path = GetAndroidRoot() + "/framework/foo.jar";
@@ -613,6 +636,33 @@
   ASSERT_EQ(0, remove(system_framework_location_path.c_str()));
 }
 
+TEST_F(HiddenApiTest, DexDomain_SystemExtFrameworkDir) {
+  // Load file from a system_ext/framework directory and check that it is flagged as a framework dex.
+  std::string system_ext_framework_location_path = android_system_ext_ + "/framework/foo.jar";
+  ASSERT_TRUE(LocationIsOnSystemExtFramework(system_ext_framework_location_path.c_str()));
+
+  ScopedObjectAccess soa(Thread::Current());
+  std::vector<std::unique_ptr<const DexFile>> dex_files;
+  std::string error_msg;
+  ObjPtr<mirror::ClassLoader> class_loader;
+
+  ASSERT_TRUE(Copy(GetTestDexFileName("Main"), system_ext_framework_location_path, &error_msg))
+      << error_msg;
+  ASSERT_TRUE(LoadDexFiles(system_ext_framework_location_path,
+                           soa,
+                           &dex_files,
+                           &class_loader,
+                           &error_msg)) << error_msg;
+  ASSERT_GE(dex_files.size(), 1u);
+  ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader,
+                                       dex_files,
+                                       hiddenapi::Domain::kPlatform,
+                                       &error_msg)) << error_msg;
+
+  dex_files.clear();
+  ASSERT_EQ(0, remove(system_ext_framework_location_path.c_str()));
+}
+
 TEST_F(HiddenApiTest, DexDomain_DataDir_MultiDex) {
   // Load multidex file from a non-system directory and check that it is not flagged as framework.
   std::string data_multi_location_path = android_data_ + "/multifoo.jar";
@@ -662,6 +712,31 @@
   ASSERT_EQ(0, remove(system_multi_location_path.c_str()));
 }
 
+TEST_F(HiddenApiTest, DexDomain_SystemExtDir_MultiDex) {
+  // Load multidex file from a system_ext, non-framework directory and check that it is not flagged
+  // as framework.
+  std::string system_ext_multi_location_path = android_system_ext_ + "/multifoo.jar";
+  ASSERT_FALSE(LocationIsOnSystemExtFramework(system_ext_multi_location_path.c_str()));
+
+  ScopedObjectAccess soa(Thread::Current());
+  std::vector<std::unique_ptr<const DexFile>> dex_files;
+  std::string error_msg;
+  ObjPtr<mirror::ClassLoader> class_loader;
+
+  ASSERT_TRUE(Copy(GetTestDexFileName("MultiDex"), system_ext_multi_location_path, &error_msg))
+      << error_msg;
+  ASSERT_TRUE(LoadDexFiles(system_ext_multi_location_path, soa, &dex_files, &class_loader, &error_msg))
+      << error_msg;
+  ASSERT_GT(dex_files.size(), 1u);
+  ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader,
+                                       dex_files,
+                                       hiddenapi::Domain::kApplication,
+                                       &error_msg)) << error_msg;
+
+  dex_files.clear();
+  ASSERT_EQ(0, remove(system_ext_multi_location_path.c_str()));
+}
+
 TEST_F(HiddenApiTest, DexDomain_SystemFrameworkDir_MultiDex) {
   // Load multidex file from a system/framework directory and check that it is flagged as a
   // framework dex.
@@ -691,4 +766,33 @@
   ASSERT_EQ(0, remove(system_framework_multi_location_path.c_str()));
 }
 
+TEST_F(HiddenApiTest, DexDomain_SystemExtFrameworkDir_MultiDex) {
+  // Load multidex file from a system_ext/framework directory and check that it is flagged as a
+  // framework dex.
+  std::string system_ext_framework_multi_location_path = android_system_ext_ + "/framework/multifoo.jar";
+  ASSERT_TRUE(LocationIsOnSystemExtFramework(system_ext_framework_multi_location_path.c_str()));
+
+  ScopedObjectAccess soa(Thread::Current());
+  std::vector<std::unique_ptr<const DexFile>> dex_files;
+  std::string error_msg;
+  ObjPtr<mirror::ClassLoader> class_loader;
+
+  ASSERT_TRUE(Copy(GetTestDexFileName("MultiDex"),
+                   system_ext_framework_multi_location_path,
+                   &error_msg)) << error_msg;
+  ASSERT_TRUE(LoadDexFiles(system_ext_framework_multi_location_path,
+                           soa,
+                           &dex_files,
+                           &class_loader,
+                           &error_msg)) << error_msg;
+  ASSERT_GT(dex_files.size(), 1u);
+  ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader,
+                                       dex_files,
+                                       hiddenapi::Domain::kPlatform,
+                                       &error_msg)) << error_msg;
+
+  dex_files.clear();
+  ASSERT_EQ(0, remove(system_ext_framework_multi_location_path.c_str()));
+}
+
 }  // namespace art