Keep the in-use extractor plugins when updating.
To track usage of extractors and close the so handle when they are
destroied, MediaExtractorPlugin/RefBase class is introduced.
Test: play MP4 file. install and uninstall media update apk.
Bug: 67908547
Change-Id: I24926f943bc7247627e62d38edafd13d9c305a51
diff --git a/media/libstagefright/InterfaceUtils.cpp b/media/libstagefright/InterfaceUtils.cpp
index cf9fdf8..f174ba4 100644
--- a/media/libstagefright/InterfaceUtils.cpp
+++ b/media/libstagefright/InterfaceUtils.cpp
@@ -38,11 +38,12 @@
return RemoteDataSource::wrap(source);
}
-sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(const sp<MediaExtractor> &extractor) {
+sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(
+ const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin) {
if (extractor == nullptr) {
return nullptr;
}
- return RemoteMediaExtractor::wrap(extractor);
+ return RemoteMediaExtractor::wrap(extractor, plugin);
}
sp<MediaSource> CreateMediaSourceFromIMediaSource(const sp<IMediaSource> &source) {
@@ -52,11 +53,12 @@
return new CallbackMediaSource(source);
}
-sp<IMediaSource> CreateIMediaSourceFromMediaSource(const sp<MediaSource> &source) {
+sp<IMediaSource> CreateIMediaSourceFromMediaSource(
+ const sp<MediaSource> &source, const sp<RefBase> &plugin) {
if (source == nullptr) {
return nullptr;
}
- return RemoteMediaSource::wrap(source);
+ return RemoteMediaSource::wrap(source, plugin);
}
} // namespace android
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 8a90e93..4ca2d0d 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -15,7 +15,7 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaExtractor"
+#define LOG_TAG "MediaExtractorFactory"
#include <utils/Log.h>
#include <binder/IServiceManager.h>
@@ -45,8 +45,7 @@
if (!property_get_bool("media.stagefright.extractremote", true)) {
// local extractor
ALOGW("creating media extractor in calling process");
- sp<MediaExtractor> extractor = CreateFromService(source, mime);
- return CreateIMediaExtractorFromMediaExtractor(extractor);
+ return CreateFromService(source, mime);
} else {
// remote extractor
ALOGV("get service manager");
@@ -103,11 +102,11 @@
return Create(*out, mime);
}
-sp<MediaExtractor> MediaExtractorFactory::CreateFromService(
+sp<IMediaExtractor> MediaExtractorFactory::CreateFromService(
const sp<DataSource> &source, const char *mime) {
- ALOGV("MediaExtractorFactory::%s %s", __func__, mime);
- RegisterDefaultSniffers();
+ ALOGV("MediaExtractorFactory::CreateFromService %s", mime);
+ UpdateExtractors(nullptr);
// initialize source decryption if needed
source->DrmInitialization(nullptr /* mime */);
@@ -117,7 +116,8 @@
MediaExtractor::CreatorFunc creator = NULL;
String8 tmp;
float confidence;
- creator = sniff(source, &tmp, &confidence, &meta);
+ sp<ExtractorPlugin> plugin;
+ creator = sniff(source, &tmp, &confidence, &meta, plugin);
if (!creator) {
ALOGV("FAILED to autodetect media content.");
return NULL;
@@ -128,39 +128,63 @@
mime, confidence);
MediaExtractor *ret = creator(source, meta);
- return ret;
+ return CreateIMediaExtractorFromMediaExtractor(ret, plugin);
}
-Mutex MediaExtractorFactory::gSnifferMutex;
-List<MediaExtractor::ExtractorDef> MediaExtractorFactory::gSniffers;
-bool MediaExtractorFactory::gSniffersRegistered = false;
+//static
+void MediaExtractorFactory::LoadPlugins(const ::std::string& libraryPath) {
+ ALOGV("Load plugins from: %s", libraryPath.c_str());
+ UpdateExtractors(libraryPath.c_str());
+}
+
+struct ExtractorPlugin : public RefBase {
+ MediaExtractor::ExtractorDef def;
+ void *libHandle;
+ String8 libPath;
+
+ ExtractorPlugin(MediaExtractor::ExtractorDef definition, void *handle, String8 &path)
+ : def(definition), libHandle(handle), libPath(path) { }
+ ~ExtractorPlugin() {
+ if (libHandle != nullptr) {
+ ALOGV("closing handle for %s %d", libPath.c_str(), def.extractor_version);
+ dlclose(libHandle);
+ }
+ }
+};
+
+Mutex MediaExtractorFactory::gPluginMutex;
+std::shared_ptr<List<sp<ExtractorPlugin>>> MediaExtractorFactory::gPlugins;
+bool MediaExtractorFactory::gPluginsRegistered = false;
// static
MediaExtractor::CreatorFunc MediaExtractorFactory::sniff(
- const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) {
+ const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta,
+ sp<ExtractorPlugin> &plugin) {
*mimeType = "";
*confidence = 0.0f;
meta->clear();
+ std::shared_ptr<List<sp<ExtractorPlugin>>> plugins;
{
- Mutex::Autolock autoLock(gSnifferMutex);
- if (!gSniffersRegistered) {
+ Mutex::Autolock autoLock(gPluginMutex);
+ if (!gPluginsRegistered) {
return NULL;
}
+ plugins = gPlugins;
}
MediaExtractor::CreatorFunc curCreator = NULL;
MediaExtractor::CreatorFunc bestCreator = NULL;
- for (List<MediaExtractor::ExtractorDef>::iterator it = gSniffers.begin();
- it != gSniffers.end(); ++it) {
+ for (auto it = plugins->begin(); it != plugins->end(); ++it) {
String8 newMimeType;
float newConfidence;
sp<AMessage> newMeta;
- if ((curCreator = (*it).sniff(source, &newMimeType, &newConfidence, &newMeta))) {
+ if ((curCreator = (*it)->def.sniff(source, &newMimeType, &newConfidence, &newMeta))) {
if (newConfidence > *confidence) {
*mimeType = newMimeType;
*confidence = newConfidence;
*meta = newMeta;
+ plugin = *it;
bestCreator = curCreator;
}
}
@@ -170,95 +194,109 @@
}
// static
-void MediaExtractorFactory::RegisterSniffer_l(const MediaExtractor::ExtractorDef &def) {
+void MediaExtractorFactory::RegisterExtractor(const sp<ExtractorPlugin> &plugin,
+ List<sp<ExtractorPlugin>> &pluginList) {
// sanity check check struct version, uuid, name
- if (def.def_version == 0 || def.def_version > MediaExtractor::EXTRACTORDEF_VERSION) {
- ALOGE("don't understand extractor format %u, ignoring.", def.def_version);
+ if (plugin->def.def_version == 0
+ || plugin->def.def_version > MediaExtractor::EXTRACTORDEF_VERSION) {
+ ALOGE("don't understand extractor format %u, ignoring.", plugin->def.def_version);
return;
}
- if (memcmp(&def.extractor_uuid, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) {
+ if (memcmp(&plugin->def.extractor_uuid, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) {
ALOGE("invalid UUID, ignoring");
return;
}
- if (def.extractor_name == NULL || strlen(def.extractor_name) == 0) {
+ if (plugin->def.extractor_name == NULL || strlen(plugin->def.extractor_name) == 0) {
ALOGE("extractors should have a name, ignoring");
return;
}
- for (List<MediaExtractor::ExtractorDef>::iterator it = gSniffers.begin();
- it != gSniffers.end(); ++it) {
- if (memcmp(&((*it).extractor_uuid), &def.extractor_uuid, 16) == 0) {
+ for (auto it = pluginList.begin(); it != pluginList.end(); ++it) {
+ if (memcmp(&((*it)->def.extractor_uuid), &plugin->def.extractor_uuid, 16) == 0) {
// there's already an extractor with the same uuid
- if ((*it).extractor_version < def.extractor_version) {
+ if ((*it)->def.extractor_version < plugin->def.extractor_version) {
// this one is newer, replace the old one
ALOGW("replacing extractor '%s' version %u with version %u",
- def.extractor_name,
- (*it).extractor_version,
- def.extractor_version);
- gSniffers.erase(it);
+ plugin->def.extractor_name,
+ (*it)->def.extractor_version,
+ plugin->def.extractor_version);
+ pluginList.erase(it);
break;
} else {
ALOGW("ignoring extractor '%s' version %u in favor of version %u",
- def.extractor_name,
- def.extractor_version,
- (*it).extractor_version);
+ plugin->def.extractor_name,
+ plugin->def.extractor_version,
+ (*it)->def.extractor_version);
return;
}
}
}
- ALOGV("registering extractor for %s", def.extractor_name);
- gSniffers.push_back(def);
+ ALOGV("registering extractor for %s", plugin->def.extractor_name);
+ pluginList.push_back(plugin);
+}
+
+//static
+void MediaExtractorFactory::RegisterExtractors(
+ const char *libDirPath, List<sp<ExtractorPlugin>> &pluginList) {
+ ALOGV("search for plugins at %s", libDirPath);
+ DIR *libDir = opendir(libDirPath);
+ if (libDir) {
+ struct dirent* libEntry;
+ while ((libEntry = readdir(libDir))) {
+ String8 libPath = String8(libDirPath) + "/" + libEntry->d_name;
+ void *libHandle = dlopen(libPath.string(), RTLD_NOW | RTLD_LOCAL);
+ if (libHandle) {
+ MediaExtractor::GetExtractorDef getDef =
+ (MediaExtractor::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
-void MediaExtractorFactory::RegisterDefaultSniffers() {
- Mutex::Autolock autoLock(gSnifferMutex);
- if (gSniffersRegistered) {
+void MediaExtractorFactory::UpdateExtractors(const char *newlyInstalledLibPath) {
+ Mutex::Autolock autoLock(gPluginMutex);
+ if (newlyInstalledLibPath != nullptr) {
+ gPluginsRegistered = false;
+ }
+ if (gPluginsRegistered) {
return;
}
- auto registerExtractors = [](const char *libDirPath) -> void {
- DIR *libDir = opendir(libDirPath);
- if (libDir) {
- struct dirent* libEntry;
- while ((libEntry = readdir(libDir))) {
- String8 libPath = String8(libDirPath) + libEntry->d_name;
- void *libHandle = dlopen(libPath.string(), RTLD_NOW | RTLD_LOCAL);
- if (libHandle) {
- MediaExtractor::GetExtractorDef getsniffer =
- (MediaExtractor::GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
- if (getsniffer) {
- ALOGV("registering sniffer for %s", libPath.string());
- RegisterSniffer_l(getsniffer());
- } else {
- ALOGW("%s does not contain sniffer", libPath.string());
- dlclose(libHandle);
- }
- } else {
- ALOGW("couldn't dlopen(%s)", libPath.string());
- }
- }
+ std::shared_ptr<List<sp<ExtractorPlugin>>> newList(new List<sp<ExtractorPlugin>>());
- closedir(libDir);
- } else {
- ALOGE("couldn't opendir(%s)", libDirPath);
- }
- };
-
- registerExtractors("/system/lib"
+ RegisterExtractors("/system/lib"
#ifdef __LP64__
"64"
#endif
- "/extractors/");
+ "/extractors", *newList);
- registerExtractors("/vendor/lib"
+ RegisterExtractors("/vendor/lib"
#ifdef __LP64__
"64"
#endif
- "/extractors/");
+ "/extractors", *newList);
- gSniffersRegistered = true;
+ if (newlyInstalledLibPath != nullptr) {
+ RegisterExtractors(newlyInstalledLibPath, *newList);
+ }
+
+ gPlugins = newList;
+ gPluginsRegistered = true;
}
-
} // namespace android
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
index 2a16e16..12654d9 100644
--- a/media/libstagefright/RemoteMediaExtractor.cpp
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -36,8 +36,10 @@
static const char *kExtractorTracks = "android.media.mediaextractor.ntrk";
static const char *kExtractorFormat = "android.media.mediaextractor.fmt";
-RemoteMediaExtractor::RemoteMediaExtractor(const sp<MediaExtractor> &extractor)
- :mExtractor(extractor) {
+RemoteMediaExtractor::RemoteMediaExtractor(
+ const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin)
+ :mExtractor(extractor),
+ mExtractorPlugin(plugin) {
mAnalyticsItem = nullptr;
if (MEDIA_LOG) {
@@ -65,6 +67,8 @@
}
RemoteMediaExtractor::~RemoteMediaExtractor() {
+ mExtractor = nullptr;
+ mExtractorPlugin = nullptr;
// log the current record, provided it has some information worth recording
if (MEDIA_LOG) {
if (mAnalyticsItem != nullptr) {
@@ -86,7 +90,8 @@
sp<IMediaSource> RemoteMediaExtractor::getTrack(size_t index) {
sp<MediaSource> source = mExtractor->getTrack(index);
- return (source.get() == nullptr) ? nullptr : CreateIMediaSourceFromMediaSource(source);
+ return (source.get() == nullptr)
+ ? nullptr : CreateIMediaSourceFromMediaSource(source, mExtractorPlugin);
}
sp<MetaData> RemoteMediaExtractor::getTrackMetaData(size_t index, uint32_t flags) {
@@ -133,11 +138,12 @@
////////////////////////////////////////////////////////////////////////////////
// static
-sp<IMediaExtractor> RemoteMediaExtractor::wrap(const sp<MediaExtractor> &extractor) {
+sp<IMediaExtractor> RemoteMediaExtractor::wrap(
+ const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin) {
if (extractor.get() == nullptr) {
return nullptr;
}
- return new RemoteMediaExtractor(extractor);
+ return new RemoteMediaExtractor(extractor, plugin);
}
} // namespace android
diff --git a/media/libstagefright/RemoteMediaSource.cpp b/media/libstagefright/RemoteMediaSource.cpp
index 866d163..d97329c 100644
--- a/media/libstagefright/RemoteMediaSource.cpp
+++ b/media/libstagefright/RemoteMediaSource.cpp
@@ -19,10 +19,14 @@
namespace android {
-RemoteMediaSource::RemoteMediaSource(const sp<MediaSource> &source)
- :mSource(source) {}
+RemoteMediaSource::RemoteMediaSource(const sp<MediaSource> &source, const sp<RefBase> &plugin)
+ :mSource(source),
+ mExtractorPlugin(plugin) {}
-RemoteMediaSource::~RemoteMediaSource() {}
+RemoteMediaSource::~RemoteMediaSource() {
+ mSource = nullptr;
+ mExtractorPlugin = nullptr;
+}
status_t RemoteMediaSource::start(MetaData *params) {
return mSource->start(params);
@@ -51,11 +55,11 @@
////////////////////////////////////////////////////////////////////////////////
// static
-sp<IMediaSource> RemoteMediaSource::wrap(const sp<MediaSource> &source) {
+sp<IMediaSource> RemoteMediaSource::wrap(const sp<MediaSource> &source, const sp<RefBase> &plugin) {
if (source.get() == nullptr) {
return nullptr;
}
- return new RemoteMediaSource(source);
+ return new RemoteMediaSource(source, plugin);
}
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/InterfaceUtils.h b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
index 783f109..224c1f1 100644
--- a/media/libstagefright/include/media/stagefright/InterfaceUtils.h
+++ b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
@@ -31,13 +31,15 @@
sp<IDataSource> CreateIDataSourceFromDataSource(const sp<DataSource> &source);
// Creates an IMediaExtractor wrapper to the given MediaExtractor.
-sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(const sp<MediaExtractor> &extractor);
+sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(
+ const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin);
// Creates a MediaSource which wraps the given IMediaSource object.
sp<MediaSource> CreateMediaSourceFromIMediaSource(const sp<IMediaSource> &source);
// Creates an IMediaSource wrapper to the given MediaSource.
-sp<IMediaSource> CreateIMediaSourceFromMediaSource(const sp<MediaSource> &source);
+sp<IMediaSource> CreateIMediaSourceFromMediaSource(
+ const sp<MediaSource> &source, const sp<RefBase> &plugin);
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
index f216ff8..0a9514a 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -26,6 +26,7 @@
namespace android {
class DataSource;
+struct ExtractorPlugin;
class MediaExtractorFactory {
public:
@@ -37,20 +38,24 @@
// will be alsp returned with |out|.
static sp<IMediaExtractor> CreateFromFd(
int fd, int64_t offset, int64_t length, const char *mime, sp<DataSource> *out);
- static sp<MediaExtractor> CreateFromService(
+ static sp<IMediaExtractor> CreateFromService(
const sp<DataSource> &source, const char *mime = NULL);
private:
- static Mutex gSnifferMutex;
- static List<MediaExtractor::ExtractorDef> gSniffers;
- static bool gSniffersRegistered;
+ static Mutex gPluginMutex;
+ static std::shared_ptr<List<sp<ExtractorPlugin>>> gPlugins;
+ static bool gPluginsRegistered;
- static void RegisterSniffer_l(const MediaExtractor::ExtractorDef &def);
+ static void RegisterExtractors(
+ const char *libDirPath, List<sp<ExtractorPlugin>> &pluginList);
+ static void RegisterExtractor(
+ const sp<ExtractorPlugin> &plugin, List<sp<ExtractorPlugin>> &pluginList);
static MediaExtractor::CreatorFunc sniff(const sp<DataSource> &source,
- String8 *mimeType, float *confidence, sp<AMessage> *meta);
+ String8 *mimeType, float *confidence, sp<AMessage> *meta,
+ sp<ExtractorPlugin> &plugin);
- static void RegisterDefaultSniffers();
+ static void UpdateExtractors(const char *newlyInstalledLibPath);
};
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
index 98b8b4d..2bd71ee 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
@@ -27,7 +27,7 @@
// IMediaExtractor wrapper to the MediaExtractor.
class RemoteMediaExtractor : public BnMediaExtractor {
public:
- static sp<IMediaExtractor> wrap(const sp<MediaExtractor> &extractor);
+ static sp<IMediaExtractor> wrap(const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin);
virtual ~RemoteMediaExtractor();
virtual size_t countTracks();
@@ -44,10 +44,11 @@
private:
sp<MediaExtractor> mExtractor;
+ sp<RefBase> mExtractorPlugin;
MediaAnalyticsItem *mAnalyticsItem;
- explicit RemoteMediaExtractor(const sp<MediaExtractor> &extractor);
+ explicit RemoteMediaExtractor(const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin);
DISALLOW_EVIL_CONSTRUCTORS(RemoteMediaExtractor);
};
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
index 0a446a5..cb222cc 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
@@ -26,7 +26,7 @@
// IMediaSrouce wrapper to the MediaSource.
class RemoteMediaSource : public BnMediaSource {
public:
- static sp<IMediaSource> wrap(const sp<MediaSource> &source);
+ static sp<IMediaSource> wrap(const sp<MediaSource> &source, const sp<RefBase> &plugin);
virtual ~RemoteMediaSource();
virtual status_t start(MetaData *params = NULL);
virtual status_t stop();
@@ -39,8 +39,9 @@
private:
sp<MediaSource> mSource;
+ sp<RefBase> mExtractorPlugin;
- explicit RemoteMediaSource(const sp<MediaSource> &source);
+ explicit RemoteMediaSource(const sp<MediaSource> &source, const sp<RefBase> &plugin);
DISALLOW_EVIL_CONSTRUCTORS(RemoteMediaSource);
};
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index f09d7cf..0dc1fce 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -36,16 +36,15 @@
sp<DataSource> localSource = CreateDataSourceFromIDataSource(remoteSource);
- sp<MediaExtractor> extractor = MediaExtractorFactory::CreateFromService(localSource, mime);
+ sp<IMediaExtractor> extractor = MediaExtractorFactory::CreateFromService(localSource, mime);
ALOGV("extractor service created %p (%s)",
extractor.get(),
extractor == nullptr ? "" : extractor->name());
if (extractor != nullptr) {
- sp<IMediaExtractor> ret = CreateIMediaExtractorFromMediaExtractor(extractor);
- registerMediaExtractor(ret, localSource, mime);
- return ret;
+ registerMediaExtractor(extractor, localSource, mime);
+ return extractor;
}
return nullptr;
}