Use the system namespace to get the right permitted paths for loading OAT files.

The ART namespace doesn't permit e.g. /product/apps, and there may be
other locations too that need to be configurable from the system linker
config.

Test: Boot
Bug: 188078687
Bug: 130340935
Change-Id: Id23c45dec6aef8379b125d70f2a47289f34c5a3a
diff --git a/libartbase/base/file_utils.h b/libartbase/base/file_utils.h
index bdabf5a..ac611ad 100644
--- a/libartbase/base/file_utils.h
+++ b/libartbase/base/file_utils.h
@@ -28,12 +28,12 @@
 
 namespace art {
 
-static constexpr const char* kAndroidArtApexDefaultPath = "/apex/com.android.art";
-static constexpr const char* kArtApexDataDefaultPath = "/data/misc/apexdata/com.android.art";
-static constexpr const char* kAndroidConscryptApexDefaultPath = "/apex/com.android.conscrypt";
-static constexpr const char* kAndroidI18nApexDefaultPath = "/apex/com.android.i18n";
+static constexpr const char kAndroidArtApexDefaultPath[] = "/apex/com.android.art";
+static constexpr const char kArtApexDataDefaultPath[] = "/data/misc/apexdata/com.android.art";
+static constexpr const char kAndroidConscryptApexDefaultPath[] = "/apex/com.android.conscrypt";
+static constexpr const char kAndroidI18nApexDefaultPath[] = "/apex/com.android.i18n";
 
-static constexpr const char* kArtImageExtension = "art";
+static constexpr const char kArtImageExtension[] = "art";
 
 // These methods return the Android Root, which is the historical location of
 // the Android "system" directory, containing the built Android artifacts. On
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 95666b9..1867894 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -375,6 +375,9 @@
                 "thread_android.cc",
                 "metrics/statsd.cc",
             ],
+            header_libs: [
+                "libnativeloader-headers", // For dlext_namespaces.h
+            ],
             shared_libs: [
                 "libdl_android",
                 "libicu",
@@ -417,7 +420,7 @@
         },
     },
     generated_sources: [
-        "art_operator_srcs"
+        "art_operator_srcs",
     ],
     // asm_support_gen.h (used by asm_support.h) is generated with cpp-define-generator
     generated_headers: ["cpp-define-generator-asm-support"],
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index d4afe0c..8a5ad63 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -31,6 +31,7 @@
 // dlopen_ext support from bionic.
 #ifdef ART_TARGET_ANDROID
 #include "android/dlext.h"
+#include "nativeloader/dlext_namespaces.h"
 #endif
 
 #include <android-base/logging.h>
@@ -1138,6 +1139,26 @@
   return success;
 }
 
+#ifdef ART_TARGET_ANDROID
+static struct android_namespace_t* GetSystemLinkerNamespace() {
+  static struct android_namespace_t* system_ns = []() {
+    // The system namespace is called "default" for binaries in /system and
+    // "system" for those in the ART APEX. Try "system" first since "default"
+    // always exists.
+    // TODO(b/185587109): Get rid of this error prone logic.
+    struct android_namespace_t* ns = android_get_exported_namespace("system");
+    if (ns == nullptr) {
+      ns = android_get_exported_namespace("default");
+      if (ns == nullptr) {
+        LOG(FATAL) << "Failed to get system namespace for loading OAT files";
+      }
+    }
+    return ns;
+  }();
+  return system_ns;
+}
+#endif  // ART_TARGET_ANDROID
+
 bool DlOpenOatFile::Dlopen(const std::string& elf_filename,
                            /*inout*/MemMap* reservation,
                            /*out*/std::string* error_msg) {
@@ -1167,6 +1188,19 @@
       extinfo.reserved_addr = reservation->Begin();
       extinfo.reserved_size = reservation->Size();
     }
+
+    if (strncmp(kAndroidArtApexDefaultPath,
+                absolute_path.get(),
+                sizeof(kAndroidArtApexDefaultPath) - 1) != 0 ||
+        absolute_path.get()[sizeof(kAndroidArtApexDefaultPath) - 1] != '/') {
+      // Use the system namespace for OAT files outside the ART APEX. Search
+      // paths and links don't matter here, but permitted paths do, and the
+      // system namespace is configured to allow loading from all appropriate
+      // locations.
+      extinfo.flags |= ANDROID_DLEXT_USE_NAMESPACE;
+      extinfo.library_namespace = GetSystemLinkerNamespace();
+    }
+
     dlopen_handle_ = android_dlopen_ext(absolute_path.get(), RTLD_NOW, &extinfo);
     if (reservation != nullptr && dlopen_handle_ != nullptr) {
       // Find used pages from the reservation.