• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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