1 /*
2 * Copyright (c) 2025 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
16 #include "hap_resource_v1.h"
17
18 #include <algorithm>
19 #include <climits>
20 #include <cstdlib>
21 #include <fstream>
22 #include "utils/utils.h"
23 #include <set>
24 #ifdef __WINNT__
25 #include <shlwapi.h>
26 #include <windows.h>
27 #undef GetLocaleInfo
28 #endif
29
30 #ifdef __LINUX__
31 #include <cstring>
32 #endif
33
34 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
35 #include "hitrace_meter.h"
36 #include "file_mapper.h"
37 #include "extractor.h"
38 #endif
39
40 #include "hap_parser_v1.h"
41 #include "hap_resource_manager.h"
42 #include "hilog_wrapper.h"
43 #include "utils/errors.h"
44
45 using ReadLock = std::shared_lock<std::shared_mutex>;
46 using WriteLock = std::unique_lock<std::shared_mutex>;
47
48 namespace OHOS {
49 namespace Global {
50 namespace Resource {
ValueUnderQualifierDirV1(const std::shared_ptr<ResKey> & resKey,const std::shared_ptr<IdItem> & idItem,const std::pair<std::string,std::string> & resPath,bool isOverlay,bool systemResource)51 ValueUnderQualifierDirV1::ValueUnderQualifierDirV1(const std::shared_ptr<ResKey> &resKey,
52 const std::shared_ptr<IdItem> &idItem, const std::pair<std::string, std::string> &resPath, bool isOverlay,
53 bool systemResource) : ValueUnderQualifierDir(resPath, resKey->resConfig_, isOverlay, systemResource),
54 idItem_(idItem)
55 {}
56
~ValueUnderQualifierDirV1()57 ValueUnderQualifierDirV1::~ValueUnderQualifierDirV1()
58 {}
59
GetIdItem() const60 std::shared_ptr<IdItem> ValueUnderQualifierDirV1::GetIdItem() const
61 {
62 return idItem_;
63 }
64
~IdValuesV1()65 IdValuesV1::~IdValuesV1()
66 {}
67
GetLimitPathsConst() const68 const std::vector<std::shared_ptr<ValueUnderQualifierDir>> &IdValuesV1::GetLimitPathsConst() const
69 {
70 return limitPaths_;
71 }
72
HapResourceV1(const std::string path,time_t lastModTime,std::shared_ptr<ResDesc> resDes,bool isSystem,bool isOverlay)73 HapResourceV1::HapResourceV1(const std::string path, time_t lastModTime, std::shared_ptr<ResDesc> resDes,
74 bool isSystem, bool isOverlay) : HapResource(path, lastModTime), resDesc_(resDes),
75 isSystem_(isSystem), isOverlay_(isOverlay)
76 {}
77
~HapResourceV1()78 HapResourceV1::~HapResourceV1()
79 {}
80
Init(std::shared_ptr<ResConfigImpl> & defaultConfig)81 bool HapResourceV1::Init(std::shared_ptr<ResConfigImpl> &defaultConfig)
82 {
83 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
84 HITRACE_METER_NAME_EX(HITRACE_LEVEL_INFO, HITRACE_TAG_APP, __PRETTY_FUNCTION__, nullptr);
85 #endif
86 #ifdef __WINNT__
87 char separator = '\\';
88 #else
89 char separator = '/';
90 #endif
91 auto index = indexPath_.rfind(separator);
92 if (index == std::string::npos) {
93 RESMGR_HILOGE(RESMGR_TAG, "index path format error");
94 return false;
95 }
96 #if defined(__IDE_PREVIEW__) || defined(__ARKUI_CROSS__)
97 resourcePath_ = indexPath_.substr(0, index + 1);
98 #else
99 if (index < 1) {
100 return false;
101 }
102 index = indexPath_.rfind(separator, index - 1);
103 if (index == std::string::npos) {
104 RESMGR_HILOGE(RESMGR_TAG, "index path format error");
105 return false;
106 }
107 resourcePath_ = indexPath_.substr(0, index + 1);
108 #endif
109 for (int i = 0; i < ResType::MAX_RES_TYPE; ++i) {
110 auto mptr = std::make_shared<std::map<std::string, std::shared_ptr<IdValuesV1>>>();
111 idValuesNameMap_.push_back(mptr);
112 }
113 WriteLock lock(mutex_);
114 return InitIdList(defaultConfig);
115 }
116
IsSystemResource() const117 bool HapResourceV1::IsSystemResource() const
118 {
119 return isSystem_;
120 }
121
IsOverlayResource() const122 bool HapResourceV1::IsOverlayResource() const
123 {
124 return isOverlay_;
125 }
126
GetIdValues(const uint32_t id)127 const std::shared_ptr<IdValues> HapResourceV1::GetIdValues(const uint32_t id)
128 {
129 ReadLock lock(mutex_);
130 if (idValuesMap_.empty()) {
131 RESMGR_HILOGE(RESMGR_TAG, "idValuesMap_ is empty");
132 return nullptr;
133 }
134 uint32_t uid = id;
135 std::map<uint32_t, std::shared_ptr<IdValuesV1>>::const_iterator iter = idValuesMap_.find(uid);
136 if (iter == idValuesMap_.end()) {
137 return nullptr;
138 }
139 return iter->second;
140 }
141
GetIdValuesByName(const std::string name,const ResType resType)142 const std::shared_ptr<IdValues> HapResourceV1::GetIdValuesByName(
143 const std::string name, const ResType resType)
144 {
145 ReadLock lock(mutex_);
146 const auto map = idValuesNameMap_[resType];
147 std::map<std::string, std::shared_ptr<IdValuesV1>>::const_iterator iter = map->find(name);
148 if (iter == map->end()) {
149 return nullptr;
150 }
151 return iter->second;
152 }
153
Update(std::shared_ptr<ResConfigImpl> & defaultConfig)154 RState HapResourceV1::Update(std::shared_ptr<ResConfigImpl> &defaultConfig)
155 {
156 return this->UpdateResConfig(defaultConfig);
157 }
158
BuildNameTypeIdMapping()159 std::unordered_map<std::string, std::unordered_map<ResType, uint32_t>> HapResourceV1::BuildNameTypeIdMapping()
160 {
161 ReadLock lock(mutex_);
162 std::unordered_map<std::string, std::unordered_map<ResType, uint32_t>> result;
163 for (auto iter = idValuesMap_.begin(); iter != idValuesMap_.end(); iter++) {
164 const std::vector<std::shared_ptr<ValueUnderQualifierDir>> &limitPaths = iter->second->GetLimitPathsConst();
165 if (limitPaths.size() > 0) {
166 std::shared_ptr<ValueUnderQualifierDirV1> value =
167 std::static_pointer_cast<ValueUnderQualifierDirV1>(limitPaths[0]);
168 result[value->idItem_->name_][value->idItem_->resType_] = value->idItem_->id_;
169 }
170 }
171 return result;
172 }
173
GetLocales(std::set<std::string> & outValue,bool includeSystem)174 void HapResourceV1::GetLocales(std::set<std::string> &outValue, bool includeSystem)
175 {
176 ReadLock lock(mutex_);
177 if (resDesc_ == nullptr) {
178 RESMGR_HILOGE(RESMGR_TAG, "resDesc_ is null! GetLocales failed");
179 return;
180 }
181 if ((!includeSystem && isSystem_) || (!isSystem_ && isOverlay_)) {
182 return;
183 }
184 outValue.insert(locales_.begin(), locales_.end());
185 }
186
UpdateOverlayInfo(std::unordered_map<std::string,std::unordered_map<ResType,uint32_t>> & nameTypeId)187 void HapResourceV1::UpdateOverlayInfo(
188 std::unordered_map<std::string, std::unordered_map<ResType, uint32_t>> &nameTypeId)
189 {
190 WriteLock lock(mutex_);
191 std::map<uint32_t, std::shared_ptr<IdValuesV1>> newIdValuesMap;
192 for (auto iter = idValuesMap_.begin(); iter != idValuesMap_.end(); iter++) {
193 const std::vector<std::shared_ptr<ValueUnderQualifierDir>> &limitPaths = iter->second->GetLimitPathsConst();
194 if (limitPaths.size() > 0) {
195 std::shared_ptr<ValueUnderQualifierDirV1> value =
196 std::static_pointer_cast<ValueUnderQualifierDirV1>(limitPaths[0]);
197 std::string name = value->idItem_->name_;
198 ResType type = value->idItem_->resType_;
199 if (nameTypeId.find(name) == nameTypeId.end()) {
200 continue;
201 }
202 auto &typeId = nameTypeId[name];
203 if (typeId.find(type) == typeId.end()) {
204 continue;
205 }
206 uint32_t newId = typeId[type];
207 for_each(limitPaths.begin(), limitPaths.end(), [&](auto &item) {
208 item->GetIdItem()->id_ = newId;
209 });
210 newIdValuesMap[newId] = iter->second;
211 }
212 }
213 idValuesMap_.swap(newIdValuesMap);
214 }
215
InitIdList(std::shared_ptr<ResConfigImpl> & defaultConfig)216 bool HapResourceV1::InitIdList(std::shared_ptr<ResConfigImpl> &defaultConfig)
217 {
218 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
219 HITRACE_METER_NAME_EX(HITRACE_LEVEL_INFO, HITRACE_TAG_APP, __PRETTY_FUNCTION__, nullptr);
220 #endif
221 if (resDesc_ == nullptr) {
222 RESMGR_HILOGE(RESMGR_TAG, "resDesc_ is null ! InitIdList failed");
223 return false;
224 }
225 const auto resPath = std::make_pair(indexPath_, resourcePath_);
226 for (size_t i = 0; i < resDesc_->keys_.size(); i++) {
227 const auto resKey = resDesc_->keys_[i];
228 if (!InitMap(resKey, resPath, defaultConfig)) {
229 return false;
230 }
231 }
232 #ifdef SUPPORT_GRAPHICS
233 if (defaultConfig && (defaultConfig->GetPreferredLocaleInfo() || defaultConfig->GetLocaleInfo())) {
234 std::shared_ptr<ResConfigImpl> currentConfig = std::make_shared<ResConfigImpl>();
235 currentConfig->Copy(*defaultConfig);
236 loadedConfig_.insert(currentConfig);
237 }
238 #endif
239 return true;
240 };
241
InitMap(const std::shared_ptr<ResKey> & resKey,const std::pair<std::string,std::string> & resPath,std::shared_ptr<ResConfigImpl> & defaultConfig)242 bool HapResourceV1::InitMap(const std::shared_ptr<ResKey> &resKey, const std::pair<std::string, std::string> &resPath,
243 std::shared_ptr<ResConfigImpl> &defaultConfig)
244 {
245 for (size_t j = 0; j < resKey->resId_->idParams_.size(); ++j) {
246 std::shared_ptr<IdParam> idParam = resKey->resId_->idParams_[j];
247 uint32_t id = idParam->id_;
248 std::map<uint32_t, std::shared_ptr<IdValuesV1>>::iterator iter = idValuesMap_.find(id);
249 if (iter == idValuesMap_.end()) {
250 auto idValues = std::make_shared<IdValuesV1>();
251 if (idValues == nullptr) {
252 RESMGR_HILOGE(RESMGR_TAG, "new IdValues failed in HapResource::InitIdList");
253 return false;
254 }
255 auto limitPath = std::make_shared<ValueUnderQualifierDirV1>(resKey,
256 idParam->idItem_, resPath, isOverlay_, isSystem_);
257 if (limitPath == nullptr) {
258 RESMGR_HILOGE(RESMGR_TAG, "new ValueUnderQualifierDir failed in HapResource::InitIdList");
259 return false;
260 }
261 idValues->AddLimitPath(limitPath);
262 IsAppDarkRes(limitPath, defaultConfig);
263 idValuesMap_.insert(std::make_pair(id, idValues));
264 std::string name = std::string(idParam->idItem_->name_);
265 idValuesNameMap_[idParam->idItem_->resType_]->insert(std::make_pair(name, idValues));
266 if (name == "system_color_change" && idParam->idItem_->value_ == "true") {
267 isThemeSystemResEnable_ = true;
268 }
269 } else {
270 std::shared_ptr<IdValuesV1> idValues = iter->second;
271 auto limitPath = std::make_shared<ValueUnderQualifierDirV1>(resKey,
272 idParam->idItem_, resPath, isOverlay_, isSystem_);
273 if (limitPath == nullptr) {
274 RESMGR_HILOGE(RESMGR_TAG, "new ValueUnderQualifierDir failed in HapResource::InitIdList");
275 return false;
276 }
277 idValues->AddLimitPath(limitPath);
278 IsAppDarkRes(limitPath, defaultConfig);
279 }
280 }
281 return true;
282 }
283
IsAppDarkRes(const std::shared_ptr<ValueUnderQualifierDir> & limitPath,std::shared_ptr<ResConfigImpl> & defaultConfig)284 void HapResourceV1::IsAppDarkRes(const std::shared_ptr<ValueUnderQualifierDir> &limitPath,
285 std::shared_ptr<ResConfigImpl> &defaultConfig)
286 {
287 if (!defaultConfig) {
288 return;
289 }
290 if (isSystem_ || isOverlay_ || defaultConfig->GetAppDarkRes()) {
291 return;
292 }
293
294 if (limitPath->GetResConfig()->GetColorMode() == ColorMode::DARK) {
295 defaultConfig->SetAppDarkRes(true);
296 hasDarkRes_ = true;
297 }
298 }
299
UpdateResConfig(std::shared_ptr<ResConfigImpl> & defaultConfig)300 RState HapResourceV1::UpdateResConfig(std::shared_ptr<ResConfigImpl> &defaultConfig)
301 {
302 if (isSystem_ || isOverlay_ || !defaultConfig) {
303 return SUCCESS;
304 }
305 #ifdef SUPPORT_GRAPHICS
306 if (!defaultConfig->GetPreferredLocaleInfo() && !defaultConfig->GetLocaleInfo()) {
307 return SUCCESS;
308 }
309 #endif
310 WriteLock lock(mutex_);
311 for (auto &config : loadedConfig_) {
312 if (defaultConfig->MatchLocal(*config)) {
313 return SUCCESS;
314 }
315 }
316
317 HapParserV1 hapParser(defaultConfig, selectedTypes_, false, true);
318 resDesc_ = std::make_shared<ResDesc>();
319 hapParser.SetResDesc(resDesc_);
320 if (!hapParser.Init(indexPath_.c_str())) {
321 return HAP_INIT_FAILED;
322 }
323 if (!InitIdList(defaultConfig)) {
324 return HAP_INIT_FAILED;
325 }
326 return SUCCESS;
327 }
328 }
329 }
330 }