1 /*
2  * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "extension_plugin_info.h"
17 
18 #include <dirent.h>
19 #include <dlfcn.h>
20 #include <unistd.h>
21 
22 #include "extension_module_loader.h"
23 #include "file_path_utils.h"
24 #include "hilog_tag_wrapper.h"
25 
26 namespace OHOS {
27 namespace AbilityRuntime {
28 #ifdef APP_USE_ARM64
29 const std::string EXTENSION_LIB = "system/lib64/extensionability";
30 #elif defined(APP_USE_X86_64)
31 const std::string EXTENSION_LIB = "system/lib64/extensionability";
32 #else
33 const std::string EXTENSION_LIB = "system/lib/extensionability";
34 #endif
35 const std::string PATH_SEPARATOR = "/";
36 const std::string LIB_TYPE = ".so";
37 constexpr char EXTENSION_PARAMS_TYPE[] = "type";
38 constexpr char EXTENSION_PARAMS_NAME[] = "name";
39 
ExtensionPluginInfo()40 ExtensionPluginInfo::ExtensionPluginInfo()
41 {
42 }
43 
GetInstance()44 ExtensionPluginInfo& ExtensionPluginInfo::GetInstance()
45 {
46     static ExtensionPluginInfo instance;
47     return instance;
48 }
49 
Preload()50 void ExtensionPluginInfo::Preload()
51 {
52     // scan all extensions in path
53     std::vector<std::string> extensionFiles;
54     ScanExtensions(extensionFiles);
55     ParseExtensions(extensionFiles);
56 }
57 
GetExtensionPlugins()58 std::vector<ExtensionPluginItem> ExtensionPluginInfo::GetExtensionPlugins()
59 {
60     return extensionPlugins_;
61 }
62 
ParseExtensions(const std::vector<std::string> & extensionFiles)63 void ExtensionPluginInfo::ParseExtensions(const std::vector<std::string>& extensionFiles)
64 {
65     if (extensionFiles.empty()) {
66         TAG_LOGE(AAFwkTag::APPKIT, "no extension files.");
67         return;
68     }
69 
70     for (auto& file : extensionFiles) {
71         TAG_LOGD(AAFwkTag::APPKIT, "Begin load extension file:%{public}s", file.c_str());
72         std::map<std::string, std::string> params =
73             AbilityRuntime::ExtensionModuleLoader::GetLoader(file.c_str()).GetParams();
74         if (params.empty()) {
75             TAG_LOGE(AAFwkTag::APPKIT, "no extension params.");
76             continue;
77         }
78         // get extension name and type
79         std::map<std::string, std::string>::iterator it = params.find(EXTENSION_PARAMS_TYPE);
80         if (it == params.end()) {
81             TAG_LOGE(AAFwkTag::APPKIT, "no extension type.");
82             continue;
83         }
84         int32_t type = -1;
85         try {
86             type = static_cast<int32_t>(std::stoi(it->second));
87         } catch (...) {
88             TAG_LOGW(AAFwkTag::APPKIT, "stoi(%{public}s) failed", it->second.c_str());
89             continue;
90         }
91 
92         it = params.find(EXTENSION_PARAMS_NAME);
93         if (it == params.end()) {
94             TAG_LOGE(AAFwkTag::APPKIT, "no extension name.");
95             continue;
96         }
97         std::string extensionName = it->second;
98 
99         ExtensionPluginItem item;
100         item.extensionType = type;
101         item.extensionName = extensionName;
102         item.extensionLibFile = file;
103         auto findTask = [extensionName](ExtensionPluginItem &item) {
104             return item.extensionName == extensionName;
105         };
106         if (find_if(extensionPlugins_.begin(), extensionPlugins_.end(), findTask) != extensionPlugins_.end()) {
107             continue;
108         }
109         extensionPlugins_.emplace_back(item);
110         TAG_LOGD(
111             AAFwkTag::APPKIT, "Success load extension type: %{public}d, name:%{public}s", type, extensionName.c_str());
112     }
113 }
114 
ScanExtensions(std::vector<std::string> & files)115 bool ExtensionPluginInfo::ScanExtensions(std::vector<std::string>& files)
116 {
117     std::string dirPath = EXTENSION_LIB;
118     DIR *dirp = opendir(dirPath.c_str());
119     if (dirp == nullptr) {
120         TAG_LOGE(AAFwkTag::APPKIT, "ScanDir open dir:%{public}s fail", dirPath.c_str());
121         return false;
122     }
123 
124     struct dirent *dirf = nullptr;
125     for (;;) {
126         dirf = readdir(dirp);
127         if (dirf == nullptr) {
128             break;
129         }
130 
131         std::string currentName(dirf->d_name);
132         if (currentName.compare(".") == 0 || currentName.compare("..") == 0) {
133             continue;
134         }
135 
136         if (CheckFileType(currentName, LIB_TYPE)) {
137             files.emplace_back(dirPath + PATH_SEPARATOR + currentName);
138         }
139     }
140 
141     if (closedir(dirp) == -1) {
142         TAG_LOGW(AAFwkTag::APPKIT, "close dir fail");
143     }
144     return true;
145 }
146 
CheckFileType(const std::string & fileName,const std::string & extensionName)147 bool ExtensionPluginInfo::CheckFileType(const std::string& fileName, const std::string& extensionName)
148 {
149     TAG_LOGD(AAFwkTag::APPKIT, "CheckFileType path is %{public}s, support suffix is %{public}s",
150         fileName.c_str(),
151         extensionName.c_str());
152 
153     if (fileName.empty()) {
154         TAG_LOGE(AAFwkTag::APPKIT, "the file name is empty.");
155         return false;
156     }
157 
158     auto position = fileName.rfind('.');
159     if (position == std::string::npos) {
160         TAG_LOGW(AAFwkTag::APPKIT, "filename no extension name.");
161         return false;
162     }
163 
164     std::string suffixStr = fileName.substr(position);
165     return LowerStr(suffixStr) == extensionName;
166 }
167 }
168 }
169