* Copyright (C) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "impl_class.h"
#include <algorithm>
#include "image_log.h"
#include "impl_class_key.h"
#include "json_helper.h"
#include "plugin.h"
#include "plugin_class_base.h"
#include "plugin_common_type.h"
#include "plugin_export.h"
#undef LOG_DOMAIN
#define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
#undef LOG_TAG
#define LOG_TAG "ImplClass"
namespace OHOS {
namespace MultimediaPlugin {
using nlohmann::json;
using std::map;
using std::recursive_mutex;
using std::set;
using std::shared_ptr;
using std::size_t;
using std::string;
using std::weak_ptr;
string ImplClass::emptyString_;
ImplClass::ImplClass() : selfKey_(*this)
{}
uint32_t ImplClass::Register(const weak_ptr<Plugin> &plugin, const json &classInfo)
{
if (state_ != ClassState::CLASS_STATE_UNREGISTER) {
IMAGE_LOGI("repeat registration.");
return ERR_INTERNAL;
}
if (JsonHelper::GetStringValue(classInfo, "className", className_) != SUCCESS) {
IMAGE_LOGE("read className failed.");
return ERR_INVALID_PARAMETER;
}
IMAGE_LOGD("register class: %{public}s.", className_.c_str());
CHECK_ERROR_RETURN_RET_LOG(!AnalysisServices(classInfo), ERR_INVALID_PARAMETER,
"failed to analysis services for class %{public}s.", className_.c_str());
uint32_t result = JsonHelper::GetUint16Value(classInfo, "priority", priority_);
if (result != SUCCESS) {
CHECK_ERROR_RETURN_RET_LOG(result != ERR_NO_TARGET, ERR_INVALID_PARAMETER,
"read priority failed, result: %{public}u.", result);
priority_ = 0;
}
IMAGE_LOGD("get class priority: %{public}u.", priority_);
CHECK_ERROR_RETURN_RET_LOG(!AnalysisMaxInstance(classInfo), ERR_INVALID_PARAMETER,
"failed to analysis maxInstance for class %{public}s.", className_.c_str());
IMAGE_LOGD("get class maxInstance: %{public}u.", maxInstance_);
if (JsonHelper::CheckElementExistence(classInfo, "capabilities") == SUCCESS) {
capability_.SetCapability(classInfo["capabilities"]);
}
pluginRef_ = plugin;
state_ = ClassState::CLASS_STATE_REGISTERED;
return SUCCESS;
}
PluginClassBase *ImplClass::CreateObject(uint32_t &errorCode)
{
errorCode = ERR_INTERNAL;
if (state_ != ClassState::CLASS_STATE_REGISTERED) {
IMAGE_LOGE("failed to create for unregistered, className: %{public}s.", className_.c_str());
return nullptr;
}
auto sharedPlugin = pluginRef_.lock();
if (sharedPlugin == nullptr) {
IMAGE_LOGE("failed to dereference Plugin, className: %{public}s.", className_.c_str());
return nullptr;
}
IMAGE_LOGD("create object, className: %{public}s.", className_.c_str());
std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
if (maxInstance_ != INSTANCE_NO_LIMIT_NUM && instanceNum_ >= maxInstance_) {
IMAGE_LOGE("failed to create for limit, currentNum: %{public}u, maxNum: %{public}u, \
className: %{public}s.", instanceNum_, maxInstance_, className_.c_str());
guard.unlock();
errorCode = ERR_INSTANCE_LIMIT;
return nullptr;
}
if (instanceNum_ == 0) {
if (sharedPlugin->Ref() != SUCCESS) {
return nullptr;
}
}
PluginClassBase *object = DoCreateObject(sharedPlugin);
if (object == nullptr) {
IMAGE_LOGE("create object result null, className: %{public}s.", className_.c_str());
if (instanceNum_ == 0) {
sharedPlugin->DeRef();
}
return nullptr;
}
++instanceNum_;
IMAGE_LOGD("create object success, InstanceNum: %{public}u.", instanceNum_);
guard.unlock();
errorCode = SUCCESS;
return object;
}
weak_ptr<Plugin> ImplClass::GetPluginRef() const
{
if (state_ != ClassState::CLASS_STATE_REGISTERED) {
return weak_ptr<Plugin>();
}
return pluginRef_;
}
const string &ImplClass::GetClassName() const
{
return className_;
}
const string &ImplClass::GetPackageName() const
{
if (state_ != ClassState::CLASS_STATE_REGISTERED) {
IMAGE_LOGE("get package name, className: %{public}s, state error: %{public}d.", className_.c_str(), state_);
return emptyString_;
}
auto sharedPlugin = pluginRef_.lock();
if (sharedPlugin == nullptr) {
IMAGE_LOGE("get package name, failed to dereference Plugin, className: %{public}s.", className_.c_str());
return emptyString_;
}
return sharedPlugin->GetPackageName();
}
bool ImplClass::IsSupport(uint16_t interfaceID) const
{
IMAGE_LOGD("search for support iid: %{public}u, className: %{public}s.", interfaceID, className_.c_str());
for (uint32_t serviceFlag : services_) {
if (MakeIID(serviceFlag) == interfaceID) {
return true;
}
}
IMAGE_LOGD("there is no matching interfaceID");
return false;
}
void ImplClass::OnObjectDestroy()
{
if (state_ != ClassState::CLASS_STATE_REGISTERED) {
IMAGE_LOGE("failed to destroy object because class unregistered, className: %{public}s.", className_.c_str());
return;
}
std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
if (instanceNum_ == 0) {
guard.unlock();
IMAGE_LOGE("destroy object while instanceNum is zero.");
return;
}
--instanceNum_;
auto sharedPlugin = pluginRef_.lock();
if (sharedPlugin == nullptr) {
guard.unlock();
IMAGE_LOGE("destroy object failed because failed to dereference Plugin, className: %{public}s.",
className_.c_str());
return;
}
IMAGE_LOGD("destroy object: className: %{public}s", className_.c_str());
if (instanceNum_ == 0) {
sharedPlugin->DeRef();
}
IMAGE_LOGD("destroy object success, InstanceNum: %{public}u.", instanceNum_);
}
const set<uint32_t> &ImplClass::GetServices() const
{
return services_;
}
bool ImplClass::IsCompatible(const map<string, AttrData> &caps) const
{
return capability_.IsCompatible(caps);
}
const AttrData *ImplClass::GetCapability(const string &key) const
{
if (state_ != ClassState::CLASS_STATE_REGISTERED) {
return nullptr;
}
return capability_.GetCapability(key);
}
const std::map<std::string, AttrData> &ImplClass::GetCapability() const
{
return capability_.GetCapability();
}
bool ImplClass::AnalysisServices(const json &classInfo)
{
size_t serviceNum;
if (JsonHelper::GetArraySize(classInfo, "services", serviceNum) != SUCCESS) {
IMAGE_LOGE("read array size of services failed.");
return false;
}
IMAGE_LOGD("class service num: %{public}zu.", serviceNum);
uint16_t interfaceID;
#ifndef PLUGIN_FLAG_RTTI_ENABLE
uint32_t lastInterfaceID = UINT32_MAX_VALUE;
#endif
uint16_t serviceType;
bool serviceAdded = false;
const json &servicesInfo = classInfo["services"];
for (size_t i = 0; i < serviceNum; i++) {
const json &serviceInfo = servicesInfo[i];
if (JsonHelper::GetUint16Value(serviceInfo, "interfaceID", interfaceID) != SUCCESS) {
IMAGE_LOGE("read interfaceID failed at %{public}zu.", i);
#ifndef PLUGIN_FLAG_RTTI_ENABLE
IMAGE_LOGE("no valid service info or encounter the risk of more than one business \
interface base class.");
return false;
#else
continue;
#endif
}
#ifndef PLUGIN_FLAG_RTTI_ENABLE
bool cond = lastInterfaceID != UINT32_MAX_VALUE && lastInterfaceID != interfaceID;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "more than one business interface base class.");
lastInterfaceID = interfaceID;
#endif
uint32_t result = JsonHelper::GetUint16Value(serviceInfo, "serviceType", serviceType);
if (result != SUCCESS) {
if (result != ERR_NO_TARGET) {
IMAGE_LOGE("read serviceType failed at %{public}zu.", i);
continue;
}
serviceType = 0;
}
IMAGE_LOGD("insert service iid: %{public}hu, serviceType: %{public}hu.", interfaceID, serviceType);
services_.insert(MakeServiceFlag(interfaceID, serviceType));
serviceAdded = true;
}
return serviceAdded;
}
bool ImplClass::AnalysisMaxInstance(const json &classInfo)
{
uint32_t result = JsonHelper::GetUint16Value(classInfo, "maxInstance", maxInstance_);
if (result == SUCCESS) {
IMAGE_LOGD("class maxInstance num: %{public}u.", maxInstance_);
if (maxInstance_ == 0) {
IMAGE_LOGE("class maxInstance num is invalid zero.");
return false;
}
return true;
}
if (result != ERR_NO_TARGET) {
IMAGE_LOGE("read maxInstance failed.");
return false;
}
maxInstance_ = INSTANCE_NO_LIMIT_NUM;
return true;
}
PluginClassBase *CfiFactory(PluginCreateFunc factory, const string &className) __attribute__((no_sanitize("cfi")))
{
return factory(className);
}
PluginClassBase *ImplClass::DoCreateObject(shared_ptr<Plugin> &plugin) __attribute__((no_sanitize("cfi")))
{
PluginCreateFunc factory = plugin->GetCreateFunc();
if (factory == nullptr) {
IMAGE_LOGE("failed to get create func, className: %{public}s.", className_.c_str());
return nullptr;
}
PluginClassBase *pluginBaseObj = CfiFactory(factory, className_);
CHECK_ERROR_RETURN_RET_LOG(pluginBaseObj == nullptr, nullptr,
"create object result null, className: %{public}s.", className_.c_str());
#ifndef PLUGIN_FLAG_RTTI_ENABLE
void *obj = dynamic_cast<void *>(pluginBaseObj);
if (obj == pluginBaseObj) {
IMAGE_LOGE("service interface class is not the first base class. className: %{public}s.", className_.c_str());
delete pluginBaseObj;
return nullptr;
}
#endif
if (pluginBaseObj->SetImplClassKey(selfKey_) != PluginClassBase::MAGIC_CODE) {
IMAGE_LOGE("failed to set key, className: %{public}s.", className_.c_str());
delete pluginBaseObj;
return nullptr;
}
return pluginBaseObj;
}
}
}