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_config_mgr.h"
17
18 #include <cctype>
19 #include <fstream>
20 #include <nlohmann/json.hpp>
21
22 #include "app_module_checker.h"
23 #include "hilog_tag_wrapper.h"
24 #include "hitrace_meter.h"
25
26 namespace OHOS::AbilityRuntime {
27 namespace {
28 constexpr char EXTENSION_BLOCKLIST_FILE_PATH[] = "/system/etc/extension_blocklist_config.json";
29 }
30
Init()31 void ExtensionConfigMgr::Init()
32 {
33 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
34 TAG_LOGD(AAFwkTag::EXT, "Init begin");
35 // clear cached data
36 blocklistConfig_.clear();
37 extensionBlocklist_.clear();
38 extensionEtsBlocklist_.clear();
39
40 // read blocklist from extension_blocklist_config.json
41 std::ifstream inFile;
42 inFile.open(EXTENSION_BLOCKLIST_FILE_PATH, std::ios::in);
43 if (!inFile.is_open()) {
44 TAG_LOGE(AAFwkTag::EXT, "read extension config error");
45 return;
46 }
47 nlohmann::json extensionConfig;
48 inFile >> extensionConfig;
49 if (extensionConfig.is_discarded()) {
50 TAG_LOGE(AAFwkTag::EXT, "extension config json discarded error");
51 inFile.close();
52 return;
53 }
54 if (!extensionConfig.contains(ExtensionConfigItem::ITEM_NAME_BLOCKLIST)) {
55 TAG_LOGE(AAFwkTag::EXT, "extension config file have no blocklist node");
56 inFile.close();
57 return;
58 }
59 auto blackList = extensionConfig.at(ExtensionConfigItem::ITEM_NAME_BLOCKLIST);
60 std::unordered_set<std::string> currentBlockList;
61 for (const auto& item : blackList.items()) {
62 if (!blackList[item.key()].is_array()) {
63 continue;
64 }
65 for (const auto& value : blackList[item.key()]) {
66 currentBlockList.emplace(value.get<std::string>());
67 }
68 blocklistConfig_.emplace(item.key(), std::move(currentBlockList));
69 currentBlockList.clear();
70 }
71 inFile.close();
72 TAG_LOGD(AAFwkTag::EXT, "Init end");
73 }
74
AddBlockListItem(const std::string & name,int32_t type)75 void ExtensionConfigMgr::AddBlockListItem(const std::string& name, int32_t type)
76 {
77 TAG_LOGD(AAFwkTag::EXT, "name: %{public}s, type: %{public}d", name.c_str(), type);
78 auto iter = blocklistConfig_.find(name);
79 if (iter == blocklistConfig_.end()) {
80 TAG_LOGD(AAFwkTag::EXT, "Extension name: %{public}s not exist", name.c_str());
81 return;
82 }
83 extensionBlocklist_.emplace(type, iter->second);
84 }
85
UpdateRuntimeModuleChecker(const std::unique_ptr<AbilityRuntime::Runtime> & runtime)86 void ExtensionConfigMgr::UpdateRuntimeModuleChecker(const std::unique_ptr<AbilityRuntime::Runtime> &runtime)
87 {
88 if (!runtime) {
89 TAG_LOGE(AAFwkTag::EXT, "null runtime");
90 return;
91 }
92 TAG_LOGD(AAFwkTag::EXT, "extensionType_: %{public}d", extensionType_);
93 if (runtime->GetLanguage() == AbilityRuntime::Runtime::Language::ETS) {
94 TAG_LOGD(AAFwkTag::EXT, "ets runtime");
95 GenerateExtensionEtsBlocklists();
96 SetExtensionEtsCheckCallback(runtime);
97 }
98
99 auto moduleChecker = std::make_shared<AppModuleChecker>(extensionType_, extensionBlocklist_);
100 runtime->SetModuleLoadChecker(moduleChecker);
101 extensionBlocklist_.clear();
102 }
103
GenerateExtensionEtsBlocklists()104 void ExtensionConfigMgr::GenerateExtensionEtsBlocklists()
105 {
106 if (!extensionEtsBlocklist_.empty()) {
107 TAG_LOGD(AAFwkTag::EXT, "extension ets block list not empty.");
108 return;
109 }
110 auto iter = extensionBlocklist_.find(extensionType_);
111 if (iter == extensionBlocklist_.end()) {
112 TAG_LOGD(AAFwkTag::EXT, "null extension block, extensionType: %{public}d.", extensionType_);
113 return;
114 }
115 for (const auto& module: iter->second) {
116 extensionEtsBlocklist_.emplace(module);
117 }
118 }
119
GetStringAfterRemovePreFix(const std::string & name)120 std::string ExtensionConfigMgr::GetStringAfterRemovePreFix(const std::string &name)
121 {
122 if (!name.empty() && name[0] == '@') {
123 size_t dotPos = name.find('.');
124 if (dotPos != std::string::npos) {
125 return name.substr(dotPos + 1);
126 }
127 }
128 return name;
129 }
130
CheckEtsModuleLoadable(const std::string & className,const std::string & fileName)131 bool ExtensionConfigMgr::CheckEtsModuleLoadable(const std::string &className, const std::string &fileName)
132 {
133 TAG_LOGD(AAFwkTag::EXT, "extensionType: %{public}d, className is %{public}s, fileName is %{public}s",
134 extensionType_, className.c_str(), fileName.c_str());
135 if (fileName.size() >= className.size() ||
136 className.compare(0, fileName.size(), fileName) != 0 ||
137 ((className.compare(0, fileName.size(), fileName) == 0) && className[fileName.size()] != '.')) {
138 TAG_LOGE(AAFwkTag::EXT, "The fileName:%{public}s and className:%{public}s do not match.",
139 fileName.c_str(), className.c_str());
140 return false;
141 }
142
143 std::string fileNameRemovePrefix = GetStringAfterRemovePreFix(fileName);
144 for (const auto &blockModuleName: extensionEtsBlocklist_) {
145 if (blockModuleName == fileNameRemovePrefix) {
146 TAG_LOGE(AAFwkTag::EXT, "%{public}s is in blocklist.", fileName.c_str());
147 return false;
148 }
149 }
150 TAG_LOGD(AAFwkTag::EXT, "not in blocklist.");
151 return true;
152 }
153
SetExtensionEtsCheckCallback(const std::unique_ptr<AbilityRuntime::Runtime> & runtime)154 void ExtensionConfigMgr::SetExtensionEtsCheckCallback(const std::unique_ptr<AbilityRuntime::Runtime> &runtime)
155 {
156 auto callback = [extensionConfigMgrWeak = weak_from_this()](const std::string &className,
157 const std::string &fileName) -> bool {
158 auto extensionConfigMgr = extensionConfigMgrWeak.lock();
159 if (extensionConfigMgr == nullptr) {
160 TAG_LOGE(AAFwkTag::EXT, "null extensionConfigMgr");
161 return false;
162 }
163 return extensionConfigMgr->CheckEtsModuleLoadable(className, fileName);
164 };
165 runtime->SetExtensionApiCheckCallback(callback);
166 }
167 }