mediaextractor: load extractor plug-ins from apex

Note: media apex is not added in the default build.
The new code path will be no-op for now.

Test: boot & adb shell dumpsys media.extractor
Bug: 112766843
Change-Id: I1bdf2c41cc5f88c80c2fd20677dce1d58420e947
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 1f8ccb3..81fc4ae 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "MediaExtractorFactory"
 #include <utils/Log.h>
 
+#include <android/dlext.h>
 #include <binder/IPCThreadState.h>
 #include <binder/PermissionCache.h>
 #include <binder/IServiceManager.h>
@@ -36,6 +37,23 @@
 #include <dirent.h>
 #include <dlfcn.h>
 
+// Copied from GraphicsEnv.cpp
+// TODO(b/37049319) Get this from a header once one exists
+extern "C" {
+  android_namespace_t* android_create_namespace(const char* name,
+                                                const char* ld_library_path,
+                                                const char* default_library_path,
+                                                uint64_t type,
+                                                const char* permitted_when_isolated_path,
+                                                android_namespace_t* parent);
+  bool android_link_namespaces(android_namespace_t* from,
+                               android_namespace_t* to,
+                               const char* shared_libs_sonames);
+  enum {
+     ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+  };
+}
+
 namespace android {
 
 // static
@@ -145,6 +163,13 @@
 std::shared_ptr<std::list<sp<ExtractorPlugin>>> MediaExtractorFactory::gPlugins;
 bool MediaExtractorFactory::gPluginsRegistered = false;
 bool MediaExtractorFactory::gIgnoreVersion = false;
+std::string MediaExtractorFactory::gLinkedLibraries;
+
+// static
+void MediaExtractorFactory::SetLinkedLibraries(const std::string& linkedLibraries) {
+    Mutex::Autolock autoLock(gPluginMutex);
+    gLinkedLibraries = linkedLibraries;
+}
 
 // static
 void *MediaExtractorFactory::sniff(
@@ -328,6 +353,62 @@
     }
 }
 
