Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5e1897bb authored by Dongwon Kang's avatar Dongwon Kang
Browse files

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
parent 9321dc86
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -38,11 +38,12 @@ sp<IDataSource> CreateIDataSourceFromDataSource(const sp<DataSource> &source) {
    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 @@ sp<MediaSource> CreateMediaSourceFromIMediaSource(const sp<IMediaSource> &source
    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
+109 −71
Original line number Diff line number Diff line
@@ -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 @@ sp<IMediaExtractor> MediaExtractorFactory::Create(
    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 @@ sp<IMediaExtractor> MediaExtractorFactory::CreateFromFd(
    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 @@ sp<MediaExtractor> MediaExtractorFactory::CreateFromService(
    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 @@ sp<MediaExtractor> MediaExtractorFactory::CreateFromService(
         mime, confidence);

    MediaExtractor *ret = creator(source, meta);
    return ret;
    return CreateIMediaExtractorFromMediaExtractor(ret, plugin);
}

//static
void MediaExtractorFactory::LoadPlugins(const ::std::string& libraryPath) {
    ALOGV("Load plugins from: %s", libraryPath.c_str());
    UpdateExtractors(libraryPath.c_str());
}

Mutex MediaExtractorFactory::gSnifferMutex;
List<MediaExtractor::ExtractorDef> MediaExtractorFactory::gSniffers;
bool MediaExtractorFactory::gSniffersRegistered = false;
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,72 +194,70 @@ MediaExtractor::CreatorFunc MediaExtractorFactory::sniff(
}

// 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::RegisterDefaultSniffers() {
    Mutex::Autolock autoLock(gSnifferMutex);
    if (gSniffersRegistered) {
        return;
    }

    auto registerExtractors = [](const char *libDirPath) -> void {
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;
            String8 libPath = String8(libDirPath) + "/" + libEntry->d_name;
            void *libHandle = dlopen(libPath.string(), RTLD_NOW | RTLD_LOCAL);
            if (libHandle) {
                    MediaExtractor::GetExtractorDef getsniffer =
                MediaExtractor::GetExtractorDef getDef =
                    (MediaExtractor::GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
                    if (getsniffer) {
                if (getDef) {
                    ALOGV("registering sniffer for %s", libPath.string());
                        RegisterSniffer_l(getsniffer());
                    RegisterExtractor(
                            new ExtractorPlugin(getDef(), libHandle, libPath), pluginList);
                } else {
                    ALOGW("%s does not contain sniffer", libPath.string());
                    dlclose(libHandle);
                }
            } else {
                    ALOGW("couldn't dlopen(%s)", libPath.string());
                ALOGW("couldn't dlopen(%s) %s", libPath.string(), strerror(errno));
            }
        }

@@ -243,22 +265,38 @@ void MediaExtractorFactory::RegisterDefaultSniffers() {
    } else {
        ALOGE("couldn't opendir(%s)", libDirPath);
    }
    };
}

    registerExtractors("/system/lib"
// static
void MediaExtractorFactory::UpdateExtractors(const char *newlyInstalledLibPath) {
    Mutex::Autolock autoLock(gPluginMutex);
    if (newlyInstalledLibPath != nullptr) {
        gPluginsRegistered = false;
    }
    if (gPluginsRegistered) {
        return;
    }

    std::shared_ptr<List<sp<ExtractorPlugin>>> newList(new List<sp<ExtractorPlugin>>());

    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
+11 −5
Original line number Diff line number Diff line
@@ -36,8 +36,10 @@ static const char *kExtractorMime = "android.media.mediaextractor.mime";
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(const sp<MediaExtractor> &extractor)
}

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 @@ size_t RemoteMediaExtractor::countTracks() {

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 @@ void RemoteMediaExtractor::release() {
////////////////////////////////////////////////////////////////////////////////

// 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
+9 −5
Original line number Diff line number Diff line
@@ -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 @@ status_t RemoteMediaSource::setStopTimeUs(int64_t stopTimeUs) {
////////////////////////////////////////////////////////////////////////////////

// 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
+4 −2
Original line number Diff line number Diff line
@@ -31,13 +31,15 @@ sp<DataSource> CreateDataSourceFromIDataSource(const sp<IDataSource> &source);
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

Loading