* 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 "plugin_mgr.h"
#include <fstream>
#include <sstream>
#include "directory_ex.h"
#include "image_log.h"
#include "json.hpp"
#include "json_helper.h"
#include "platform_adp.h"
#include "plugin.h"
#include "plugin_metadata.h"
#undef LOG_DOMAIN
#define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
#undef LOG_TAG
#define LOG_TAG "PluginMgr"
namespace OHOS {
namespace MultimediaPlugin {
using nlohmann::json;
using std::ifstream;
using std::istringstream;
using std::size_t;
using std::string;
using std::vector;
using std::weak_ptr;
PlatformAdp &PluginMgr::platformAdp_ = DelayedRefSingleton<PlatformAdp>::GetInstance();
uint32_t PluginMgr::Register(const vector<string> &canonicalPaths)
{
if (canonicalPaths.empty()) {
const vector<string> &metadata = OHOS::MultimediaPlugin::META_DATA;
for (size_t i = 0; i < metadata.size(); i++) {
uint32_t errorCode = RegisterPlugin(metadata[i]);
if (errorCode != SUCCESS) {
return errorCode;
}
}
return SUCCESS;
}
bool pathTraversed = false;
uint32_t errorCode = SUCCESS;
for (const string &path : canonicalPaths) {
uint32_t result = TraverseFiles(path);
if (result == SUCCESS) {
pathTraversed = true;
} else {
if ((errorCode == SUCCESS) || (errorCode == ERR_NO_TARGET)) {
errorCode = result;
}
}
}
if (!pathTraversed) {
return errorCode;
}
return SUCCESS;
}
PluginMgr::PluginMgr()
{}
PluginMgr::~PluginMgr()
{}
uint32_t PluginMgr::TraverseFiles(const string &canonicalPath)
{
bool noTarget = true;
vector<string> strFiles;
GetDirFiles(canonicalPath, strFiles);
if (strFiles.empty()) {
IMAGE_LOGE("failed to get dir files.");
return ERR_GENERAL;
}
string libraryPath;
for (const auto &file : strFiles) {
if (!CheckPluginMetaFile(file, libraryPath)) {
continue;
}
if (RegisterPlugin(file, std::move(libraryPath)) != SUCCESS) {
continue;
}
noTarget = false;
}
if (noTarget) {
IMAGE_LOGW("there is no plugin meta file in path.");
return ERR_NO_TARGET;
}
return SUCCESS;
}
bool PluginMgr::CheckPluginMetaFile(const string &candidateFile, string &libraryPath)
{
#ifdef _WIN32
const string libraryFileSuffix = "dll";
#elif defined _APPLE
const string libraryFileSuffix = "dylib";
#else
const string libraryFileSuffix = "so";
#endif
return CheckPluginMetaFile(candidateFile, libraryPath, libraryFileSuffix);
}
bool PluginMgr::CheckPluginMetaFile(const string &candidateFile, string &libraryPath, const string &libraryFileSuffix)
{
const string meatedataFileSuffix = "pluginmeta";
string fileExt = ExtractFileExt(candidateFile);
if (fileExt != meatedataFileSuffix) {
return false;
}
ifstream metadata(candidateFile);
if (!metadata.is_open()) {
IMAGE_LOGE("failed to open metadata file.");
return false;
}
json root = nlohmann::json::parse(metadata, nullptr, false);
metadata.close();
if (root.is_discarded()) {
IMAGE_LOGE("metadata json parsing failed.");
return false;
}
if (JsonHelper::GetStringValue(root, "libraryPath", libraryPath) != SUCCESS) {
IMAGE_LOGE("read libraryPath failed.");
return false;
}
#if defined(_WIN32) || defined(_APPLE)
libraryPath = TransformFileName(libraryPath);
#endif
fileExt = ExtractFileExt(libraryPath);
if (fileExt != libraryFileSuffix) {
IMAGE_LOGE("invalid library suffix.");
return false;
}
#if !defined(_WIN32) && !defined(_APPLE)
const string dirSeparator = "/";
if (libraryPath.substr(0, 1) != dirSeparator) {
return true;
}
#endif
string realPath;
if (!PathToRealPath(libraryPath, realPath)) {
IMAGE_LOGE("library path to real path error.");
return false;
}
libraryPath = std::move(realPath);
return true;
}
uint32_t PluginMgr::RegisterPlugin(const string &metadataPath, string &&libraryPath)
{
auto iter = plugins_.find(&libraryPath);
if (iter != plugins_.end()) {
IMAGE_LOGD("the libraryPath has already been registered before.");
return ERR_GENERAL;
}
ifstream metadata(metadataPath);
if (!metadata.is_open()) {
IMAGE_LOGE("failed to open metadata file.");
return ERR_GENERAL;
}
auto plugin = std::make_shared<Plugin>();
if (plugin == nullptr) {
IMAGE_LOGE("failed to create Plugin.");
metadata.close();
return ERR_INTERNAL;
}
weak_ptr<Plugin> weakPtr = plugin;
auto regRet = plugin->Register(metadata, std::move(libraryPath), weakPtr);
if (regRet != SUCCESS) {
IMAGE_LOGE("failed to register plugin,ERRNO: %{public}u.", regRet);
metadata.close();
return regRet;
}
metadata.close();
const std::string &key = plugin->GetLibraryPath();
if (key.empty()) {
IMAGE_LOGE("get empty libraryPath.");
return ERR_INTERNAL;
}
auto insertRet = plugins_.insert(PluginMap::value_type(&key, std::move(plugin)));
if (!insertRet.second) {
IMAGE_LOGE("failed to insert Plugin");
return ERR_INTERNAL;
}
return SUCCESS;
}
uint32_t PluginMgr::RegisterPlugin(const string &metadataJson)
{
if (metadataJson.empty() || !nlohmann::json::accept(metadataJson)) {
IMAGE_LOGE("metadataJson not match, %{public}s", metadataJson.c_str());
return ERR_INVALID_PARAMETER;
}
string libraryPath;
json root = nlohmann::json::parse(metadataJson, nullptr, false);
if (root.is_discarded()) {
IMAGE_LOGE("RegisterPlugin parse json failed.");
return ERR_INVALID_PARAMETER;
}
if (JsonHelper::GetStringValue(root, "libraryPath", libraryPath) != SUCCESS) {
IMAGE_LOGE("read libraryPath failed.");
return ERR_INVALID_PARAMETER;
}
auto iter = plugins_.find(&libraryPath);
if (iter != plugins_.end()) {
IMAGE_LOGD("the libraryPath has already been registered before.");
return ERR_GENERAL;
}
istringstream metadata(metadataJson);
if (!metadata) {
IMAGE_LOGE("failed to read metadata.");
return ERR_GENERAL;
}
auto crossPlugin = std::make_shared<Plugin>();
weak_ptr<Plugin> weakPtr = crossPlugin;
auto regRet = crossPlugin->Register(metadata, std::move(libraryPath), weakPtr);
if (regRet != SUCCESS) {
IMAGE_LOGE("failed to register plugin,ERRNO: %{public}u.", regRet);
return regRet;
}
const std::string &key = crossPlugin->GetLibraryPath();
if (key.empty()) {
IMAGE_LOGE("get empty libraryPath.");
return ERR_INTERNAL;
}
auto insertRet = plugins_.insert(PluginMap::value_type(&key, std::move(crossPlugin)));
if (!insertRet.second) {
IMAGE_LOGE("failed to insert Plugin");
return ERR_INTERNAL;
}
return SUCCESS;
}
}
}