Android Codec2 CCodec(八)SW组件创建过程分析

在这一篇文章中,我们将先了解SW ComponentStore HIDL层的Codec2组件创建过程,然后了解组件实现架构。

1、C2PlatformComponentStore::createComponent

ComponentStore的HIDL接口会调用C2ComponentStore的createComponent方法:

c2_status_t C2PlatformComponentStore::createComponent(
        C2String name, std::shared_ptr<C2Component> *const component) {
    component->reset();
    // 查找ComponentModule
    std::shared_ptr<ComponentModule> module;
    c2_status_t res = findComponent(name, &module);
    if (res == C2_OK) {
        // 创建C2Component实例
        res = module->createComponent(0, component);
    }
    return res;
}

createComponent的传入参数为组件名称,传出参数为创建出的C2Component对象:

  1. 根据传入的组件名查找对应的ComponentModule;
  2. 调用ComponentModule的createComponent方法创建组件。

ComponentModule是ComponentLoader的一个成员,在Codec2服务启动一文,我们看到C2PlatformComponentStore的构造函数中会为每一个组件都添加一个ComponentLoader,此时ComponentModule还没有被初始化。

c2_status_t C2PlatformComponentStore::findComponent(
        C2String name, std::shared_ptr<ComponentModule> *module) {
    (*module).reset();
    // 1.
    visitComponents();
    // 2.
    auto pos = mComponentNameToPath.find(name);
    if (pos != mComponentNameToPath.end()) {
        // 3.
        return mComponents.at(pos->second).fetchModule(module);
    }
    return C2_NOT_FOUND;
}

findComponent的工作如下:

  1. 首先调用visitComponents打开lib,加载函数指针,获取组件信息;
  2. 从mComponentNameToPath查找是否有匹配的组件名称;
  3. 调用ComponentLoader的fetchModule方法。

C2PlatformComponentStore使用visitComponents来打开lib,将handle以及获取到的函数指针存储到ComponentModule中,使用mVisited来保证lib信息的加载只会执行一次,visitComponents会遍历所有的lib,一次性载入所有组件的信息。但是要注意的是,visitComponents只会调用一次不代表ComponentModule存储的内容会一直存在,组件使用释放后,ComponentModule中的信息就会清空,直到下次使用再重新加载到ComponentModule中。

void C2PlatformComponentStore::visitComponents() {
    std::lock_guard<std::mutex> lock(mMutex);
    if (mVisited) {
        return;
    }
    for (auto &pathAndLoader : mComponents) {
        const C2String &path = pathAndLoader.first;
        ComponentLoader &loader = pathAndLoader.second;
        std::shared_ptr<ComponentModule> module;
		// 初始化ComponentModule
        if (loader.fetchModule(&module) == C2_OK) {
			// 获取traits
            std::shared_ptr<const C2Component::Traits> traits = module->getTraits();
            if (traits) {
                mComponentList.push_back(traits);
                mComponentNameToPath.emplace(traits->name, path);
                for (const C2String &alias : traits->aliases) {
                    mComponentNameToPath.emplace(alias, path);
                }
            }
        }
    }
    mVisited = true;
}

c2_status_t fetchModule(std::shared_ptr<ComponentModule> *module) {
    c2_status_t res = C2_OK;
    std::lock_guard<std::mutex> lock(mMutex);
    std::shared_ptr<ComponentModule> localModule = mModule.lock();
    if (localModule == nullptr) {
        // 实例化ComponentModule
        localModule = std::make_shared<ComponentModule>();
        // 初始化ComponentModule
        res = localModule->init(mLibPath);
        if (res == C2_OK) {
            mModule = localModule;
        }
    }
    *module = localModule;
    return res;
}

最终调用到ComponentModule的init方法来载入组件信息,传入参数为lib名:

c2_status_t C2PlatformComponentStore::ComponentModule::init(
        std::string libPath) {
	// 1. 打开lib,获取函数指针
    if(!createFactory) {
        mLibHandle = dlopen(libPath.c_str(), RTLD_NOW|RTLD_NODELETE);
        LOG_ALWAYS_FATAL_IF(mLibHandle == nullptr,
                "could not dlopen %s: %s", libPath.c_str(), dlerror());

        createFactory =
            (C2ComponentFactory::CreateCodec2FactoryFunc)dlsym(mLibHandle, "CreateCodec2Factory");
        LOG_ALWAYS_FATAL_IF(createFactory == nullptr,
                "createFactory is null in %s", libPath.c_str());

        destroyFactory =
            (C2ComponentFactory::DestroyCodec2FactoryFunc)dlsym(mLibHandle, "DestroyCodec2Factory");
        LOG_ALWAYS_FATAL_IF(destroyFactory == nullptr,
                "destroyFactory is null in %s", libPath.c_str());
    }
	// 2. 创建C2ComponentFactory
    mComponentFactory = createFactory();
    if (mComponentFactory == nullptr) {
        ALOGD("could not create factory in %s", libPath.c_str());
        mInit = C2_NO_MEMORY;
    } else {
        mInit = C2_OK;
    }

    if (mInit != C2_OK) {
        return mInit;
    }
	// 3. 创建Interface
    std::shared_ptr<C2ComponentInterface> intf;
    c2_status_t res = createInterface(0, &intf);
    if (res != C2_OK) {
        ALOGD("failed to create interface: %d", res);
        return mInit;
    }
	// 4. 获取组件traits
    std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
    if (traits) {
        if (!C2InterfaceUtils::FillTraitsFromInterface(traits.get(), intf)) {
            ALOGD("Failed to fill traits from interface");
            return mInit;
        }

        // TODO: get this properly from the store during emplace
        switch (traits->domain) {
        case C2Component::DOMAIN_AUDIO:
            traits->rank = 8;
            break;
        default:
            traits->rank = 512;
        }
    }
    mTraits = traits;

    return mInit;
}

ComponentModule和OMXStore的内部实现类似,都是用的插件式编程。每个组件都要定义一个CreateCodec2Factory和DestroyCodec2Factory方法,ComponentModule使用dlopen打开lib后,再用dlsym获取到组件定义的方法,接着使用拿到的CreateCodec2Factory创建一个C2ComponentFactory对象,最后就能够使用C2ComponentFactory创建组件实例,或者创建接口实例了。

请添加图片描述

lib信息获取完成后,会调用C2ComponentFactory实例的createInterface方法,获取组件Traits。在init方法中偷偷修改了traits的rank,如果是audio组件,则修改rank为8。如果是video组件,修改rank为512。

2、Traits

3、ComponentStore::createComponent

关注公众号《青山渺渺》阅读完整内容

请添加图片描述

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青山渺渺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值