• 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 #include "theme_pack_manager.h"
16 
17 #include "auto_mutex.h"
18 #include <dirent.h>
19 #include <cstdio>
20 #include <cstdlib>
21 #include <cstring>
22 #include "hilog_wrapper.h"
23 #include "theme_pack_resource.h"
24 #include <securec.h>
25 #include "utils/utils.h"
26 
27 namespace OHOS {
28 namespace Global {
29 namespace Resource {
30 constexpr int FIRST_ELEMENT = 0;
31 constexpr int SECOND_ELEMENT = 1;
32 constexpr int THIRED_ELEMENT = 2;
33 static std::shared_ptr<ThemePackManager> themeMgr = nullptr;
34 static std::once_flag themeMgrFlag;
35 constexpr uint32_t SYSTEM_ID_BEGIN = 117440512; // 0x07000000
36 constexpr uint32_t SYSTEM_ID_END = 134217727; // 0x07FFFFFF
37 const std::string themeFlagA = "data/themes/a/app/flag";
38 const std::string themeFlagB = "data/themes/b/app/flag";
39 const std::string themeSkinA = "/data/themes/a/app/skin";
40 const std::string themeSkinB = "/data/themes/b/app/skin";
41 const std::string themeIconsA = "/data/themes/a/app/icons";
42 const std::string themeIconsB = "/data/themes/b/app/icons";
43 const std::string absoluteThemeFlagA = "data/service/el1/public/themes/<currentUserId>/a/app/flag";
44 const std::string absoluteThemeFlagB = "data/service/el1/public/themes/<currentUserId>/b/app/flag";
45 const std::string absoluteThemeSkinA = "/data/service/el1/public/themes/<currentUserId>/a/app/skin";
46 const std::string absoluteThemeSkinB = "/data/service/el1/public/themes/<currentUserId>/b/app/skin";
47 const std::string absoluteThemeIconsA = "/data/service/el1/public/themes/<currentUserId>/a/app/icons";
48 const std::string absoluteThemeIconsB = "/data/service/el1/public/themes/<currentUserId>/b/app/icons";
49 const std::string absoluteThemePath = "/data/service/el1/public/themes/";
ThemePackManager()50 ThemePackManager::ThemePackManager()
51 {}
52 
~ThemePackManager()53 ThemePackManager::~ThemePackManager()
54 {
55     RESMGR_HILOGW_BY_FLAG(isLogFlag_, RESMGR_TAG, "~ThemePackManager");
56     skinResource_.clear();
57     iconResource_.clear();
58     iconMaskValues_.clear();
59 }
60 
GetThemePackManager()61 std::shared_ptr<ThemePackManager> ThemePackManager::GetThemePackManager()
62 {
63     std::call_once(themeMgrFlag, [&] {
64         themeMgr = std::shared_ptr<ThemePackManager>(new ThemePackManager());
65     });
66     return themeMgr;
67 }
68 
GetRootDir(const std::string & strCurrentDir)69 std::vector<std::string> ThemePackManager::GetRootDir(const std::string &strCurrentDir)
70 {
71     std::vector<std::string> vDir;
72 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
73     DIR *dir;
74     struct dirent *pDir;
75     if ((dir = opendir(strCurrentDir.c_str())) == nullptr) {
76         return vDir;
77     }
78     while ((pDir = readdir(dir)) != nullptr) {
79         if (strcmp(pDir->d_name, ".") == 0 || strcmp(pDir->d_name, "..") == 0) {
80             continue;
81         } else if (pDir->d_type == 4) { // 4 means dir
82             std::string strNextDir = strCurrentDir + "/" + pDir->d_name;
83             vDir.emplace_back(strNextDir);
84         } else if (pDir->d_type == 8) { // 8 means file
85             std::string filePath = strCurrentDir + "/" + pDir->d_name;
86             if (filePath.find("icon_mask") != std::string::npos) {
87                 themeMask = filePath;
88             }
89         }
90     }
91     closedir(dir);
92 #endif
93     return vDir;
94 }
95 
ClearSkinResource()96 void ThemePackManager::ClearSkinResource()
97 {
98     for (auto it = skinResource_.begin(); it != skinResource_.end();) {
99         if ((*it) == nullptr) {
100             continue;
101         }
102         // 1 means get the enable theme
103         if (!(*it)->IsNewResource()) {
104             it = skinResource_.erase(it);
105         } else {
106             ++it;
107         }
108     }
109 }
110 
LoadThemeSkinResource(const std::string & bundleName,const std::string & moduleName,const std::vector<std::string> & rootDirs,int32_t userId)111 void ThemePackManager::LoadThemeSkinResource(const std::string &bundleName, const std::string &moduleName,
112     const std::vector<std::string> &rootDirs, int32_t userId)
113 {
114     AutoMutex mutex(this->lockSkin_);
115     ChangeSkinResourceStatus(userId);
116     if (rootDirs.empty()) {
117         ClearSkinResource();
118         return;
119     }
120     for (const auto &dir : rootDirs) {
121         auto pos = dir.rfind('/');
122         if (pos == std::string::npos) {
123             RESMGR_HILOGE(RESMGR_TAG, "invalid dir = %{public}s in LoadThemeSkinResource", dir.c_str());
124             continue;
125         }
126         std::string tempBundleName = dir.substr(pos + 1);
127         if (tempBundleName != bundleName && tempBundleName != "systemRes") {
128             continue;
129         }
130         auto pThemeResource = ThemeResource::LoadThemeResource(dir);
131         if (pThemeResource != nullptr) {
132             this->skinResource_.emplace_back(pThemeResource);
133         }
134     }
135     ClearSkinResource();
136 }
137 
LoadThemeRes(const std::string & bundleName,const std::string & moduleName,int32_t userId)138 void ThemePackManager::LoadThemeRes(const std::string &bundleName, const std::string &moduleName, int32_t userId)
139 {
140     UpdateUserId(userId);
141     std::vector<std::string> rootDirs;
142     std::vector<std::string> iconDirs;
143     if (Utils::IsFileExist(themeFlagA)) {
144         rootDirs = GetRootDir(themeSkinA);
145         iconDirs = GetRootDir(themeIconsA);
146     } else if (Utils::IsFileExist(themeFlagB)) {
147         rootDirs = GetRootDir(themeSkinB);
148         iconDirs = GetRootDir(themeIconsB);
149     } else {
150         isLogFlag_ = true;
151         LoadSAThemeRes(bundleName, moduleName, userId, rootDirs, iconDirs);
152     }
153     LoadThemeSkinResource(bundleName, moduleName, rootDirs, userId);
154     LoadThemeIconsResource(bundleName, moduleName, iconDirs, userId);
155     return;
156 }
157 
LoadSAThemeRes(const std::string & bundleName,const std::string & moduleName,int32_t userId,std::vector<std::string> & rootDirs,std::vector<std::string> & iconDirs)158 void ThemePackManager::LoadSAThemeRes(const std::string &bundleName, const std::string &moduleName,
159     int32_t userId, std::vector<std::string> &rootDirs, std::vector<std::string> &iconDirs)
160 {
161     if (Utils::IsFileExist(ReplaceUserIdInPath(absoluteThemeFlagA, userId))) {
162         rootDirs = GetRootDir(ReplaceUserIdInPath(absoluteThemeSkinA, userId));
163         iconDirs = GetRootDir(ReplaceUserIdInPath(absoluteThemeIconsA, userId));
164     } else if (Utils::IsFileExist(ReplaceUserIdInPath(absoluteThemeFlagB, userId))) {
165         rootDirs = GetRootDir(ReplaceUserIdInPath(absoluteThemeSkinB, userId));
166         iconDirs = GetRootDir(ReplaceUserIdInPath(absoluteThemeIconsB, userId));
167     }
168     return;
169 }
170 
ReplaceUserIdInPath(const std::string & originalPath,int32_t userId)171 const std::string ThemePackManager::ReplaceUserIdInPath(const std::string &originalPath, int32_t userId)
172 {
173     std::string result = originalPath;
174     auto found = result.find("<currentUserId>");
175     if (found != std::string::npos) {
176         result.replace(found, 15, std::to_string(userId)); // 15 is the length of "<currentUserId>"
177     }
178     return result;
179 }
180 
FindThemeResource(const std::pair<std::string,std::string> & bundleInfo,std::vector<std::shared_ptr<IdItem>> idItems,const ResConfigImpl & resConfig,int32_t userId,bool isThemeSystemResEnable)181 const std::string ThemePackManager::FindThemeResource(const std::pair<std::string, std::string> &bundleInfo,
182     std::vector<std::shared_ptr<IdItem>> idItems, const ResConfigImpl &resConfig, int32_t userId,
183     bool isThemeSystemResEnable)
184 {
185     std::string result;
186     for (size_t i = 0; i < idItems.size(); i++) {
187         std::string resName = idItems[i]->GetItemResName();
188         uint32_t id = idItems[i]->GetItemResId();
189         ResType resType = idItems[i]->GetItemResType();
190         if (id >= SYSTEM_ID_BEGIN && id <= SYSTEM_ID_END) {
191             if (resType == ResType::COLOR && !isThemeSystemResEnable) {
192                 break;
193             }
194             std::pair<std::string, std::string> tempInfo("systemRes", "entry");
195             result = GetThemeResource(tempInfo, resType, resName, resConfig, userId);
196         } else {
197             result = GetThemeResource(bundleInfo, resType, resName, resConfig, userId);
198         }
199         if (!result.empty()) {
200             break;
201         }
202     }
203     return result;
204 }
205 
GetThemeResource(const std::pair<std::string,std::string> & bundInfo,const ResType & resType,const std::string & resName,const ResConfigImpl & resConfig,int32_t userId)206 const std::string ThemePackManager::GetThemeResource(const std::pair<std::string, std::string> &bundInfo,
207     const ResType &resType, const std::string &resName, const ResConfigImpl &resConfig, int32_t userId)
208 {
209     auto themeQualifierValue = GetThemeQualifierValue(bundInfo, resType, resName, resConfig, userId);
210     if (themeQualifierValue == nullptr) {
211         RESMGR_HILOGD(RESMGR_TAG, "themeQualifierValue == nullptr");
212         return std::string("");
213     }
214     return themeQualifierValue->GetResValue();
215 }
216 
GetThemeResourceList(const std::pair<std::string,std::string> & bundInfo,const ResType & resType,const std::string & resName,int32_t userId)217 std::vector<std::shared_ptr<ThemeResource::ThemeValue> > ThemePackManager::GetThemeResourceList(
218     const std::pair<std::string, std::string> &bundInfo, const ResType &resType, const std::string &resName,
219     int32_t userId)
220 {
221     AutoMutex mutex(this->lockSkin_);
222     std::vector<std::shared_ptr<ThemeResource::ThemeValue> > result;
223     for (size_t i = 0; i < skinResource_.size(); ++i) {
224         auto pThemeResource = skinResource_[i];
225         if (pThemeResource == nullptr) {
226             continue;
227         }
228         if (!IsSameResourceByUserId(pThemeResource->GetThemePath(), userId)) {
229             continue;
230         }
231         std::string bundleName = pThemeResource->GetThemeResBundleName(pThemeResource->themePath_);
232         if (bundleName != bundInfo.first) {
233             continue;
234         }
235         result = pThemeResource->GetThemeValues(bundInfo, resType, resName);
236     }
237     return result;
238 }
239 
GetThemeQualifierValue(const std::pair<std::string,std::string> & bundInfo,const ResType & resType,const std::string & resName,const ResConfigImpl & resConfig,int32_t userId)240 const std::shared_ptr<ThemeResource::ThemeQualifierValue> ThemePackManager::GetThemeQualifierValue(
241     const std::pair<std::string, std::string> &bundInfo, const ResType &resType,
242     const std::string &resName, const ResConfigImpl &resConfig, int32_t userId)
243 {
244     auto candidates = this->GetThemeResourceList(bundInfo, resType, resName, userId);
245     if (candidates.size() == 0) {
246         return nullptr;
247     }
248     return GetBestMatchThemeResource(candidates, resConfig);
249 }
250 
GetBestMatchThemeResource(const std::vector<std::shared_ptr<ThemeResource::ThemeValue>> & candidates,const ResConfigImpl & resConfig)251 const std::shared_ptr<ThemeResource::ThemeQualifierValue> ThemePackManager::GetBestMatchThemeResource(
252     const std::vector<std::shared_ptr<ThemeResource::ThemeValue> > &candidates, const ResConfigImpl &resConfig)
253 {
254     std::shared_ptr<ThemeResource::ThemeQualifierValue> result = nullptr;
255     std::shared_ptr<ThemeConfig> bestThemeConfig = nullptr;
256     for (auto iter = candidates.rbegin(); iter != candidates.rend(); iter++) {
257         const std::vector<std::shared_ptr<ThemeResource::ThemeQualifierValue> > ThemePaths =
258             (*iter)->GetThemeLimitPathsConst();
259         size_t len = ThemePaths.size();
260         for (size_t i = 0; i < len; i++) {
261             std::shared_ptr<ThemeResource::ThemeQualifierValue> path = ThemePaths[i];
262             auto themeConfig = path->GetThemeConfig();
263             if (!ThemeConfig::Match(themeConfig, resConfig)) {
264                 continue;
265             }
266             if (bestThemeConfig == nullptr) {
267                 bestThemeConfig = themeConfig;
268                 result = path;
269                 continue;
270             }
271             if (!bestThemeConfig->BestMatch(themeConfig, resConfig)) {
272                 bestThemeConfig = themeConfig;
273                 result = path;
274             }
275         }
276     }
277     return result;
278 }
279 
ClearIconResource()280 void ThemePackManager::ClearIconResource()
281 {
282     for (auto it = iconResource_.begin(); it != iconResource_.end();) {
283         if ((*it) == nullptr) {
284             continue;
285         }
286         // 1 means get the enable theme
287         if (!(*it)->IsNewResource()) {
288             it = iconResource_.erase(it);
289         } else {
290             ++it;
291         }
292     }
293     iconMaskValues_.clear();
294 }
295 
LoadThemeIconsResource(const std::string & bundleName,const std::string & moduleName,const std::vector<std::string> & rootDirs,int32_t userId)296 void ThemePackManager::LoadThemeIconsResource(const std::string &bundleName, const std::string &moduleName,
297     const std::vector<std::string> &rootDirs, int32_t userId)
298 {
299     AutoMutex mutex(this->lockIcon_);
300     ChangeIconResourceStatus(userId);
301     if (rootDirs.empty()) {
302         ClearIconResource();
303         return;
304     }
305     for (const auto &dir : rootDirs) {
306         auto pos = dir.rfind('/');
307         if (pos == std::string::npos) {
308             RESMGR_HILOGE(RESMGR_TAG, "invalid dir = %{public}s in LoadThemeIconsResource", dir.c_str());
309             continue;
310         }
311         RESMGR_HILOGW_BY_FLAG(isLogFlag_, RESMGR_TAG, "load img, %{public}s", GetMaskString(dir).c_str());
312         auto pThemeResource = ThemeResource::LoadThemeIconResource(dir);
313         if (pThemeResource != nullptr) {
314             this->iconResource_.emplace_back(pThemeResource);
315         }
316     }
317     RESMGR_HILOGW_BY_FLAG(isLogFlag_, RESMGR_TAG, "load img end, size is %{public}zu", iconResource_.size());
318     ClearIconResource();
319 }
320 
FindThemeIconResource(const std::pair<std::string,std::string> & bundleInfo,const std::string & iconName,int32_t userId,const std::string & abilityName)321 const std::string ThemePackManager::FindThemeIconResource(const std::pair<std::string, std::string> &bundleInfo,
322     const std::string &iconName, int32_t userId, const std::string &abilityName)
323 {
324     AutoMutex mutex(this->lockIcon_);
325     std::string result;
326     for (size_t i = 0; i < iconResource_.size(); i++) {
327         auto pThemeResource = iconResource_[i];
328         if (pThemeResource == nullptr) {
329             continue;
330         }
331         if (!IsSameResourceByUserId(pThemeResource->GetThemePath(), userId)) {
332             continue;
333         }
334         result = pThemeResource->GetThemeAppIcon(bundleInfo, iconName, abilityName);
335         if (!result.empty()) {
336             RESMGR_HILOGW_BY_FLAG(isLogFlag_, RESMGR_TAG, "find img, %{public}s", GetMaskString(result).c_str());
337             break;
338         }
339     }
340     return result;
341 }
342 
UpdateThemeId(uint32_t newThemeId)343 bool ThemePackManager::UpdateThemeId(uint32_t newThemeId)
344 {
345     AutoMutex mutex(this->lockThemeId_);
346     if (newThemeId != 0 && newThemeId != themeId_) {
347         RESMGR_HILOGW(RESMGR_TAG, "update theme, themeId_= %{public}d, newThemeId= %{public}d", themeId_, newThemeId);
348         themeId_ = newThemeId;
349         return true;
350     }
351     return false;
352 }
353 
IsFirstLoadResource()354 bool ThemePackManager::IsFirstLoadResource()
355 {
356     if (isFirstCreate) {
357         isFirstCreate = false;
358         return true;
359     }
360     return false;
361 }
362 
HasIconInTheme(const std::string & bundleName,int32_t userId)363 bool ThemePackManager::HasIconInTheme(const std::string &bundleName, int32_t userId)
364 {
365     AutoMutex mutex(this->lockIcon_);
366     bool result = false;
367     for (size_t i = 0; i < iconResource_.size(); i++) {
368         auto pThemeResource = iconResource_[i];
369         if (pThemeResource == nullptr) {
370             continue;
371         }
372         if (!IsSameResourceByUserId(pThemeResource->GetThemePath(), userId)) {
373             continue;
374         }
375         result = pThemeResource->HasIconInTheme(bundleName);
376         if (result) {
377             break;
378         }
379     }
380     return result;
381 }
382 
GetOtherIconsInfo(const std::string & iconName,std::unique_ptr<uint8_t[]> & outValue,size_t & len,bool isGlobalMask,int32_t userId)383 RState ThemePackManager::GetOtherIconsInfo(const std::string &iconName,
384     std::unique_ptr<uint8_t[]> &outValue, size_t &len, bool isGlobalMask, int32_t userId)
385 {
386     AutoMutex mutex(this->lockIconValue_);
387     std::string iconPath;
388     std::string iconTag;
389     if (iconName.find("icon_mask") != std::string::npos && isGlobalMask) {
390         iconPath = themeMask;
391         iconTag = "global_" + iconName;
392     } else {
393         std::pair<std::string, std::string> bundleInfo;
394         bundleInfo.first = "other_icons";
395         iconPath = FindThemeIconResource(bundleInfo, iconName, userId);
396         iconTag = "other_icons_" + iconName;
397     }
398 
399     if (iconPath.empty()) {
400         RESMGR_HILOGE(RESMGR_TAG, "no found, iconName = %{public}s", iconName.c_str());
401         return ERROR_CODE_RES_NOT_FOUND_BY_NAME;
402     }
403 
404     outValue = Utils::LoadResourceFile(iconPath, len);
405     if (outValue != nullptr && len != 0) {
406         auto tmpInfo = std::make_unique<uint8_t[]>(len);
407         errno_t ret = memcpy_s(tmpInfo.get(), len, outValue.get(), len);
408         if (ret != 0) {
409             RESMGR_HILOGE(RESMGR_TAG, "save fail, iconName = %{public}s, ret = %{public}d", iconName.c_str(), ret);
410             return SUCCESS;
411         }
412         iconMaskValues_.emplace_back(std::make_tuple(iconTag, std::move(tmpInfo), len));
413         return SUCCESS;
414     }
415     return ERROR_CODE_RES_NOT_FOUND_BY_NAME;
416 }
417 
GetThemeIconFromCache(const std::string & iconTag,std::unique_ptr<uint8_t[]> & outValue,size_t & len)418 RState ThemePackManager::GetThemeIconFromCache(
419     const std::string &iconTag, std::unique_ptr<uint8_t[]> &outValue, size_t &len)
420 {
421     AutoMutex mutex(this->lockIconValue_);
422     if (iconMaskValues_.empty()) {
423         return NOT_FOUND;
424     }
425 
426     for (const auto &iconValue : iconMaskValues_) {
427         std::string tag = std::get<FIRST_ELEMENT>(iconValue);
428         if (iconTag != tag) {
429             continue;
430         }
431         size_t length = std::get<THIRED_ELEMENT>(iconValue);
432         auto iconInfo = std::make_unique<uint8_t[]>(length);
433         auto tmpInfo = std::get<SECOND_ELEMENT>(iconValue).get();
434         errno_t ret = memcpy_s(iconInfo.get(), length, tmpInfo, length);
435         if (ret != 0) {
436             RESMGR_HILOGE(RESMGR_TAG, "get icon info fail, ret = %{public}d", ret);
437             continue;
438         }
439         len = length;
440         outValue = std::move(iconInfo);
441         return SUCCESS;
442     }
443     return NOT_FOUND;
444 }
445 
IsUpdateByUserId(int32_t userId)446 bool ThemePackManager::IsUpdateByUserId(int32_t userId)
447 {
448     AutoMutex mutex(this->lockUserId_);
449     return userId != 0 && currentUserId_ != userId;
450 }
451 
UpdateUserId(int32_t userId)452 void ThemePackManager::UpdateUserId(int32_t userId)
453 {
454     AutoMutex mutex(this->lockUserId_);
455     if (userId != 0 && currentUserId_ != userId) {
456         RESMGR_HILOGW(RESMGR_TAG,
457             "update userId, currentUserId_= %{public}d, userId= %{public}d", currentUserId_, userId);
458         currentUserId_ = userId;
459     }
460 }
461 
IsSameResourceByUserId(const std::string & path,int32_t userId)462 bool ThemePackManager::IsSameResourceByUserId(const std::string &path, int32_t userId)
463 {
464     std::string absolutePath("/data/service/el1/public/themes/");
465     if (path.empty() || path.find(absolutePath) == std::string::npos) {
466         return true;
467     }
468     auto pos = path.find("/", absolutePath.length());
469     if (pos == std::string::npos) {
470         return true;
471     }
472     auto subStr = path.substr(absolutePath.length(), pos - absolutePath.length());
473     int tmpId = -1;
474     if (!Utils::convertToInteger(subStr, tmpId)) {
475         return true;
476     }
477     return tmpId == userId;
478 }
479 
ChangeSkinResourceStatus(int32_t userId)480 void ThemePackManager::ChangeSkinResourceStatus(int32_t userId)
481 {
482     for (size_t i = 0; i < skinResource_.size(); ++i) {
483         auto pThemeResource = skinResource_[i];
484         if (pThemeResource == nullptr) {
485             continue;
486         }
487         if (IsSameResourceByUserId(pThemeResource->GetThemePath(), userId)) {
488             pThemeResource->SetNewResource(false);
489         }
490     }
491 }
492 
ChangeIconResourceStatus(int32_t userId)493 void ThemePackManager::ChangeIconResourceStatus(int32_t userId)
494 {
495     for (size_t i = 0; i < iconResource_.size(); ++i) {
496         auto pThemeResource = iconResource_[i];
497         if (pThemeResource == nullptr) {
498             continue;
499         }
500         if (IsSameResourceByUserId(pThemeResource->GetThemePath(), userId)) {
501             pThemeResource->SetNewResource(false);
502         }
503     }
504 }
505 
GetMaskString(const std::string & path)506 const std::string ThemePackManager::GetMaskString(const std::string &path)
507 {
508     if (path.empty() || path.find(absoluteThemePath) == std::string::npos) {
509         return path;
510     }
511     return path.substr(absoluteThemePath.length(), path.length() - absoluteThemePath.length());
512 }
513 } // namespace Resource
514 } // namespace Global
515 } // namespace OHOS
516