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.h"
17 
18 #include <fstream>
19 
20 #include "config_policy_utils.h"
21 #include "hilog_tag_wrapper.h"
22 
23 namespace OHOS {
24 namespace AAFwk {
25 namespace {
26 constexpr const char* EXTENSION_CONFIG_DEFAULT_PATH = "/system/etc/ams_extension_config.json";
27 constexpr const char* EXTENSION_CONFIG_FILE_PATH = "/etc/ams_extension_config.json";
28 
29 constexpr const char* EXTENSION_CONFIG_NAME = "ams_extension_config";
30 constexpr const char* EXTENSION_TYPE_NAME = "extension_type_name";
31 constexpr const char* EXTENSION_AUTO_DISCONNECT_TIME = "auto_disconnect_time";
32 
33 constexpr const char* EXTENSION_THIRD_PARTY_APP_BLOCKED_FLAG_NAME = "third_party_app_blocked_flag";
34 constexpr const char* EXTENSION_SERVICE_BLOCKED_LIST_NAME = "service_blocked_list";
35 constexpr const char* EXTENSION_SERVICE_STARTUP_ENABLE_FLAG = "service_startup_enable_flag";
36 
37 const int32_t DEFAULT_EXTENSION_AUTO_DISCONNECT_TIME = -1;
38 }
39 
GetExtensionConfigPath() const40 std::string ExtensionConfig::GetExtensionConfigPath() const
41 {
42     char buf[MAX_PATH_LEN] = { 0 };
43     char *configPath = GetOneCfgFile(EXTENSION_CONFIG_FILE_PATH, buf, MAX_PATH_LEN);
44     if (configPath == nullptr || configPath[0] == '\0' || strlen(configPath) > MAX_PATH_LEN) {
45         return EXTENSION_CONFIG_DEFAULT_PATH;
46     }
47     return configPath;
48 }
49 
LoadExtensionConfiguration()50 void ExtensionConfig::LoadExtensionConfiguration()
51 {
52     TAG_LOGD(AAFwkTag::ABILITYMGR, "call");
53     nlohmann::json jsonBuf;
54     if (!ReadFileInfoJson(GetExtensionConfigPath().c_str(), jsonBuf)) {
55         TAG_LOGE(AAFwkTag::ABILITYMGR, "Parse file failed.");
56         return;
57     }
58 
59     LoadExtensionConfig(jsonBuf);
60 }
61 
GetExtensionAutoDisconnectTime(std::string extensionTypeName)62 int32_t ExtensionConfig::GetExtensionAutoDisconnectTime(std::string extensionTypeName)
63 {
64     if (extensionAutoDisconnectTimeMap_.find(extensionTypeName) != extensionAutoDisconnectTimeMap_.end()) {
65         return extensionAutoDisconnectTimeMap_[extensionTypeName];
66     }
67     return DEFAULT_EXTENSION_AUTO_DISCONNECT_TIME;
68 }
69 
IsExtensionStartThirdPartyAppEnable(std::string extensionTypeName)70 bool ExtensionConfig::IsExtensionStartThirdPartyAppEnable(std::string extensionTypeName)
71 {
72     if (thirdPartyAppEnableFlags_.find(extensionTypeName) != thirdPartyAppEnableFlags_.end()) {
73         return thirdPartyAppEnableFlags_[extensionTypeName];
74     }
75     return true;
76 }
77 
IsExtensionStartServiceEnable(std::string extensionTypeName,std::string targetUri)78 bool ExtensionConfig::IsExtensionStartServiceEnable(std::string extensionTypeName, std::string targetUri)
79 {
80     AppExecFwk::ElementName targetElementName;
81     if (serviceEnableFlags_.find(extensionTypeName) != serviceEnableFlags_.end() &&
82         !serviceEnableFlags_[extensionTypeName]) {
83         return false;
84     }
85     if (!targetElementName.ParseURI(targetUri) ||
86         serviceBlockedLists_.find(extensionTypeName) == serviceBlockedLists_.end()) {
87         return true;
88     }
89     for (const auto& iter : serviceBlockedLists_[extensionTypeName]) {
90         AppExecFwk::ElementName iterElementName;
91         if (iterElementName.ParseURI(iter) &&
92             iterElementName.GetBundleName() == targetElementName.GetBundleName() &&
93             iterElementName.GetAbilityName() == targetElementName.GetAbilityName()) {
94             return false;
95         }
96     }
97     return true;
98 }
99 
LoadExtensionConfig(const nlohmann::json & object)100 void ExtensionConfig::LoadExtensionConfig(const nlohmann::json &object)
101 {
102     if (!object.contains(EXTENSION_CONFIG_NAME) || !object.at(EXTENSION_CONFIG_NAME).is_array()) {
103         TAG_LOGE(AAFwkTag::ABILITYMGR, "Extension config not existed.");
104         return;
105     }
106 
107     for (auto &item : object.at(EXTENSION_CONFIG_NAME).items()) {
108         const nlohmann::json& jsonObject = item.value();
109         if (!jsonObject.contains(EXTENSION_TYPE_NAME) || !jsonObject.at(EXTENSION_TYPE_NAME).is_string()) {
110             continue;
111         }
112         std::string extensionTypeName = jsonObject.at(EXTENSION_TYPE_NAME).get<std::string>();
113         LoadExtensionAutoDisconnectTime(jsonObject, extensionTypeName);
114         LoadExtensionThirdPartyAppBlockedList(jsonObject, extensionTypeName);
115         LoadExtensionServiceBlockedList(jsonObject, extensionTypeName);
116     }
117 }
118 
LoadExtensionAutoDisconnectTime(const nlohmann::json & object,std::string extensionTypeName)119 void ExtensionConfig::LoadExtensionAutoDisconnectTime(const nlohmann::json &object, std::string extensionTypeName)
120 {
121     if (!object.contains(EXTENSION_AUTO_DISCONNECT_TIME) ||
122         !object.at(EXTENSION_AUTO_DISCONNECT_TIME).is_number()) {
123         TAG_LOGE(AAFwkTag::ABILITYMGR, "Auto disconnect time config not existed.");
124         return;
125     }
126     int32_t extensionAutoDisconnectTime = object.at(EXTENSION_AUTO_DISCONNECT_TIME).get<int32_t>();
127     extensionAutoDisconnectTimeMap_[extensionTypeName] = extensionAutoDisconnectTime;
128 }
129 
LoadExtensionThirdPartyAppBlockedList(const nlohmann::json & object,std::string extensionTypeName)130 void ExtensionConfig::LoadExtensionThirdPartyAppBlockedList(const nlohmann::json &object,
131     std::string extensionTypeName)
132 {
133     TAG_LOGD(AAFwkTag::ABILITYMGR, "call.");
134     if (!object.contains(EXTENSION_THIRD_PARTY_APP_BLOCKED_FLAG_NAME) ||
135         !object.at(EXTENSION_THIRD_PARTY_APP_BLOCKED_FLAG_NAME).is_boolean()) {
136         TAG_LOGE(AAFwkTag::ABILITYMGR, "Third party config not existed.");
137         return;
138     }
139     thirdPartyAppEnableFlags_[extensionTypeName] = object.at(EXTENSION_THIRD_PARTY_APP_BLOCKED_FLAG_NAME).get<bool>();
140     TAG_LOGD(AAFwkTag::ABILITYMGR, "The %{public}s extension's third party app blocked flag is %{public}d",
141         extensionTypeName.c_str(), thirdPartyAppEnableFlags_[extensionTypeName]);
142 }
143 
LoadExtensionServiceBlockedList(const nlohmann::json & object,std::string extensionTypeName)144 void ExtensionConfig::LoadExtensionServiceBlockedList(const nlohmann::json &object, std::string extensionTypeName)
145 {
146     TAG_LOGD(AAFwkTag::ABILITYMGR, "call.");
147     if (!object.contains(EXTENSION_SERVICE_STARTUP_ENABLE_FLAG) ||
148         !object.at(EXTENSION_SERVICE_STARTUP_ENABLE_FLAG).is_boolean()) {
149         TAG_LOGE(AAFwkTag::ABILITYMGR, "Service enable config not existed.");
150         return;
151     }
152     bool serviceEnableFlag = object.at(EXTENSION_SERVICE_STARTUP_ENABLE_FLAG).get<bool>();
153     if (!serviceEnableFlag) {
154         serviceEnableFlags_[extensionTypeName] = serviceEnableFlag;
155         TAG_LOGD(AAFwkTag::ABILITYMGR, "%{public}s Service startup is blocked.", extensionTypeName.c_str());
156         return;
157     }
158     if (!object.contains(EXTENSION_SERVICE_BLOCKED_LIST_NAME) ||
159         !object.at(EXTENSION_SERVICE_BLOCKED_LIST_NAME).is_array()) {
160         TAG_LOGE(AAFwkTag::ABILITYMGR, "Service config not existed.");
161         return;
162     }
163     std::unordered_set<std::string> serviceBlockedList;
164     for (auto &item : object.at(EXTENSION_SERVICE_BLOCKED_LIST_NAME).items()) {
165         const nlohmann::json& jsonObject = item.value();
166         if (!jsonObject.is_string()) {
167             continue;
168         }
169         std::string serviceUri = jsonObject.get<std::string>();
170         if (CheckServiceExtensionUriValid(serviceUri)) {
171             serviceBlockedList.emplace(serviceUri);
172         }
173     }
174     serviceBlockedLists_[extensionTypeName] = serviceBlockedList;
175     TAG_LOGD(AAFwkTag::ABILITYMGR, "The size of %{public}s extension's service blocked list is %{public}zu",
176         extensionTypeName.c_str(), serviceBlockedList.size());
177 }
178 
ReadFileInfoJson(const std::string & filePath,nlohmann::json & jsonBuf)179 bool ExtensionConfig::ReadFileInfoJson(const std::string &filePath, nlohmann::json &jsonBuf)
180 {
181     if (access(filePath.c_str(), F_OK) != 0) {
182         TAG_LOGD(AAFwkTag::ABILITYMGR, "%{public}s, not existed", filePath.c_str());
183         return false;
184     }
185 
186     std::fstream in;
187     char errBuf[256];
188     errBuf[0] = '\0';
189     in.open(filePath, std::ios_base::in);
190     if (!in.is_open()) {
191         strerror_r(errno, errBuf, sizeof(errBuf));
192         TAG_LOGE(AAFwkTag::ABILITYMGR, "the file cannot be open due to  %{public}s", errBuf);
193         return false;
194     }
195 
196     in.seekg(0, std::ios::end);
197     int64_t size = in.tellg();
198     if (size <= 0) {
199         TAG_LOGE(AAFwkTag::ABILITYMGR, "the file is an empty file");
200         in.close();
201         return false;
202     }
203 
204     in.seekg(0, std::ios::beg);
205     jsonBuf = nlohmann::json::parse(in, nullptr, false);
206     in.close();
207     if (jsonBuf.is_discarded()) {
208         TAG_LOGE(AAFwkTag::ABILITYMGR, "bad profile file");
209         return false;
210     }
211 
212     return true;
213 }
214 
CheckServiceExtensionUriValid(const std::string & uri)215 bool ExtensionConfig::CheckServiceExtensionUriValid(const std::string &uri)
216 {
217     const size_t memberNum = 4;
218     if (std::count(uri.begin(), uri.end(), '/') != memberNum - 1) {
219         TAG_LOGE(AAFwkTag::ABILITYMGR, "Invalid uri: %{public}s.", uri.c_str());
220         return false;
221     }
222     // correct uri: "/bundleName/moduleName/abilityName"
223     std::string::size_type pos1 = 0;
224     std::string::size_type pos2 = uri.find('/', pos1 + 1);
225     std::string::size_type pos3 = uri.find('/', pos2 + 1);
226     std::string::size_type pos4 = uri.find('/', pos3 + 1);
227     if ((pos3 == pos2 + 1) || (pos4 == pos3 + 1) || (pos4 == uri.size() - 1)) {
228         TAG_LOGE(AAFwkTag::ABILITYMGR, "Invalid uri: %{public}s.", uri.c_str());
229         return false;
230     }
231     return true;
232 }
233 }
234 }