Codec2Client类继承于Codec2ConfigurableClient父类,它可以创建component,创建与component相关联的interface,是Codec2 HIDL的client实现。
创建硬件codec2 Component
- 先通过CreateFromService从ComponentStore service中获取store,然后初始化Codec2Client返回
- 然后设置Codec2ClientInterfaceWrapper为preferred store,client用于初始化Codec2ClientInterfaceWrapper
- 创建c2.qti.avc.decoder
参考CCdoec中的代码,Codec2Client创建一个component需要通过下面三行代码就可以实现:
// CreateFromService从ComponentStore service中获取store,然后初始化Codec2Client返回
std::shared_ptr<Codec2Client> client = Codec2Client::CreateFromService("default");
// 设置Codec2ClientInterfaceWrapper为preferred store,client用于初始化Codec2ClientInterfaceWrapper
SetPreferredCodec2ComponentStore(std::make_shared<Codec2ClientInterfaceWrapper>(client));
// 创建c2.qti.avc.decoder
mComponent = Codec2Client::CreateComponentByName("c2.qti.avc.decoder", mClientListener, &client);
Codec2Client::CreateFromService的细节
std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
const char* name,
bool setAsPreferredCodec2ComponentStore) {
// 获取service idx,然后根据idx创建Codec2Client对象
size_t index = getServiceIndex(name);
if (index == GetServiceNames().size()) {
if (setAsPreferredCodec2ComponentStore) {
LOG(WARNING) << "CreateFromService(" << name
<< ") -- preferred C2ComponentStore not set.";
}
return nullptr;
}
std::shared_ptr<Codec2Client> client = _CreateFromIndex(index);
if (setAsPreferredCodec2ComponentStore) {
SetPreferredCodec2ComponentStore(
std::make_shared<Client2Store>(client));
LOG(INFO) << "CreateFromService(" << name
<< ") -- service set as preferred C2ComponentStore.";
}
return client;
}
service的创建可能像这样:
media/codec2/hidl/services/vendor.cpp
store = new utils::ComponentStore( std::make_shared<StoreImpl>()); if (store == nullptr) { LOG(ERROR) << "Cannot create Codec2's IComponentStore service."; } else { constexpr char const* serviceName = "default"; if (store->registerAsService(serviceName) != OK) { LOG(ERROR) << "Cannot register Codec2's IComponentStore service" " with instance name << \"" << serviceName << "\"."; } else { LOG(DEBUG) << "Codec2's IComponentStore service registered. " "Instance name: \"" << serviceName << "\"."; } }
Codec2Client::_CreateFromIndex
getService去获取ComponentStore server,比如android.hardware.media.c2@1.0::IComponentStore/default
,然后将这个ComponentStore作为baseStore参数传给Codec2Client构造函数初始化Codec2Client,赋值给mBase1_0,所以在Codec2Client中的mBase1_0的mBase1_0就是这个service获得的ComponentStore对象,然后调用其对应的createComponent函数。
std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) {
std::string const& name = GetServiceNames()[index];
LOG(VERBOSE) << "Creating a Codec2 client to service \"" << name << "\"";
sp<Base> baseStore = Base::getService(name);
CHECK(baseStore) << "Codec2 service \"" << name << "\""
" inaccessible for unknown reasons.";
LOG(VERBOSE) << "Client to Codec2 service \"" << name << "\" created";
return std::make_shared<Codec2Client>(baseStore, index);
}
lshal | grep media可以查到ComponentStore server
android.hardware.media.c2@1.0::IComponentStore/default android.hardware.media.c2@1.0::IComponentStore/software android.hardware.media.c2@1.1::IComponentStore/software android.hardware.media.omx@1.0::IOmx/default android.hardware.media.omx@1.0::IOmxStore/default
IComponentStore::getService的代码
::android::sp<IComponentStore> IComponentStore::getService(const std::string &serviceName, const bool getStub) {
return ::android::hardware::details::getServiceInternal<BpHwComponentStore>(serviceName, true, getStub);
}
Codec2Client::CreateComponentByName
调用ForAllServices创建component
std::shared_ptr<Codec2Client::Component>
Codec2Client::CreateComponentByName(
const char* componentName,
const std::shared_ptr<Listener>& listener,
std::shared_ptr<Codec2Client>* owner,
size_t numberOfAttempts) {
std::string key{"create:"};
key.append(componentName);
std::shared_ptr<Component> component;
c2_status_t status = ForAllServices(
key,
numberOfAttempts,
// 细节需要看这个lambda表达式对应的函数在ForAllServices中被调用的地方,在ForAllServices函数中会有传入参数client
[owner, &component, componentName, &listener](const std::shared_ptr<Codec2Client> &client)-> c2_status_t {
c2_status_t status = client->createComponent(componentName, listener, &component);
if (status == C2_OK) {
if (owner) {
*owner = client;
}
} else if (status != C2_NOT_FOUND) {
// LOG ...
}
return status;
});
if (status != C2_OK) {
// LOG ...
}
return component;
}
Codec2Client::ForAllServices
c2_status_t Codec2Client::ForAllServices(
const std::string &key,
size_t numberOfAttempts,
std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)>predicate) {
c2_status_t status = C2_NO_INIT; // no IComponentStores present
// Cache the mapping key -> index of Codec2Client in Cache::List().
static std::mutex key2IndexMutex;
static std::map<std::string, size_t> key2Index;
// By default try all stores. However, try the last known client first. If
// the last known client fails, retry once. We do this by pushing the last
// known client in front of the list of all clients.
std::deque<size_t> indices;
for (size_t index = Cache::List().size(); index > 0; ) {
indices.push_front(--index);
}
bool wasMapped = false;
{
std::scoped_lock lock{key2IndexMutex};
auto it = key2Index.find(key);
if (it != key2Index.end()) {
indices.push_front(it->second);
wasMapped = true;
}
}
for (size_t index : indices) {
Cache& cache = Cache::List()[index];
for (size_t tries = numberOfAttempts; tries > 0; --tries) {
std::shared_ptr<Codec2Client> client{cache.getClient()};
// 这个地方执行CreateComponentByName中的lambda表达式
// 从cache中获取Codec2Client对象,然后调用createComponent函数,更新owner
status = predicate(client);
if (status == C2_OK) {
std::scoped_lock lock{key2IndexMutex};
key2Index[key] = index; // update last known client index
return C2_OK;
} else if (status == C2_TRANSACTION_FAILED) {
cache.invalidate();
continue;
}
if (wasMapped) {
wasMapped = false;
}
break;
}
}
return status; // return the last status from a valid client
}
其中
std::function
定义了一个参数表为(const std::shared_ptr<Codec2Client>&)
,返回类型为c2_status_t的函数,函数名为predicate,后面的花括号紧跟ForAllServices函数体:std::function< c2_status_t(const std::shared_ptr<Codec2Client>&) >predicate
Codec2Client::createComponent
c2_status_t Codec2Client::createComponent(
const C2String& name,
const std::shared_ptr<Codec2Client::Listener>& listener,
std::shared_ptr<Codec2Client::Component>* const component) {
c2_status_t status;
sp<Component::HidlListener> hidlListener = new Component::HidlListener{};
hidlListener->base = listener;
// mBase1_1就是IComponentStore
Return<void> transStatus = mBase1_1 ?
mBase1_1->createComponent_1_1(
name,
hidlListener,
ClientManager::getInstance(),
[&status, component, hidlListener](
Status s,
const sp<IComponent>& c) {
status = static_cast<c2_status_t>(s);
if (status != C2_OK) {
return;
}
*component = std::make_shared<Codec2Client::Component>(c);
hidlListener->component = *component;
}) :
// mBase1_0 就是IComponentStore,调用ComponentStore::createComponent
// service中获得的ComponentStore对象
mBase1_0->createComponent(
name,
hidlListener,
ClientManager::getInstance(),
[&status, component, hidlListener](
Status s,
const sp<hardware::media::c2::V1_0::IComponent>& c) {
status = static_cast<c2_status_t>(s);
if (status != C2_OK) {
return;
}
*component = std::make_shared<Codec2Client::Component>(c);
hidlListener->component = *component;
});
}
ComponentStore::createComponent
frameworks/av/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
frameworks/av/media/codec2/hidl/1.0/utils/ComponentStore.cpp
ComponentStore::createComponent中的mStore是C2ComponentStore类型,所以:hardware component应该也有这么个类似C2PlatformComponentStore : public C2ComponentStore
的类
// Methods from ::android::hardware::media::c2::V1_0::IComponentStore
Return<void> ComponentStore::createComponent(
const hidl_string& name,
const sp<IComponentListener>& listener,
const sp<IClientManager>& pool,
createComponent_cb _hidl_cb) {
sp<Component> component;
std::shared_ptr<C2Component> c2component;
// 这地方又有一个mStore的调用,mStore是C2ComponentStore类型
// 那么具体会是谁呢?只有可能是Client2Store
// 疑问,这个怎么获得vendor的component列表的?
// C2PlatformComponentStore只能获得软解,SetPreferredCodec2ComponentStore的时候,会设置这个store
// 所以:hardware component应该也有这么个类似`C2PlatformComponentStore : public C2ComponentStore`的类
// 然后在注册到HIDL service里面,Client2Client获得store,进而调用mStore->createComponent
// C2ComponentStore::createComponent
Status status = static_cast<Status>(
mStore->createComponent(name, &c2component));
if (status == Status::OK) {
#ifndef __ANDROID_APEX__
c2component = GetFilterWrapper()->maybeWrapComponent(c2component);
#endif
onInterfaceLoaded(c2component->intf());
// 创建Component类型
component = new Component(c2component, listener, this, pool);
if (!component) {
status = Status::CORRUPTED;
} else {
reportComponentBirth(component.get());
if (component->status() != C2_OK) {
status = static_cast<Status>(component->status());
} else {
component->initListener(component);
if (component->status() != C2_OK) {
status = static_cast<Status>(component->status());
}
}
}
}
_hidl_cb(status, component);
return Void();
}
前面函数中createComponent_cb原型如下,comp是IComponent类型:
using createComponent_cb = std::function<void(::android::hardware::media::c2::V1_0::Status status,
const ::android::sp<::android::hardware::media::c2::V1_0::IComponent>& comp)>;
疑问,这个地方把IComponent类型通过make_shared转换为Codec2Client::Component类型?
在前面的
Codec2Client::createComponent
中有:std::shared_ptr<Codec2Client::Component>* const component *component = std::make_shared<Codec2Client::Component>(c);
make_shared会调用Codec2Client::Component的构造函数,Codec2Client::Component构造函数如下,Base就是IComponent,所以前面的
c
作为参数给Codec2Client::Component的构造函数没有问题,这个如果理解成类型转换就不对了,这两个类之间是没有共同基类的。Component(const sp<Base>& base); Component(const sp<Base1_1>& base); Component(const sp<Base1_2>& base);
IComponent继承自IBase
struct IComponent : public ::android::hidl::base::V1_0::IBase
ComponentStore::createComponent_1_1
Return<void> ComponentStore::createComponent_1_1(
const hidl_string& name,
const sp<IComponentListener>& listener,
const sp<IClientManager>& pool,
createComponent_1_1_cb _hidl_cb);
media/codec2/hidl/1.1/utils/ComponentStore.cpp
在ComponentStore中通过C2ComponentStore创建c2component,然后c2component作为参数,创建Component,创建的component又作为_hidl_cb的参数,所以关系是:
ComponentStore::createComponent_1_1 C2ComponentStore::createComponent new Component(c2component, listener, this, pool)
_hidl_cb就是Codec2Client::createComponent
中的拉姆达表达式:
// Methods from ::android::hardware::media::c2::V1_1::IComponentStore
Return<void> ComponentStore::createComponent_1_1(
const hidl_string& name,
const sp<IComponentListener>& listener,
const sp<IClientManager>& pool,
createComponent_1_1_cb _hidl_cb) {
sp<Component> component;
std::shared_ptr<C2Component> c2component;
// C2ComponentStore::createComponent
Status status = static_cast<Status>(
mStore->createComponent(name, &c2component));
if (status == Status::OK) {
onInterfaceLoaded(c2component->intf());
// new hidl Component
component = new Component(c2component, listener, this, pool);
if (!component) {
status = Status::CORRUPTED;
} else {
reportComponentBirth(component.get());
if (component->status() != C2_OK) {
status = static_cast<Status>(component->status());
} else {
component->initListener(component);
if (component->status() != C2_OK) {
status = static_cast<Status>(component->status());
}
}
}
}
_hidl_cb(status, component);
return Void();
}
C2ComponentStore::createComponent
因为C2ComponentStore是作为基类的一个抽象类,SimpleC2Component继承自C2ComponentStore,真正的codec component又继承自SimpleC2Component,所以这部分的实现参考C2PlatformComponentStore::createComponent
就可以,后面的过程就比较清晰。
图中表示的是C2ComponentStore和C2SoftAvcDec以及Codec2Client之间的关系
C2PlatformComponentStore::createComponent
c2_status_t C2PlatformComponentStore::createComponent(
C2String name, std::shared_ptr<C2Component> *const component) {
// This method SHALL return within 100ms.
component->reset();
std::shared_ptr<ComponentModule> module;
c2_status_t res = findComponent(name, &module);
if (res == C2_OK) {
// TODO: get a unique node ID
res = module->createComponent(0, component);
}
return res;
}
C2PlatformComponentStore::findComponent
c2_status_t C2PlatformComponentStore::findComponent(
C2String name, std::shared_ptr<ComponentModule> *module) {
(*module).reset();
// 调用visitComponents
visitComponents();
auto pos = mComponentNameToPath.find(name);
if (pos != mComponentNameToPath.end()) {
return mComponents.at(pos->second).fetchModule(module);
}
return C2_NOT_FOUND;
}
C2PlatformComponentStore::visitComponents
从mComponents的map中取的ComponentLoader,然后逐个去加载:
void C2PlatformComponentStore::visitComponents() {
std::lock_guard<std::mutex> lock(mMutex);
if (mVisited) {
return;
}
// 从mComponents的map中取的ComponentLoader,然后逐个去加载
for (auto &pathAndLoader : mComponents) {
const C2String &path = pathAndLoader.first;
ComponentLoader &loader = pathAndLoader.second;
std::shared_ptr<ComponentModule> module;
// fetchModule
if (loader.fetchModule(&module) == C2_OK) {
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;
}
C2PlatformComponentStore::fetchModule
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) {
localModule = std::make_shared<ComponentModule>();
res = localModule->init(mLibPath);
if (res == C2_OK) {
mModule = localModule;
}
}
*module = localModule;
return res;
}
C2PlatformComponentStore::createComponent
c2_status_t C2PlatformComponentStore::createComponent(
C2String name, std::shared_ptr<C2Component> *const component) {
// This method SHALL return within 100ms.
component->reset();
std::shared_ptr<ComponentModule> module;
c2_status_t res = findComponent(name, &module);
if (res == C2_OK) {
// TODO: get a unique node ID
res = module->createComponent(0, component);
}
return res;
}
调用栈如下,C2PlatformComponentStore::ComponentModule::init
中会dlopen具体的动态库,然后获得符号CreateCodec2Factory
,DestroyCodec2Factory
,调用CreateCodec2Factory创建component factory,然后createComponent创建具体的component。
C2PlatformComponentStore::createComponent
C2PlatformComponentStore::findComponent
C2PlatformComponentStore::ComponentModule::createComponent
总结
所以有总结createComponent的过程,可以得出Codec2Client,codec2.0接口以及HIDL接口之间的关系:
- Codec2Client <==> C2ComponentStore <==> IComponentStore
- Codec2Client::Listener <==> C2Component::Listener <==> IComponentListener
- Codec2Client::Configurable <==> [No equivalent] <==> IConfigurable
- Codec2Client::Interface <==> C2ComponentInterface <==> IComponentInterface
- Codec2Client::Component <==> C2Component <==> IComponent
createComponent的时序图