/* * 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 #include #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::GetInstance(); uint32_t PluginMgr::Register(const vector &canonicalPaths) { if (canonicalPaths.empty()) { const vector &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 { // no target is not a critical error type, giving priority to more serious errors. if ((errorCode == SUCCESS) || (errorCode == ERR_NO_TARGET)) { errorCode = result; } } } if (!pathTraversed) { return errorCode; } return SUCCESS; } // ------------------------------- private method ------------------------------- PluginMgr::PluginMgr() {} PluginMgr::~PluginMgr() {} uint32_t PluginMgr::TraverseFiles(const string &canonicalPath) { bool noTarget = true; vector 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) { // not a plugin metadata file, quietly skip this item. 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); // no callback, no exceptions 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) { // relative path to absolute path. // just keep original library name 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()) { // already registered before, just skip it. 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(); if (plugin == nullptr) { IMAGE_LOGE("failed to create Plugin."); metadata.close(); return ERR_INTERNAL; } weak_ptr 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); // no callback, no exceptions 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()) { // already registered before, just skip it. 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(); weak_ptr 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; } } // namespace MultimediaPlugin } // namespace OHOS