1 /*
2 * Copyright (c) 2021-2022 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 #include "hap_manager.h"
16
17 #include <algorithm>
18 #include <fstream>
19 #include <climits>
20 #include <cstdlib>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include "utils/errors.h"
24 #ifdef SUPPORT_GRAPHICS
25 #include <ohos/init_data.h>
26 #include <unicode/unistr.h>
27 #include <unicode/utypes.h>
28 #endif
29
30 #include "auto_mutex.h"
31 #include "hilog_wrapper.h"
32
33 #include "hap_parser.h"
34 #include "utils/utils.h"
35
36 #ifdef __WINNT__
37 #include <shlwapi.h>
38 #include <windows.h>
39 #else
40 #include <dlfcn.h>
41 #endif
42
43 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
44 #include "hisysevent_adapter.h"
45 #endif
46
47 namespace OHOS {
48 namespace Global {
49 namespace Resource {
50 #ifdef SUPPORT_GRAPHICS
51 constexpr uint32_t PLURAL_CACHE_MAX_COUNT = 3;
52 #endif
HapManager(ResConfigImpl * resConfig)53 HapManager::HapManager(ResConfigImpl *resConfig)
54 : resConfig_(resConfig)
55 {
56 }
57
58 bool HapManager::icuInitialized = HapManager::Init();
59
Init()60 bool HapManager::Init()
61 {
62 #ifdef SUPPORT_GRAPHICS
63 #ifdef __IDE_PREVIEW__
64 #ifdef __WINNT__
65 MEMORY_BASIC_INFORMATION mbi;
66 if (::VirtualQuery((LPCVOID)SetHwIcuDirectory, &mbi, sizeof(mbi)) != 0) {
67 char path[MAX_PATH] = { 0 };
68 GetModuleFileName((HMODULE)mbi.AllocationBase, path, MAX_PATH);
69 std::string tempPath(path);
70 auto pos = tempPath.rfind('\\');
71 if (pos != std::string::npos) {
72 u_setDataDirectory(tempPath.substr(0, pos).c_str());
73 }
74 }
75 #else
76 Dl_info info;
77 if (dladdr((void*)SetHwIcuDirectory, &info) != 0) {
78 std::string tempPath(info.dli_fname);
79 auto pos = tempPath.rfind('/');
80 if (pos != std::string::npos) {
81 u_setDataDirectory(tempPath.substr(0, pos).c_str());
82 }
83 }
84 #endif
85 #else
86 #if !defined(__ARKUI_CROSS__)
87 SetHwIcuDirectory();
88 #endif
89 #endif
90 #endif
91 return true;
92 }
93
GetPluralRulesAndSelect(int quantity)94 std::string HapManager::GetPluralRulesAndSelect(int quantity)
95 {
96 std::string defaultRet("other");
97 #ifdef SUPPORT_GRAPHICS
98 AutoMutex mutex(this->lock_);
99 if (this->resConfig_ == nullptr || this->resConfig_->GetResLocale() == nullptr ||
100 this->resConfig_->GetResLocale()->GetLanguage() == nullptr) {
101 HILOG_ERROR("GetPluralRules language is null!");
102 return defaultRet;
103 }
104 std::string language = this->resConfig_->GetResLocale()->GetLanguage();
105
106 icu::PluralRules *pluralRules = nullptr;
107 for (uint32_t i = 0; i < plurRulesCache_.size(); i++) {
108 auto pair = plurRulesCache_[i];
109 if (language == pair.first) {
110 // cache hit
111 pluralRules = pair.second;
112 break;
113 }
114 }
115
116 if (pluralRules == nullptr) {
117 // no cache hit
118 icu::Locale locale(language.c_str());
119 if (locale.isBogus()) {
120 HILOG_ERROR("icu::Locale init error : %s", language.c_str());
121 return defaultRet;
122 }
123 UErrorCode status = U_ZERO_ERROR;
124 pluralRules = icu::PluralRules::forLocale(locale, status);
125 if (status != U_ZERO_ERROR) {
126 HILOG_ERROR("icu::PluralRules::forLocale error : %d", status);
127 return defaultRet;
128 }
129 // after PluralRules created, we add it to cache, if > 3 delete oldest one
130 if (plurRulesCache_.size() >= PLURAL_CACHE_MAX_COUNT) {
131 HILOG_DEBUG("cache rotate delete plurRulesMap_ %s", plurRulesCache_[0].first.c_str());
132 delete (plurRulesCache_[0].second);
133 plurRulesCache_.erase(plurRulesCache_.begin());
134 }
135 auto plPair = std::make_pair(language, pluralRules);
136 plurRulesCache_.push_back(plPair);
137 }
138 std::string converted;
139 icu::UnicodeString us = pluralRules->select(quantity);
140 us.toUTF8String(converted);
141 return converted;
142 #else
143 return defaultRet;
144 #endif
145 }
146
FindResourceById(uint32_t id)147 const IdItem *HapManager::FindResourceById(uint32_t id)
148 {
149 auto qualifierValue = FindQualifierValueById(id);
150 if (qualifierValue == nullptr) {
151 return nullptr;
152 }
153 return qualifierValue->GetIdItem();
154 }
155
FindResourceByName(const char * name,const ResType resType)156 const IdItem *HapManager::FindResourceByName(const char *name, const ResType resType)
157 {
158 auto qualifierValue = FindQualifierValueByName(name, resType);
159 if (qualifierValue == nullptr) {
160 return nullptr;
161 }
162 return qualifierValue->GetIdItem();
163 }
164
FindQualifierValueByName(const char * name,const ResType resType,uint32_t density)165 const HapResource::ValueUnderQualifierDir *HapManager::FindQualifierValueByName(
166 const char *name, const ResType resType, uint32_t density)
167 {
168 AutoMutex mutex(this->lock_);
169 std::vector<const HapResource::IdValues *> candidates = this->GetResourceListByName(name, resType);
170 if (candidates.size() == 0) {
171 return nullptr;
172 }
173 return this->GetBestMatchResource(candidates, density);
174 }
175
FindQualifierValueById(uint32_t id,uint32_t density)176 const HapResource::ValueUnderQualifierDir *HapManager::FindQualifierValueById(uint32_t id, uint32_t density)
177 {
178 AutoMutex mutex(this->lock_);
179 std::vector<const HapResource::IdValues *> candidates = this->GetResourceList(id);
180 if (candidates.size() == 0) {
181 return nullptr;
182 }
183 return this->GetBestMatchResource(candidates, density);
184 }
185
GetBestMatchResource(std::vector<const HapResource::IdValues * > candidates,uint32_t density)186 const HapResource::ValueUnderQualifierDir *HapManager::GetBestMatchResource(std::vector<const HapResource::IdValues *>
187 candidates, uint32_t density)
188 {
189 const ResConfigImpl *bestResConfig = nullptr;
190 const ResConfigImpl *bestOverlayResConfig = nullptr;
191 const HapResource::ValueUnderQualifierDir *result = nullptr;
192 const HapResource::ValueUnderQualifierDir *overlayResult = nullptr;
193 const ResConfigImpl *currentResConfig = this->resConfig_;
194 for (auto iter = candidates.begin(); iter != candidates.end(); iter++) {
195 const std::vector<HapResource::ValueUnderQualifierDir *> paths = (*iter)->GetLimitPathsConst();
196 size_t len = paths.size();
197 size_t i = 0;
198 bool isOverlayHapResource = paths[0]->IsOverlay();
199 for (i = 0; i < len; i++) {
200 HapResource::ValueUnderQualifierDir *path = paths[i];
201 const ResConfigImpl *resConfig = path->GetResConfig();
202 if (!this->resConfig_->Match(resConfig)) {
203 continue;
204 }
205 if (isOverlayHapResource) {
206 if (bestOverlayResConfig == nullptr) {
207 bestOverlayResConfig = resConfig;
208 overlayResult = paths[i];
209 continue;
210 }
211 if (!bestOverlayResConfig->IsMoreSuitable(resConfig, currentResConfig, density)) {
212 bestOverlayResConfig = resConfig;
213 overlayResult = paths[i];
214 }
215 } else {
216 if (bestResConfig == nullptr) {
217 bestResConfig = resConfig;
218 result = paths[i];
219 continue;
220 }
221 if (!bestResConfig->IsMoreSuitable(resConfig, currentResConfig, density)) {
222 bestResConfig = resConfig;
223 result = paths[i];
224 }
225 }
226 }
227 }
228 if (bestOverlayResConfig != nullptr && result != nullptr && result->IsSystemResource()) {
229 if (bestOverlayResConfig->IsMoreSuitable(bestResConfig, currentResConfig, density)) {
230 return overlayResult;
231 }
232 }
233 return result;
234 }
235
FindRawFile(const std::string & name,std::string & outValue)236 RState HapManager::FindRawFile(const std::string &name, std::string &outValue)
237 {
238 #ifdef __WINNT__
239 char seperator = '\\';
240 #else
241 char seperator = '/';
242 #endif
243 for (auto iter = hapResources_.rbegin(); iter != hapResources_.rend(); iter++) {
244 std::string indexPath = (*iter)->GetIndexPath();
245 auto index = indexPath.rfind(seperator);
246 if (index == std::string::npos) {
247 HILOG_ERROR("index path format error, %s", indexPath.c_str());
248 continue;
249 }
250 std::string resourcesIndexPath = indexPath.substr(0, index);
251 char tmpPath[PATH_MAX] = {0};
252 std::string tempName = name;
253 const std::string rawFileDirName = "rawfile/";
254 if (tempName.length() <= rawFileDirName.length()
255 || (tempName.compare(0, rawFileDirName.length(), rawFileDirName) != 0)) {
256 tempName = rawFileDirName + tempName;
257 }
258 #ifdef __WINNT__
259 if (!PathCanonicalizeA(tmpPath, (resourcesIndexPath + "/resources/" + tempName).c_str())) {
260 continue;
261 }
262 #else
263 if (realpath((resourcesIndexPath + "/resources/" + tempName).c_str(), tmpPath) == nullptr) {
264 HILOG_ERROR("FindRawFile path to realpath error");
265 continue;
266 }
267 #endif
268 const std::string realPath = tmpPath;
269 if (realPath.length() > resourcesIndexPath.length()
270 && (realPath.compare(0, resourcesIndexPath.length(), resourcesIndexPath) == 0)) {
271 std::fstream inputFile;
272 inputFile.open(realPath, std::ios::in);
273 if (inputFile) {
274 outValue = realPath;
275 return SUCCESS;
276 }
277 }
278 }
279 return ERROR_CODE_RES_PATH_INVALID;
280 }
281
UpdateResConfig(ResConfig & resConfig)282 RState HapManager::UpdateResConfig(ResConfig &resConfig)
283 {
284 AutoMutex mutex(this->lock_);
285 this->resConfig_->Copy(resConfig);
286 RState rState = this->ReloadAll();
287 if (rState != SUCCESS) {
288 HILOG_ERROR("ReloadAll() failed when UpdateResConfig!");
289 }
290 return rState;
291 }
292
293
GetResConfig(ResConfig & resConfig)294 void HapManager::GetResConfig(ResConfig &resConfig)
295 {
296 AutoMutex mutex(this->lock_);
297 resConfig.Copy(*(this->resConfig_));
298 }
299
AddResource(const char * path)300 bool HapManager::AddResource(const char *path)
301 {
302 AutoMutex mutex(this->lock_);
303 return this->AddResourcePath(path);
304 }
305
AddResource(const std::string & path,const std::vector<std::string> & overlayPaths)306 bool HapManager::AddResource(const std::string &path, const std::vector<std::string> &overlayPaths)
307 {
308 loadedHapPaths_[path] = overlayPaths;
309 std::unordered_map<std::string, HapResource *> result = HapResource::LoadOverlays(path, overlayPaths, resConfig_);
310 if (result.size() > 0) {
311 std::vector<std::string> &validOverlayPaths = loadedHapPaths_[path];
312 int i = 0;
313 for (auto iter = result.begin(); iter != result.end(); iter++) {
314 this->hapResources_.push_back(iter->second);
315 if (i > 0) {
316 // the first is the target, not the overlay
317 validOverlayPaths.push_back(iter->first);
318 i++;
319 }
320 }
321 return true;
322 }
323 return false;
324 }
325
~HapManager()326 HapManager::~HapManager()
327 {
328 for (size_t i = 0; i < hapResources_.size(); ++i) {
329 if (hapResources_[i] != nullptr) {
330 delete hapResources_[i];
331 hapResources_[i] = nullptr;
332 }
333 }
334 if (resConfig_ != nullptr) {
335 delete resConfig_;
336 resConfig_ = nullptr;
337 }
338
339 #ifdef SUPPORT_GRAPHICS
340 auto iter = plurRulesCache_.begin();
341 for (; iter != plurRulesCache_.end(); iter++) {
342 HILOG_DEBUG("delete plurRulesMap_ %s", iter->first.c_str());
343 if (iter->second != nullptr) {
344 auto ptr = iter->second;
345 delete (ptr);
346 iter->second = nullptr;
347 }
348 }
349 #endif
350 }
351
GetResourceList(uint32_t ident) const352 std::vector<const HapResource::IdValues *> HapManager::GetResourceList(uint32_t ident) const
353 {
354 std::vector<const HapResource::IdValues *> result;
355 // one id only exit in one hap
356 for (size_t i = 0; i < hapResources_.size(); ++i) {
357 HapResource *pResource = hapResources_[i];
358 const HapResource::IdValues *out = pResource->GetIdValues(ident);
359 if (out != nullptr) {
360 result.emplace_back(out);
361 }
362 }
363 return result;
364 }
365
GetResourceListByName(const char * name,const ResType resType) const366 std::vector<const HapResource::IdValues *> HapManager::GetResourceListByName(const char *name,
367 const ResType resType) const
368 {
369 std::vector<const HapResource::IdValues *> result;
370 // all match will return
371 for (size_t i = 0; i < hapResources_.size(); ++i) {
372 HapResource *pResource = hapResources_[i];
373 const HapResource::IdValues *out = pResource->GetIdValuesByName(std::string(name), resType);
374 if (out != nullptr) {
375 result.emplace_back(out);
376 }
377 }
378 return result;
379 }
380
AddResourcePath(const char * path)381 bool HapManager::AddResourcePath(const char *path)
382 {
383 std::string sPath(path);
384 auto it = loadedHapPaths_.find(sPath);
385 if (it != loadedHapPaths_.end()) {
386 HILOG_ERROR(" %s has already been loaded!", path);
387 return false;
388 }
389 const HapResource *pResource = HapResource::Load(path, resConfig_);
390 if (pResource == nullptr) {
391 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
392 ReportAddResourcePathFail(path, "AddResourcePath failed");
393 #endif
394 return false;
395 }
396 this->hapResources_.push_back(const_cast<HapResource *>(pResource));
397 this->loadedHapPaths_[sPath] = std::vector<std::string>();
398 return true;
399 }
400
DeleteNewResource(std::vector<HapResource * > & newResources)401 void DeleteNewResource(std::vector<HapResource *> &newResources)
402 {
403 for (size_t i = 0; i < newResources.size(); ++i) {
404 if (newResources[i] != nullptr) {
405 delete (newResources[i]);
406 newResources[i] = nullptr;
407 }
408 }
409 }
410
ReloadAll()411 RState HapManager::ReloadAll()
412 {
413 if (hapResources_.size() == 0) {
414 return SUCCESS;
415 }
416 std::vector<HapResource *> newResources;
417 for (auto iter = loadedHapPaths_.begin(); iter != loadedHapPaths_.end(); iter++) {
418 std::vector<std::string> &overlayPaths = iter->second;
419 if (overlayPaths.size() == 0) {
420 const HapResource *pResource = HapResource::Load(iter->first.c_str(), resConfig_);
421 if (pResource == nullptr) {
422 DeleteNewResource(newResources);
423 return HAP_INIT_FAILED;
424 }
425 newResources.push_back(const_cast<HapResource *>(pResource));
426 continue;
427 }
428 std::unordered_map<std::string, HapResource *> result = HapResource::LoadOverlays(iter->first.c_str(),
429 overlayPaths, resConfig_);
430 if (result.size() == 0) {
431 continue;
432 }
433 for (auto iter = result.begin(); iter != result.end(); iter++) {
434 newResources.push_back(iter->second);
435 }
436 }
437 for (size_t i = 0; i < hapResources_.size(); ++i) {
438 delete (hapResources_[i]);
439 }
440 hapResources_ = newResources;
441 return SUCCESS;
442 }
443
GetResourcePaths()444 std::vector<std::string> HapManager::GetResourcePaths()
445 {
446 std::vector<std::string> result;
447 for (auto iter = hapResources_.rbegin(); iter != hapResources_.rend(); iter++) {
448 std::string indexPath = (*iter)->GetIndexPath();
449 auto index = indexPath.rfind('/');
450 if (index == std::string::npos) {
451 HILOG_ERROR("index path format error, %s", indexPath.c_str());
452 continue;
453 }
454
455 result.emplace_back(indexPath.substr(0, index) + "/resources/");
456 }
457
458 return result;
459 }
460
IsLoadHap()461 bool HapManager::IsLoadHap()
462 {
463 for (auto iter = hapResources_.rbegin(); iter != hapResources_.rend(); iter++) {
464 if ((*iter) == nullptr) {
465 HILOG_ERROR("the hapResource_ is nullptr");
466 return false;
467 }
468 const std::string hapPath = (*iter)->GetIndexPath();
469 if (Utils::ContainsTail(hapPath, Utils::tailSet)) {
470 return true;
471 }
472 }
473 return false;
474 }
475
GetFilePath(const HapResource::ValueUnderQualifierDir * qd,unzFile & uf,const ResType resType)476 std::string GetFilePath(const HapResource::ValueUnderQualifierDir *qd, unzFile &uf, const ResType resType)
477 {
478 std::string filePath;
479 if (qd == nullptr) {
480 return filePath;
481 }
482 const IdItem *idItem = qd->GetIdItem();
483 if (idItem == nullptr || idItem->resType_ != resType) {
484 return filePath;
485 }
486 if (HapParser::IsStageMode(uf)) {
487 std::string tempFilePath(idItem->value_);
488 auto index = tempFilePath.find('/');
489 if (index == std::string::npos) {
490 HILOG_ERROR("resource path format error, %s", tempFilePath.c_str());
491 return filePath;
492 }
493 filePath = idItem->value_.substr(index + 1);
494 } else {
495 // FA mode
496 std::string tempFilePath("assets/");
497 tempFilePath.append(idItem->value_);
498 filePath = tempFilePath;
499 }
500 return filePath;
501 }
502
GetImageType(const std::string fileName)503 std::string GetImageType(const std::string fileName)
504 {
505 auto pos = fileName.find_last_of('.');
506 std::string imgType;
507 if (pos != std::string::npos) {
508 imgType = fileName.substr(pos + 1);
509 }
510 return imgType;
511 }
512
GetHapUf(const HapResource::ValueUnderQualifierDir * qd)513 unzFile GetHapUf(const HapResource::ValueUnderQualifierDir *qd)
514 {
515 std::string hapPath = qd->GetHapResource()->GetIndexPath();
516 unzFile uf = unzOpen64(hapPath.c_str()); // open zipfile stream
517 if (uf == nullptr) {
518 HILOG_ERROR("Open the %{public}s failed in GetHapUf", hapPath.c_str());
519 return nullptr;
520 } // file is open
521 return uf;
522 }
523
GetProfileData(const HapResource::ValueUnderQualifierDir * qd,size_t & len,std::unique_ptr<uint8_t[]> & outValue)524 RState HapManager::GetProfileData(const HapResource::ValueUnderQualifierDir *qd, size_t &len,
525 std::unique_ptr<uint8_t[]> &outValue)
526 {
527 unzFile uf = GetHapUf(qd);
528 if (uf == nullptr) {
529 return NOT_FOUND;
530 }
531 std::string filePath = GetFilePath(qd, uf, ResType::PROF);
532 int err = HapParser::ReadFileFromZip(uf, filePath.c_str(), outValue, len);
533 if (err < 0) {
534 unzClose(uf);
535 return NOT_FOUND;
536 }
537 unzClose(uf);
538 return SUCCESS;
539 }
540
GetMediaData(const HapResource::ValueUnderQualifierDir * qd,size_t & len,std::unique_ptr<uint8_t[]> & outValue)541 RState HapManager::GetMediaData(const HapResource::ValueUnderQualifierDir *qd, size_t &len,
542 std::unique_ptr<uint8_t[]> &outValue)
543 {
544 unzFile uf = GetHapUf(qd);
545 if (uf == nullptr) {
546 return NOT_FOUND;
547 }
548 std::string filePath = GetFilePath(qd, uf, ResType::MEDIA);
549 int err = HapParser::ReadFileFromZip(uf, filePath.c_str(), outValue, len);
550 if (err < 0) {
551 unzClose(uf);
552 return NOT_FOUND;
553 }
554 unzClose(uf);
555 return SUCCESS;
556 }
557
GetMediaBase64Data(const HapResource::ValueUnderQualifierDir * qd,std::string & outValue)558 RState HapManager::GetMediaBase64Data(const HapResource::ValueUnderQualifierDir *qd, std::string &outValue)
559 {
560 unzFile uf = GetHapUf(qd);
561 if (uf == nullptr) {
562 return NOT_FOUND;
563 }
564 std::string filePath = GetFilePath(qd, uf, ResType::MEDIA);
565 std::unique_ptr<uint8_t[]> buffer;
566 size_t tmpLen;
567 int err = HapParser::ReadFileFromZip(uf, filePath.c_str(), buffer, tmpLen);
568 if (err < 0) {
569 unzClose(uf);
570 return NOT_FOUND;
571 }
572 std::string imgType = GetImageType(filePath);
573 Utils::EncodeBase64(buffer, tmpLen, imgType, outValue);
574 unzClose(uf);
575 return SUCCESS;
576 }
577
GetFileFd(const char * zipFile,std::unique_ptr<ResourceManager::RawFile> & rawFile)578 int32_t GetFileFd(const char *zipFile, std::unique_ptr<ResourceManager::RawFile> &rawFile)
579 {
580 int zipFd = open(zipFile, O_RDONLY);
581 if (zipFd < 0) {
582 HILOG_ERROR("open file failed in GetFileFd");
583 return UNKNOWN_ERROR;
584 }
585 FILE *file = fdopen(zipFd, "r");
586 if (file == nullptr) {
587 HILOG_ERROR("fdopen the fd failed in GetFileFd");
588 close(zipFd);
589 return UNKNOWN_ERROR;
590 }
591 rawFile->pf = file;
592 return OK;
593 }
594
FindRawFileFromHap(const std::string & rawFileName,std::unique_ptr<ResourceManager::RawFile> & rawFile)595 RState HapManager::FindRawFileFromHap(const std::string &rawFileName,
596 std::unique_ptr<ResourceManager::RawFile> &rawFile)
597 {
598 if (rawFile == nullptr) {
599 rawFile = std::make_unique<ResourceManager::RawFile>();
600 }
601 const std::string sysResHap = "SystemResources.hap";
602 for (auto iter = hapResources_.rbegin(); iter != hapResources_.rend(); iter++) {
603 const std::string hapPath = (*iter)->GetIndexPath();
604 if (hapPath.find(sysResHap) != std::string::npos) {
605 continue;
606 }
607 if (Utils::ContainsTail(hapPath, Utils::tailSet)) {
608 size_t tmpLen;
609 int32_t ret = HapParser::ReadRawFileFromHap(hapPath.c_str(), rawFile->buffer, tmpLen, rawFileName, rawFile);
610 if (ret != OK) {
611 continue;
612 }
613 ret = GetFileFd(hapPath.c_str(), rawFile);
614 if (ret != OK) {
615 return ERROR_CODE_RES_PATH_INVALID;
616 }
617 rawFile->length = static_cast<long>(tmpLen);
618 return SUCCESS;
619 }
620 }
621 return ERROR_CODE_RES_PATH_INVALID;
622 }
623 } // namespace Resource
624 } // namespace Global
625 } // namespace OHOS
626