• 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 <chrono>
19 #include <cinttypes>
20 #include "utd_client.h"
21 #include "logger.h"
22 #include "utd_graph.h"
23 #include "custom_utd_store.h"
24 #include "accesstoken_kit.h"
25 #include "ipc_skeleton.h"
26 #include "os_account_manager.h"
27 namespace OHOS {
28 namespace UDMF {
29 constexpr const int MAX_UTD_LENGTH = 256;
30 constexpr const int64_t RELOAD_INTERVAL = 10;
31 using namespace std::chrono;
32 
UtdClient()33 UtdClient::UtdClient()
34 {
35     if (!Init()) {
36         LOG_WARN(UDMF_CLIENT, "construct UtdClient failed, try again.");
37         auto updateTask = []() {
38             std::this_thread::sleep_for(std::chrono::seconds(3));
39             UtdClient::GetInstance().Init();
40         };
41         std::thread(updateTask).detach();
42     }
43     LOG_INFO(UDMF_CLIENT, "construct UtdClient sucess.");
44 }
45 
~UtdClient()46 UtdClient::~UtdClient()
47 {
48 }
49 
GetInstance()50 UtdClient &UtdClient::GetInstance()
51 {
52     static auto instance = new UtdClient();
53     return *instance;
54 }
55 
Init()56 bool UtdClient::Init()
57 {
58     bool result = true;
59     int32_t userId = DEFAULT_USER_ID;
60     bool isHap = IsHapTokenType();
61     if (!isHap && GetCurrentActiveUserId(userId) != Status::E_OK) {
62         result = false;
63     }
64 
65     std::vector<TypeDescriptorCfg> customUtd;
66     {
67         std::lock_guard<std::mutex> lock(customUtdMutex_);
68         utdFileInfo_ = CustomUtdStore::GetInstance().GetCustomUtdInfo(isHap, userId);
69         customUtd = CustomUtdStore::GetInstance().GetCustomUtd(isHap, userId);
70         lastLoadTime_ = duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
71     }
72 
73     std::unique_lock<std::shared_mutex> lock(utdMutex_);
74     descriptorCfgs_ = PresetTypeDescriptors::GetInstance().GetPresetTypes();
75 
76     LOG_INFO(UDMF_CLIENT, "get customUtd size:%{public}zu, file size:%{public}" PRIu64,
77         customUtd.size(), utdFileInfo_.size);
78     if (!customUtd.empty()) {
79         descriptorCfgs_.insert(descriptorCfgs_.end(), customUtd.begin(), customUtd.end());
80     }
81     UtdGraph::GetInstance().InitUtdGraph(descriptorCfgs_);
82     return result;
83 }
84 
GetTypeDescriptor(const std::string & typeId,std::shared_ptr<TypeDescriptor> & descriptor)85 Status UtdClient::GetTypeDescriptor(const std::string &typeId, std::shared_ptr<TypeDescriptor> &descriptor)
86 {
87     {
88         std::shared_lock<std::shared_mutex> guard(utdMutex_);
89         for (const auto &utdTypeCfg : descriptorCfgs_) {
90             if (utdTypeCfg.typeId == typeId) {
91                 descriptor = std::make_shared<TypeDescriptor>(utdTypeCfg);
92                 return Status::E_OK;
93             }
94         }
95     }
96     if (typeId.find(FLEXIBLE_TYPE_FLAG) != typeId.npos) {
97         return GetFlexibleTypeDescriptor(typeId, descriptor);
98     }
99     if (TryReloadCustomUtd()) {
100         return GetTypeDescriptor(typeId, descriptor);
101     }
102     return Status::E_OK;
103 }
104 
IsValidFileExtension(const std::string & fileExtension)105 bool UtdClient::IsValidFileExtension(const std::string &fileExtension)
106 {
107     if (fileExtension.empty()) {
108         return false;
109     }
110     if (fileExtension[0] != '.' || fileExtension.find("?") != fileExtension.npos ||
111         fileExtension.find(":") != fileExtension.npos || fileExtension.find("=") != fileExtension.npos ||
112         fileExtension.find("\\") != fileExtension.npos) {
113             return false;
114     }
115 
116     return true;
117 }
118 
IsValidMimeType(const std::string & mimeType)119 bool UtdClient::IsValidMimeType(const std::string &mimeType)
120 {
121     if (mimeType.empty()) {
122         return false;
123     }
124     if (mimeType.find("?") != mimeType.npos || mimeType.find(":") != mimeType.npos ||
125         mimeType.find("=") != mimeType.npos ||mimeType.find("\\") != mimeType.npos) {
126             return false;
127     }
128     return true;
129 }
130 
GetFlexibleTypeDescriptor(const std::string & typeId,std::shared_ptr<TypeDescriptor> & descriptor)131 Status UtdClient::GetFlexibleTypeDescriptor(const std::string &typeId, std::shared_ptr<TypeDescriptor> &descriptor)
132 {
133     TypeDescriptorCfg flexibleTypeDescriptorCfg;
134     if (!FlexibleType::ParseFlexibleUtd(typeId, flexibleTypeDescriptorCfg)) {
135         LOG_ERROR(UDMF_CLIENT, "ParseFlexibleUtd failed, invalid typeId");
136         return Status::E_ERROR;
137     }
138     descriptor = std::make_shared<TypeDescriptor>(flexibleTypeDescriptorCfg);
139     return Status::E_OK;
140 }
141 
GetUniformDataTypeByFilenameExtension(const std::string & fileExtension,std::string & typeId,std::string belongsTo)142 Status UtdClient::GetUniformDataTypeByFilenameExtension(const std::string &fileExtension, std::string &typeId,
143                                                         std::string belongsTo)
144 {
145     std::string lowerFileExtension = fileExtension;
146     std::transform(lowerFileExtension.begin(), lowerFileExtension.end(), lowerFileExtension.begin(), ::tolower);
147     if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
148         LOG_ERROR(UDMF_CLIENT, "invalid belongsTo.");
149         if (TryReloadCustomUtd()) {
150             return GetUniformDataTypeByFilenameExtension(fileExtension, typeId, belongsTo);
151         }
152         return Status::E_INVALID_PARAMETERS;
153     }
154     {
155         std::shared_lock<std::shared_mutex> guard(utdMutex_);
156         bool found = false;
157         for (const auto &utdTypeCfg : descriptorCfgs_) {
158             for (auto fileEx : utdTypeCfg.filenameExtensions) {
159                 std::transform(fileEx.begin(), fileEx.end(), fileEx.begin(), ::tolower);
160                 if (fileEx == lowerFileExtension && IsBelongingType(belongsTo, utdTypeCfg.typeId)) {
161                     typeId = utdTypeCfg.typeId;
162                     found = true;
163                     break;
164                 }
165             }
166             if (found) {
167                 break;
168             }
169         }
170     }
171     if (typeId.empty() && TryReloadCustomUtd()) {
172         return GetUniformDataTypeByFilenameExtension(fileExtension, typeId, belongsTo);
173     }
174     if (typeId.empty()) {
175         if (!IsValidFileExtension(lowerFileExtension)) {
176             LOG_ERROR(UDMF_CLIENT, "invalid fileExtension.");
177             return Status::E_INVALID_PARAMETERS;
178         }
179         typeId = FlexibleType::GenFlexibleUtd("", lowerFileExtension, belongsTo);
180     }
181     return Status::E_OK;
182 }
183 
GetUniformDataTypesByFilenameExtension(const std::string & fileExtension,std::vector<std::string> & typeIds,const std::string & belongsTo)184 Status UtdClient::GetUniformDataTypesByFilenameExtension(const std::string &fileExtension,
185     std::vector<std::string> &typeIds, const std::string &belongsTo)
186 {
187     if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
188         LOG_ERROR(UDMF_CLIENT, "invalid belongsTo.");
189         if (TryReloadCustomUtd()) {
190             return GetUniformDataTypesByFilenameExtension(fileExtension, typeIds, belongsTo);
191         }
192         return Status::E_INVALID_PARAMETERS;
193     }
194     if (!IsValidFileExtension(fileExtension)) {
195         LOG_ERROR(UDMF_CLIENT, "invalid fileExtension.");
196         return Status::E_INVALID_PARAMETERS;
197     }
198 
199     std::string lowerFileExtension = fileExtension;
200     std::transform(lowerFileExtension.begin(), lowerFileExtension.end(), lowerFileExtension.begin(), ::tolower);
201     std::vector<std::string> typeIdsInCfg;
202     {
203         std::shared_lock<std::shared_mutex> guard(utdMutex_);
204         for (const auto &utdTypeCfg : descriptorCfgs_) {
205             for (auto fileEx : utdTypeCfg.filenameExtensions) {
206                 std::transform(fileEx.begin(), fileEx.end(), fileEx.begin(), ::tolower);
207                 if (fileEx == lowerFileExtension) {
208                     typeIdsInCfg.push_back(utdTypeCfg.typeId);
209                     break;
210                 }
211             }
212         }
213     }
214     if (typeIdsInCfg.empty() && TryReloadCustomUtd()) {
215         return GetUniformDataTypesByFilenameExtension(fileExtension, typeIds, belongsTo);
216     }
217     typeIds.clear();
218     for (const auto &typeId : typeIdsInCfg) {
219         // the find typeId is not belongsTo to the belongsTo.
220         if (!IsBelongingType(belongsTo, typeId)) {
221             continue;
222         }
223         typeIds.emplace_back(typeId);
224     }
225     if (typeIds.empty()) {
226         typeIds.emplace_back(FlexibleType::GenFlexibleUtd("", lowerFileExtension, belongsTo));
227     }
228     return Status::E_OK;
229 }
230 
GetUniformDataTypeByMIMEType(const std::string & mimeType,std::string & typeId,std::string belongsTo)231 Status UtdClient::GetUniformDataTypeByMIMEType(const std::string &mimeType, std::string &typeId,
232                                                std::string belongsTo)
233 {
234     std::string lowerMimeType = mimeType;
235     std::transform(lowerMimeType.begin(), lowerMimeType.end(), lowerMimeType.begin(), ::tolower);
236     if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
237         LOG_ERROR(UDMF_CLIENT, "invalid belongsTo.");
238         if (TryReloadCustomUtd()) {
239             return GetUniformDataTypeByMIMEType(mimeType, typeId, belongsTo);
240         }
241         return Status::E_INVALID_PARAMETERS;
242     }
243     typeId = GetTypeIdFromCfg(lowerMimeType, belongsTo);
244     if (typeId.empty()) {
245         if (!IsValidMimeType(mimeType)) {
246             LOG_ERROR(UDMF_CLIENT, "invalid mimeType.");
247             return Status::E_INVALID_PARAMETERS;
248         }
249         typeId = FlexibleType::GenFlexibleUtd(lowerMimeType, "", belongsTo);
250     }
251     return Status::E_OK;
252 }
253 
GetTypeIdFromCfg(const std::string & mimeType,const std::string & belongsTo)254 std::string UtdClient::GetTypeIdFromCfg(const std::string &mimeType, const std::string &belongsTo)
255 {
256     if (mimeType.empty()) {
257         return "";
258     }
259     {
260         std::shared_lock<std::shared_mutex> guard(utdMutex_);
261         for (const auto &utdTypeCfg : descriptorCfgs_) {
262             for (auto mime : utdTypeCfg.mimeTypes) {
263                 std::transform(mime.begin(), mime.end(), mime.begin(), ::tolower);
264                 if (mime == mimeType && IsBelongingType(belongsTo, utdTypeCfg.typeId)) {
265                     return utdTypeCfg.typeId;
266                 }
267             }
268         }
269     }
270     if (mimeType.back() != '*') {
271         if (TryReloadCustomUtd()) {
272             return GetTypeIdFromCfg(mimeType, belongsTo);
273         }
274         return "";
275     }
276     {
277         std::shared_lock<std::shared_mutex> guard(utdMutex_);
278         std::string prefixType = mimeType.substr(0, mimeType.length() - 1);
279         for (const auto &utdTypeCfg : descriptorCfgs_) {
280             for (auto mime : utdTypeCfg.mimeTypes) {
281                 std::transform(mime.begin(), mime.end(), mime.begin(), ::tolower);
282                 if (mime.rfind(prefixType, 0) == 0 && utdTypeCfg.belongingToTypes.size() > 0
283                     && IsBelongingType(belongsTo, utdTypeCfg.typeId)) {
284                     return utdTypeCfg.belongingToTypes[0];
285                 }
286             }
287         }
288     }
289     if (TryReloadCustomUtd()) {
290         return GetTypeIdFromCfg(mimeType);
291     }
292     return "";
293 }
294 
GetUniformDataTypesByMIMEType(const std::string & mimeType,std::vector<std::string> & typeIds,const std::string & belongsTo)295 Status UtdClient::GetUniformDataTypesByMIMEType(const std::string &mimeType, std::vector<std::string> &typeIds,
296     const std::string &belongsTo)
297 {
298     if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
299         LOG_ERROR(UDMF_CLIENT, "invalid belongsTo.");
300         if (TryReloadCustomUtd()) {
301             return GetUniformDataTypesByMIMEType(mimeType, typeIds, belongsTo);
302         }
303         return Status::E_INVALID_PARAMETERS;
304     }
305     if (!IsValidMimeType(mimeType)) {
306         LOG_ERROR(UDMF_CLIENT, "invalid mimeType.");
307         return Status::E_INVALID_PARAMETERS;
308     }
309 
310     std::string lowerMimeType = mimeType;
311     std::transform(lowerMimeType.begin(), lowerMimeType.end(), lowerMimeType.begin(), ::tolower);
312     std::vector<std::string> typeIdsInCfg = GetTypeIdsFromCfg(lowerMimeType);
313     typeIds.clear();
314     for (const auto &typeId : typeIdsInCfg) {
315         // the find typeId is not belongsTo to the belongsTo.
316         if (!IsBelongingType(belongsTo, typeId)) {
317             continue;
318         }
319         typeIds.emplace_back(typeId);
320     }
321     if (typeIds.empty()) {
322         typeIds.emplace_back(FlexibleType::GenFlexibleUtd(lowerMimeType, "", belongsTo));
323     }
324     return Status::E_OK;
325 }
326 
GetTypeIdsFromCfg(const std::string & mimeType)327 std::vector<std::string> UtdClient::GetTypeIdsFromCfg(const std::string &mimeType)
328 {
329     bool prefixMatch = false;
330     std::string prefixType;
331     if (!mimeType.empty() && mimeType.back() == '*') {
332         prefixType = mimeType.substr(0, mimeType.length() - 1);
333         prefixMatch = true;
334     }
335     std::vector<std::string> typeIdsInCfg;
336 
337     {
338         std::shared_lock<std::shared_mutex> guard(utdMutex_);
339         for (const auto &utdTypeCfg : descriptorCfgs_) {
340             for (auto mime : utdTypeCfg.mimeTypes) {
341                 std::transform(mime.begin(), mime.end(), mime.begin(), ::tolower);
342                 if ((mime == mimeType) || (prefixMatch && mime.rfind(prefixType, 0) == 0)) {
343                     typeIdsInCfg.push_back(utdTypeCfg.typeId);
344                     break;
345                 }
346             }
347         }
348     }
349     if (typeIdsInCfg.empty() && TryReloadCustomUtd()) {
350         return GetTypeIdsFromCfg(mimeType);
351     }
352     return typeIdsInCfg;
353 }
354 
IsUtd(std::string typeId,bool & result)355 Status UtdClient::IsUtd(std::string typeId, bool &result)
356 {
357     try {
358         if (typeId.empty() || typeId.size() > MAX_UTD_LENGTH) {
359             result = false;
360             return Status::E_INVALID_PARAMETERS;
361         }
362         if (typeId[0] == '.' || find(typeId.begin(), typeId.end(), '/') != typeId.end()) {
363             result = false;
364             return Status::E_OK;
365         }
366         constexpr const char *preSetTypeIdRegexRule =
367             R"(^(general\.|openharmony\.|org\.|com\.|macos\.|debian\.|redhat\.|io\.|de\.|net\.)[a-z0-9-\.]+(\-[a-z0-9-]+)*$)";
368         if (std::regex_match(typeId, std::regex(preSetTypeIdRegexRule))) {
369             result = true;
370             return Status::E_OK;
371         }
372         constexpr const char *customUtdRegexRule = R"(^([A-Za-z]\w*)(\.\w+)+(\.[A-Za-z\d-]+)+)";
373         if (std::regex_match(typeId, std::regex(customUtdRegexRule))) {
374             result = true;
375             return Status::E_OK;
376         }
377         result = false;
378     } catch (...) {
379         LOG_ERROR(UDMF_CLIENT, "throw error");
380         result = false;
381         return Status::E_ERROR;
382     }
383     LOG_ERROR(UDMF_CLIENT, "is not utd");
384     return Status::E_OK;
385 }
386 
IsHapTokenType()387 bool UtdClient::IsHapTokenType()
388 {
389     uint32_t tokenId = IPCSkeleton::GetSelfTokenID();
390     auto tokenType = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId);
391     LOG_DEBUG(UDMF_CLIENT, "GetTokenTypeFlag, tokenType = %{public}d.", tokenType);
392     if (tokenType == Security::AccessToken::TypeATokenTypeEnum::TOKEN_HAP) {
393         return true;
394     }
395     return false;
396 }
397 
GetCurrentActiveUserId(int32_t & userId)398 Status UtdClient::GetCurrentActiveUserId(int32_t& userId)
399 {
400     std::vector<int32_t> localIds;
401     int32_t status = OHOS::AccountSA::OsAccountManager::QueryActiveOsAccountIds(localIds);
402     if (status != Status::E_OK || localIds.empty()) {
403         LOG_ERROR(UDMF_CLIENT, "Get OsAccountId fail, status:%{public}d", status);
404         return Status::E_ERROR;
405     }
406     userId = localIds[0];
407     return Status::E_OK;
408 }
409 
InstallCustomUtds(const std::string & bundleName,const std::string & jsonStr,int32_t user)410 void UtdClient::InstallCustomUtds(const std::string &bundleName, const std::string &jsonStr, int32_t user)
411 {
412     if (IsHapTokenType()) {
413         return;
414     }
415     LOG_INFO(UDMF_CLIENT, "start, bundleName:%{public}s, user:%{public}d", bundleName.c_str(), user);
416     std::lock_guard<std::mutex> lock(updateUtdMutex_);
417     std::vector<TypeDescriptorCfg> customTyepCfgs = CustomUtdStore::GetInstance().GetCustomUtd(false, user);
418     if (!CustomUtdStore::GetInstance().UninstallCustomUtds(bundleName, user, customTyepCfgs)) {
419         LOG_ERROR(UDMF_CLIENT, "custom utd installed failed. bundleName:%{public}s, user:%{public}d",
420             bundleName.c_str(), user);
421         return;
422     }
423     UpdateGraph(customTyepCfgs);
424     if (!jsonStr.empty()) {
425         if (!CustomUtdStore::GetInstance().InstallCustomUtds(bundleName, jsonStr, user, customTyepCfgs)) {
426             LOG_ERROR(UDMF_CLIENT, "no custom utd installed. bundleName:%{public}s, user:%{public}d",
427                 bundleName.c_str(), user);
428             return;
429         }
430         UpdateGraph(customTyepCfgs);
431     }
432 }
433 
UninstallCustomUtds(const std::string & bundleName,int32_t user)434 void UtdClient::UninstallCustomUtds(const std::string &bundleName, int32_t user)
435 {
436     if (IsHapTokenType()) {
437         return;
438     }
439     LOG_INFO(UDMF_CLIENT, "start, bundleName:%{public}s, user:%{public}d", bundleName.c_str(), user);
440     std::lock_guard<std::mutex> lock(updateUtdMutex_);
441     std::vector<TypeDescriptorCfg> customTyepCfgs = CustomUtdStore::GetInstance().GetCustomUtd(false, user);
442     if (!CustomUtdStore::GetInstance().UninstallCustomUtds(bundleName, user, customTyepCfgs)) {
443         LOG_ERROR(UDMF_CLIENT, "custom utd installed failed. bundleName:%{public}s, user:%{public}d",
444             bundleName.c_str(), user);
445         return;
446     }
447     UpdateGraph(customTyepCfgs);
448 }
449 
UpdateGraph(const std::vector<TypeDescriptorCfg> & customTyepCfgs)450 void UtdClient::UpdateGraph(const std::vector<TypeDescriptorCfg> &customTyepCfgs)
451 {
452     std::vector<TypeDescriptorCfg> allTypeCfgs = PresetTypeDescriptors::GetInstance().GetPresetTypes();
453     allTypeCfgs.insert(allTypeCfgs.end(), customTyepCfgs.begin(), customTyepCfgs.end());
454     LOG_INFO(UDMF_CLIENT, "customTyepSize:%{public}zu, allTypeSize:%{public}zu",
455         customTyepCfgs.size(), allTypeCfgs.size());
456     auto graph = UtdGraph::GetInstance().ConstructNewGraph(allTypeCfgs);
457     std::unique_lock<std::shared_mutex> lock(utdMutex_);
458     UtdGraph::GetInstance().Update(std::move(graph));
459     descriptorCfgs_ = allTypeCfgs;
460 }
461 
TryReloadCustomUtd()462 bool UtdClient::TryReloadCustomUtd()
463 {
464     {
465         std::lock_guard<std::mutex> lock(customUtdMutex_);
466         auto now = duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
467         auto delay = now - lastLoadTime_;
468         if (delay <= RELOAD_INTERVAL) {
469             LOG_DEBUG(UDMF_CLIENT, "interval time too short");
470             return false;
471         }
472         lastLoadTime_ = now;
473     }
474 
475     bool isHap = IsHapTokenType();
476     int32_t userId = DEFAULT_USER_ID;
477     if (!isHap) {
478         int32_t status = GetCurrentActiveUserId(userId);
479         LOG_DEBUG(UDMF_CLIENT, "get user id status=%{public}d", status);
480         if (status != Status::E_OK) {
481             return false;
482         }
483     }
484     UtdFileInfo info = CustomUtdStore::GetInstance().GetCustomUtdInfo(isHap, userId);
485     if (info.size == utdFileInfo_.size && info.lastTime == utdFileInfo_.lastTime) {
486         LOG_DEBUG(UDMF_CLIENT, "utd file not change");
487         return false;
488     }
489     LOG_INFO(UDMF_CLIENT, "utd file has change, try reload custom utd info");
490     if (Init()) {
491         std::lock_guard<std::mutex> lock(customUtdMutex_);
492         utdFileInfo_ = info;
493         return true;
494     }
495     return false;
496 }
497 
IsBelongingType(const std::string & belongsTo,const std::string & typeId) const498 bool UtdClient::IsBelongingType(const std::string &belongsTo, const std::string &typeId) const
499 {
500     return belongsTo == DEFAULT_TYPE_ID ||
501            belongsTo == typeId ||
502            UtdGraph::GetInstance().IsLowerLevelType(belongsTo, typeId);
503 }
504 } // namespace UDMF
505 } // namespace OHOS
506