+//static
+void MediaExtractorFactory::RegisterExtractorsInApex(
+        const char *libDirPath, std::list<sp<ExtractorPlugin>> &pluginList) {
+    ALOGV("search for plugins at %s", libDirPath);
+    ALOGV("linked libs %s", gLinkedLibraries.c_str());
+
+    android_namespace_t *extractorNs = android_create_namespace("extractor",
+            nullptr,  // ld_library_path
+            libDirPath,
+            ANDROID_NAMESPACE_TYPE_ISOLATED,
+            nullptr,  // permitted_when_isolated_path
+            nullptr); // parent
+    if (!android_link_namespaces(extractorNs, nullptr, gLinkedLibraries.c_str())) {
+        ALOGE("Failed to link namespace. Failed to load extractor plug-ins in apex.");
+        return;
+    }
+    const android_dlextinfo dlextinfo = {
+        .flags = ANDROID_DLEXT_USE_NAMESPACE,
+        .library_namespace = extractorNs,
+    };
+
+    DIR *libDir = opendir(libDirPath);
+    if (libDir) {
+        struct dirent* libEntry;
+        while ((libEntry = readdir(libDir))) {
+            if (libEntry->d_name[0] == '.') {
+                continue;
+            }
+            String8 libPath = String8(libDirPath) + "/" + libEntry->d_name;
+            if (!libPath.contains("extractor.so")) {
+                continue;
+            }
+            void *libHandle = android_dlopen_ext(
+                    libPath.string(),
+                    RTLD_NOW | RTLD_LOCAL, &dlextinfo);
+            if (libHandle) {
+                GetExtractorDef getDef =
+                    (GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
+                if (getDef) {
+                    ALOGV("registering sniffer for %s", libPath.string());
+                    RegisterExtractor(
+                            new ExtractorPlugin(getDef(), libHandle, libPath), pluginList);
+                } else {
+                    ALOGW("%s does not contain sniffer", libPath.string());
+                    dlclose(libHandle);
+                }
+            } else {
+                ALOGW("couldn't dlopen(%s) %s", libPath.string(), strerror(errno));
+            }
+        }
+        closedir(libDir);
+    } else {
+        ALOGE("couldn't opendir(%s)", libDirPath);
+    }
+}
+
 static bool compareFunc(const sp<ExtractorPlugin>& first, const sp<ExtractorPlugin>& second) {
     return strcmp(first->def.extractor_name, second->def.extractor_name) < 0;
 }
@@ -346,6 +427,12 @@
 
     std::shared_ptr<std::list<sp<ExtractorPlugin>>> newList(new std::list<sp<ExtractorPlugin>>());
 
+    RegisterExtractorsInApex("/apex/com.android.media/lib"
+#ifdef __LP64__
+            "64"
+#endif
+            , *newList);
+
     RegisterExtractorsInSystem("/system/lib"
 #ifdef __LP64__
             "64"
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
index ef9f7ed..84e01f3 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -35,17 +35,21 @@
             const sp<DataSource> &source, const char *mime = NULL);
     static void LoadPlugins(const ::std::string& apkPath);
     static status_t dump(int fd, const Vector<String16>& args);
+    static void SetLinkedLibraries(const std::string& linkedLibraries);
 
 private:
     static Mutex gPluginMutex;
     static std::shared_ptr<std::list<sp<ExtractorPlugin>>> gPlugins;
     static bool gPluginsRegistered;
     static bool gIgnoreVersion;
+    static std::string gLinkedLibraries;
 
     static void RegisterExtractorsInApk(
             const char *apkPath, std::list<sp<ExtractorPlugin>> &pluginList);
     static void RegisterExtractorsInSystem(
             const char *libDirPath, std::list<sp<ExtractorPlugin>> &pluginList);
+    static void RegisterExtractorsInApex(
+            const char *libDirPath, std::list<sp<ExtractorPlugin>> &pluginList);
     static void RegisterExtractor(
             const sp<ExtractorPlugin> &plugin, std::list<sp<ExtractorPlugin>> &pluginList);
 
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index 73c9535..19ce7e9 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -9,6 +9,24 @@
 
 LOCAL_SHARED_LIBRARIES := libmedia libstagefright libbinder libutils liblog
 LOCAL_MODULE:= libmediaextractorservice
+
+sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
+  $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+  $(UBSAN_RUNTIME_LIBRARY) \
+  $(TSAN_RUNTIME_LIBRARY)))
+
+# $(info Sanitizer:  $(sanitizer_runtime_libraries))
+
+ndk_libraries := $(call normalize-path-list,$(addprefix lib,$(addsuffix .so,\
+  $(NDK_PREBUILT_SHARED_LIBRARIES))))
+
+# $(info NDK:  $(ndk_libraries))
+
+LOCAL_CFLAGS += -DLINKED_LIBRARIES='"$(sanitizer_runtime_libraries):$(ndk_libraries)"'
+
+sanitizer_runtime_libraries :=
+ndk_libraries :=
+
 include $(BUILD_SHARED_LIBRARY)
 
 
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index f4d8b43..8b26178 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -29,6 +29,11 @@
 
 namespace android {
 
+MediaExtractorService::MediaExtractorService()
+        : BnMediaExtractorService() {
+    MediaExtractorFactory::SetLinkedLibraries(std::string(LINKED_LIBRARIES));
+}
+
 sp<IMediaExtractor> MediaExtractorService::makeExtractor(
         const sp<IDataSource> &remoteSource, const char *mime) {
     ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime);
diff --git a/services/mediaextractor/MediaExtractorService.h b/services/mediaextractor/MediaExtractorService.h
index 9df3ecd..6007004 100644
--- a/services/mediaextractor/MediaExtractorService.h
+++ b/services/mediaextractor/MediaExtractorService.h
@@ -27,7 +27,7 @@
 {
     friend class BinderService<MediaExtractorService>;    // for MediaExtractorService()
 public:
-    MediaExtractorService() : BnMediaExtractorService() { }
+    MediaExtractorService();
     virtual ~MediaExtractorService() { }
     virtual void onFirstRef() { }