1 /*
2 * Copyright (c) 2023 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 #define LOG_TAG "UtdClient"
16 #include <regex>
17 #include <thread>
18 #include "common_event_manager.h"
19 #include "common_event_subscriber.h"
20 #include "common_event_support.h"
21 #include "utd_client.h"
22 #include "logger.h"
23 #include "utd_graph.h"
24 #include "custom_utd_store.h"
25 #include "accesstoken_kit.h"
26 #include "ipc_skeleton.h"
27 #include "os_account_manager.h"
28 namespace OHOS {
29 namespace UDMF {
30 constexpr const char* CUSTOM_UTD_HAP_DIR = "/data/utd/utd-adt.json";
31 constexpr const char* CUSTOM_UTD_SA_DIR = "/data/service/el1/";
32 constexpr const char* CUSTOM_UTD_SA_SUB_DIR = "/distributeddata/utd/utd-adt.json";
33
34 class UtdChangeSubscriber final : public EventFwk::CommonEventSubscriber {
35 public:
36 explicit UtdChangeSubscriber(const EventFwk::CommonEventSubscribeInfo &subscribeInfo,
37 const std::function<void()> &callback);
38 virtual ~UtdChangeSubscriber() = default;
39 void OnReceiveEvent(const EventFwk::CommonEventData &data) override;
40 private:
41 std::function<void()> callback_;
42 };
43
UtdClient()44 UtdClient::UtdClient()
45 {
46 Init();
47 SubscribeUtdChange();
48 LOG_INFO(UDMF_CLIENT, "construct UtdClient sucess.");
49 }
50
~UtdClient()51 UtdClient::~UtdClient()
52 {
53 }
54
GetInstance()55 UtdClient &UtdClient::GetInstance()
56 {
57 static auto instance = new UtdClient();
58 return *instance;
59 }
60
Init()61 void UtdClient::Init()
62 {
63 std::unique_lock<std::shared_mutex> lock(utdMutex_);
64 descriptorCfgs_ = PresetTypeDescriptors::GetInstance().GetPresetTypes();
65 std::string customUtdPath = GetCustomUtdPath();
66 if (!customUtdPath.empty()) {
67 std::vector<TypeDescriptorCfg> customTypes =
68 CustomUtdStore::GetInstance().GetTypeCfgs(customUtdPath);
69 LOG_INFO(UDMF_CLIENT, "get customUtd. path:%{public}s, size:%{public}zu",
70 customUtdPath.c_str(), customTypes.size());
71 if (!customTypes.empty()) {
72 descriptorCfgs_.insert(descriptorCfgs_.end(), customTypes.begin(), customTypes.end());
73 }
74 }
75 UtdGraph::GetInstance().InitUtdGraph(descriptorCfgs_);
76 }
77
GetTypeDescriptor(const std::string & typeId,std::shared_ptr<TypeDescriptor> & descriptor)78 Status UtdClient::GetTypeDescriptor(const std::string &typeId, std::shared_ptr<TypeDescriptor> &descriptor)
79 {
80 {
81 std::shared_lock<std::shared_mutex> guard(utdMutex_);
82 for (const auto &utdTypeCfg : descriptorCfgs_) {
83 if (utdTypeCfg.typeId == typeId) {
84 descriptor = std::make_shared<TypeDescriptor>(utdTypeCfg);
85 LOG_DEBUG(UDMF_CLIENT, "get descriptor success. %{public}s ", typeId.c_str());
86 return Status::E_OK;
87 }
88 }
89 }
90 if (typeId.find(FLEXIBLE_TYPE_FLAG) != typeId.npos) {
91 LOG_DEBUG(UDMF_CLIENT, "get flexible descriptor. %{public}s ", typeId.c_str());
92 return GetFlexibleTypeDescriptor(typeId, descriptor);
93 }
94 return Status::E_OK;
95 }
96
IsValidFileExtension(const std::string & fileExtension)97 bool UtdClient::IsValidFileExtension(const std::string &fileExtension)
98 {
99 if (fileExtension.empty()) {
100 return false;
101 }
102 if (fileExtension[0] != '.' || fileExtension.find("?") != fileExtension.npos ||
103 fileExtension.find(":") != fileExtension.npos || fileExtension.find("=") != fileExtension.npos ||
104 fileExtension.find("\\") != fileExtension.npos) {
105 return false;
106 }
107
108 return true;
109 }
110
IsValidMimeType(const std::string & mimeType)111 bool UtdClient::IsValidMimeType(const std::string &mimeType)
112 {
113 if (mimeType.empty()) {
114 return false;
115 }
116 if (mimeType.find("?") != mimeType.npos || mimeType.find(":") != mimeType.npos ||
117 mimeType.find("=") != mimeType.npos ||mimeType.find("\\") != mimeType.npos) {
118 return false;
119 }
120 return true;
121 }
122
GetFlexibleTypeDescriptor(const std::string & typeId,std::shared_ptr<TypeDescriptor> & descriptor)123 Status UtdClient::GetFlexibleTypeDescriptor(const std::string &typeId, std::shared_ptr<TypeDescriptor> &descriptor)
124 {
125 TypeDescriptorCfg flexibleTypeDescriptorCfg;
126 if (!FlexibleType::ParseFlexibleUtd(typeId, flexibleTypeDescriptorCfg)) {
127 LOG_ERROR(UDMF_CLIENT, "ParseFlexibleUtd failed, invalid typeId: %{public}s", typeId.c_str());
128 return Status::E_ERROR;
129 }
130 descriptor = std::make_shared<TypeDescriptor>(flexibleTypeDescriptorCfg);
131 return Status::E_OK;
132 }
133
GetUniformDataTypeByFilenameExtension(const std::string & fileExtension,std::string & typeId,std::string belongsTo)134 Status UtdClient::GetUniformDataTypeByFilenameExtension(const std::string &fileExtension, std::string &typeId,
135 std::string belongsTo)
136 {
137 std::string lowerFileExtension = fileExtension;
138 std::transform(lowerFileExtension.begin(), lowerFileExtension.end(), lowerFileExtension.begin(), ::tolower);
139 if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
140 LOG_ERROR(UDMF_CLIENT, "invalid belongsTo. fileExtension:%{public}s, belongsTo:%{public}s ",
141 fileExtension.c_str(), belongsTo.c_str());
142 return Status::E_INVALID_PARAMETERS;
143 }
144 {
145 std::shared_lock<std::shared_mutex> guard(utdMutex_);
146 for (const auto &utdTypeCfg : descriptorCfgs_) {
147 std::vector<std::string> fileExtensions = utdTypeCfg.filenameExtensions;
148 if (find(fileExtensions.begin(), fileExtensions.end(), lowerFileExtension) != fileExtensions.end() ||
149 find(fileExtensions.begin(), fileExtensions.end(), fileExtension) != fileExtensions.end()) {
150 typeId = utdTypeCfg.typeId;
151 break;
152 }
153 }
154 }
155 // the find typeId is not belongsTo to the belongsTo.
156 if (!typeId.empty() && belongsTo != DEFAULT_TYPE_ID && belongsTo != typeId &&
157 !UtdGraph::GetInstance().IsLowerLevelType(belongsTo, typeId)) {
158 typeId = "";
159 }
160
161 if (typeId.empty()) {
162 if (!IsValidFileExtension(lowerFileExtension)) {
163 LOG_ERROR(UDMF_CLIENT, "invalid fileExtension. fileExtension:%{public}s, belongsTo:%{public}s ",
164 fileExtension.c_str(), belongsTo.c_str());
165 return Status::E_INVALID_PARAMETERS;
166 }
167 typeId = FlexibleType::GenFlexibleUtd("", lowerFileExtension, belongsTo);
168 }
169 return Status::E_OK;
170 }
171
GetUniformDataTypesByFilenameExtension(const std::string & fileExtension,std::vector<std::string> & typeIds,const std::string & belongsTo)172 Status UtdClient::GetUniformDataTypesByFilenameExtension(const std::string &fileExtension,
173 std::vector<std::string> &typeIds, const std::string &belongsTo)
174 {
175 if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
176 LOG_ERROR(UDMF_CLIENT, "invalid belongsTo. fileExtension:%{public}s, belongsTo:%{public}s ",
177 fileExtension.c_str(), belongsTo.c_str());
178 return Status::E_INVALID_PARAMETERS;
179 }
180 if (!IsValidFileExtension(fileExtension)) {
181 LOG_ERROR(UDMF_CLIENT, "invalid fileExtension. fileExtension:%{public}s, belongsTo:%{public}s ",
182 fileExtension.c_str(), belongsTo.c_str());
183 return Status::E_INVALID_PARAMETERS;
184 }
185
186 std::string lowerFileExtension = fileExtension;
187 std::transform(lowerFileExtension.begin(), lowerFileExtension.end(), lowerFileExtension.begin(), ::tolower);
188 std::vector<std::string> typeIdsInCfg;
189 {
190 std::shared_lock<std::shared_mutex> guard(utdMutex_);
191 for (const auto &utdTypeCfg : descriptorCfgs_) {
192 std::vector<std::string> fileExtensions = utdTypeCfg.filenameExtensions;
193 if (find(fileExtensions.begin(), fileExtensions.end(), lowerFileExtension) != fileExtensions.end()) {
194 typeIdsInCfg.push_back(utdTypeCfg.typeId);
195 }
196 }
197 }
198 typeIds.clear();
199 for (const auto &typeId : typeIdsInCfg) {
200 // the find typeId is not belongsTo to the belongsTo.
201 if (belongsTo != DEFAULT_TYPE_ID && belongsTo != typeId &&
202 !UtdGraph::GetInstance().IsLowerLevelType(belongsTo, typeId)) {
203 continue;
204 }
205 typeIds.emplace_back(typeId);
206 }
207 if (typeIds.empty()) {
208 typeIds.emplace_back(FlexibleType::GenFlexibleUtd("", lowerFileExtension, belongsTo));
209 }
210 return Status::E_OK;
211 }
212
GetUniformDataTypeByMIMEType(const std::string & mimeType,std::string & typeId,std::string belongsTo)213 Status UtdClient::GetUniformDataTypeByMIMEType(const std::string &mimeType, std::string &typeId,
214 std::string belongsTo)
215 {
216 std::string lowerMimeType = mimeType;
217 std::transform(lowerMimeType.begin(), lowerMimeType.end(), lowerMimeType.begin(), ::tolower);
218 if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
219 LOG_ERROR(UDMF_CLIENT, "invalid belongsTo. mimeType:%{public}s, belongsTo:%{public}s ",
220 mimeType.c_str(), belongsTo.c_str());
221 return Status::E_INVALID_PARAMETERS;
222 }
223 typeId = GetTypeIdFromCfg(lowerMimeType);
224 // the find typeId is not belongsTo to the belongsTo.
225 if (!typeId.empty() && belongsTo != DEFAULT_TYPE_ID && belongsTo != typeId &&
226 !UtdGraph::GetInstance().IsLowerLevelType(belongsTo, typeId)) {
227 typeId = "";
228 }
229 if (typeId.empty()) {
230 if (!IsValidMimeType(mimeType)) {
231 LOG_ERROR(UDMF_CLIENT, "invalid mimeType. mimeType:%{public}s, belongsTo:%{public}s ",
232 mimeType.c_str(), belongsTo.c_str());
233 return Status::E_INVALID_PARAMETERS;
234 }
235 typeId = FlexibleType::GenFlexibleUtd(lowerMimeType, "", belongsTo);
236 }
237 return Status::E_OK;
238 }
239
GetTypeIdFromCfg(const std::string & mimeType)240 std::string UtdClient::GetTypeIdFromCfg(const std::string &mimeType)
241 {
242 std::shared_lock<std::shared_mutex> guard(utdMutex_);
243 for (const auto &utdTypeCfg : descriptorCfgs_) {
244 for (auto mime : utdTypeCfg.mimeTypes) {
245 std::transform(mime.begin(), mime.end(), mime.begin(), ::tolower);
246 if (mime == mimeType) {
247 return utdTypeCfg.typeId;
248 }
249 }
250 }
251 if (mimeType.empty() || mimeType.back() != '*') {
252 return "";
253 }
254 std::string prefixType = mimeType.substr(0, mimeType.length() - 1);
255 for (const auto &utdTypeCfg : descriptorCfgs_) {
256 for (auto mime : utdTypeCfg.mimeTypes) {
257 std::transform(mime.begin(), mime.end(), mime.begin(), ::tolower);
258 if (mime.rfind(prefixType, 0) == 0 && utdTypeCfg.belongingToTypes.size() > 0) {
259 return utdTypeCfg.belongingToTypes[0];
260 }
261 }
262 }
263 return "";
264 }
265
GetUniformDataTypesByMIMEType(const std::string & mimeType,std::vector<std::string> & typeIds,const std::string & belongsTo)266 Status UtdClient::GetUniformDataTypesByMIMEType(const std::string &mimeType, std::vector<std::string> &typeIds,
267 const std::string &belongsTo)
268 {
269 if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
270 LOG_ERROR(UDMF_CLIENT, "invalid belongsTo. mimeType:%{public}s, belongsTo:%{public}s ",
271 mimeType.c_str(), belongsTo.c_str());
272 return Status::E_INVALID_PARAMETERS;
273 }
274 if (!IsValidMimeType(mimeType)) {
275 LOG_ERROR(UDMF_CLIENT, "invalid mimeType. mimeType:%{public}s, belongsTo:%{public}s ",
276 mimeType.c_str(), belongsTo.c_str());
277 return Status::E_INVALID_PARAMETERS;
278 }
279
280 std::string lowerMimeType = mimeType;
281 std::transform(lowerMimeType.begin(), lowerMimeType.end(), lowerMimeType.begin(), ::tolower);
282 std::vector<std::string> typeIdsInCfg = GetTypeIdsFromCfg(lowerMimeType);
283 typeIds.clear();
284 for (const auto &typeId : typeIdsInCfg) {
285 // the find typeId is not belongsTo to the belongsTo.
286 if (belongsTo != DEFAULT_TYPE_ID && belongsTo != typeId &&
287 !UtdGraph::GetInstance().IsLowerLevelType(belongsTo, typeId)) {
288 continue;
289 }
290 typeIds.emplace_back(typeId);
291 }
292 if (typeIds.empty()) {
293 typeIds.emplace_back(FlexibleType::GenFlexibleUtd(lowerMimeType, "", belongsTo));
294 }
295 return Status::E_OK;
296 }
297
GetTypeIdsFromCfg(const std::string & mimeType)298 std::vector<std::string> UtdClient::GetTypeIdsFromCfg(const std::string &mimeType)
299 {
300 bool prefixMatch = false;
301 std::string prefixType;
302 if (!mimeType.empty() && mimeType.back() == '*') {
303 prefixType = mimeType.substr(0, mimeType.length() - 1);
304 prefixMatch = true;
305 }
306 std::vector<std::string> typeIdsInCfg;
307
308 std::shared_lock<std::shared_mutex> guard(utdMutex_);
309 for (const auto &utdTypeCfg : descriptorCfgs_) {
310 for (auto mime : utdTypeCfg.mimeTypes) {
311 std::transform(mime.begin(), mime.end(), mime.begin(), ::tolower);
312 if ((mime == mimeType) || (prefixMatch && mime.rfind(prefixType, 0) == 0)) {
313 typeIdsInCfg.push_back(utdTypeCfg.typeId);
314 break;
315 }
316 }
317 }
318 return typeIdsInCfg;
319 }
320
IsUtd(std::string typeId,bool & result)321 Status UtdClient::IsUtd(std::string typeId, bool &result)
322 {
323 try {
324 if (typeId.empty()) {
325 result = false;
326 return Status::E_INVALID_PARAMETERS;
327 }
328 if (typeId[0] == '.' || find(typeId.begin(), typeId.end(), '/') != typeId.end()) {
329 result = false;
330 return Status::E_OK;
331 }
332 constexpr const char *preSetTypeIdRegexRule =
333 R"(^(general\.|openharmony\.|org\.|com\.|macos\.|debian\.|redhat\.|io\.|de\.|net\.)[a-z0-9-\.]+(\-[a-z0-9-]+)*$)";
334 if (std::regex_match(typeId, std::regex(preSetTypeIdRegexRule))) {
335 result = true;
336 return Status::E_OK;
337 }
338 constexpr const char *customUtdRegexRule = R"(^([A-Za-z]\w*)(\.\w+)+(\.[A-Za-z\d-]+)+)";
339 if (std::regex_match(typeId, std::regex(customUtdRegexRule))) {
340 result = true;
341 return Status::E_OK;
342 }
343 result = false;
344 } catch (...) {
345 LOG_ERROR(UDMF_CLIENT, "exception, typeId:%{public}s", typeId.c_str());
346 result = false;
347 return Status::E_ERROR;
348 }
349 LOG_ERROR(UDMF_CLIENT, "is not utd, typeId:%{public}s", typeId.c_str());
350 return Status::E_OK;
351 }
352
IsHapTokenType()353 bool UtdClient::IsHapTokenType()
354 {
355 uint32_t tokenId = IPCSkeleton::GetSelfTokenID();
356 auto tokenType = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId);
357 LOG_DEBUG(UDMF_CLIENT, "GetTokenTypeFlag, tokenType = %{public}d.", tokenType);
358 if (tokenType == Security::AccessToken::TypeATokenTypeEnum::TOKEN_HAP) {
359 return true;
360 }
361 return false;
362 }
363
GetCustomUtdPath()364 std::string UtdClient::GetCustomUtdPath()
365 {
366 if (IsHapTokenType()) {
367 return std::string(CUSTOM_UTD_HAP_DIR);
368 }
369 int32_t userId = DEFAULT_USER_ID;
370 if (GetCurrentActiveUserId(userId) != Status::E_OK) {
371 return "";
372 }
373 std::string customUtdSaPath = std::string(CUSTOM_UTD_SA_DIR) +
374 std::to_string(userId) + std::string(CUSTOM_UTD_SA_SUB_DIR);
375 return customUtdSaPath;
376 }
377
GetCurrentActiveUserId(int32_t & userId)378 Status UtdClient::GetCurrentActiveUserId(int32_t& userId)
379 {
380 std::vector<int32_t> localIds;
381 int32_t status = OHOS::AccountSA::OsAccountManager::QueryActiveOsAccountIds(localIds);
382 if (status != Status::E_OK || localIds.empty()) {
383 LOG_ERROR(UDMF_CLIENT, "Get OsAccountId fail, status:%{public}d", status);
384 return Status::E_ERROR;
385 }
386 userId = localIds[0];
387 return Status::E_OK;
388 }
389
SubscribeUtdChange()390 void UtdClient::SubscribeUtdChange()
391 {
392 if (IsHapTokenType()) {
393 return;
394 }
395 LOG_INFO(UDMF_CLIENT, "subscribe utd change callback.");
396 EventFwk::MatchingSkills matchingSkills;
397 matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_ADDED);
398 matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_CHANGED);
399 matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED);
400 EventFwk::CommonEventSubscribeInfo subscribeInfo(matchingSkills);
401 auto updateTask = []() {
402 std::this_thread::sleep_for(std::chrono::milliseconds(3000));
403 UtdClient::GetInstance().Init();
404 };
405 subscriber_ = std::make_shared<UtdChangeSubscriber>(subscribeInfo, updateTask);
406 (void)EventFwk::CommonEventManager::SubscribeCommonEvent(subscriber_);
407 }
408
UtdChangeSubscriber(const EventFwk::CommonEventSubscribeInfo & subscribeInfo,const std::function<void ()> & callback)409 UtdChangeSubscriber::UtdChangeSubscriber(const EventFwk::CommonEventSubscribeInfo &subscribeInfo,
410 const std::function<void()> &callback)
411 : EventFwk::CommonEventSubscriber(subscribeInfo), callback_(callback)
412 {
413 }
414
OnReceiveEvent(const EventFwk::CommonEventData & data)415 void UtdChangeSubscriber::OnReceiveEvent(const EventFwk::CommonEventData &data)
416 {
417 LOG_INFO(UDMF_CLIENT, "start.");
418 std::thread(callback_).detach();
419 }
420 } // namespace UDMF
421 } // namespace OHOS
422