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 
16 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMMON_RESOURCE_RESOURCE_MANAGER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMMON_RESOURCE_RESOURCE_MANAGER_H
18 
19 #include <climits>
20 #include <functional>
21 #include <map>
22 #include <mutex>
23 #include <shared_mutex>
24 #include <string>
25 #include <utility>
26 
27 #include "base/memory/ace_type.h"
28 #include "base/memory/referenced.h"
29 #include "base/utils/resource_configuration.h"
30 #include "core/common/resource/resource_object.h"
31 #include "core/components/theme/resource_adapter.h"
32 #include "core/common/lru/count_limit_lru.h"
33 
34 namespace OHOS::Ace {
35 constexpr char DEFAULT_RESOURCE_KEY[] = "";
36 
37 class ACE_FORCE_EXPORT ResourceManager final : public AceType {
38     DECLARE_ACE_TYPE(ResourceManager, AceType);
39 
40 public:
41     ~ResourceManager() = default;
42 
43     static ResourceManager& GetInstance();
44 
45     RefPtr<ResourceAdapter> GetOrCreateResourceAdapter(RefPtr<ResourceObject>& resourceObject);
46 
MakeCacheKey(const std::string & bundleName,const std::string & moduleName)47     std::string MakeCacheKey(const std::string& bundleName, const std::string& moduleName)
48     {
49         if (bundleName.empty() && moduleName.empty()) {
50             return DEFAULT_RESOURCE_KEY;
51         }
52         return bundleName + "." + moduleName;
53     }
54 
55     void AddResourceAdapter(const std::string& bundleName, const std::string& moduleName,
56         RefPtr<ResourceAdapter>& resourceAdapter, bool replace = false)
57     {
58         std::unique_lock<std::shared_mutex> lock(mutex_);
59         if (bundleName.empty() && moduleName.empty()) {
60             resourceAdapters_[DEFAULT_RESOURCE_KEY] = resourceAdapter;
61         } else {
62             auto key = MakeCacheKey(bundleName, moduleName);
63             if (replace) {
64                 CountLimitLRU::RemoveCacheObjFromCountLimitLRU<RefPtr<ResourceAdapter>>(key, cacheList_, cache_);
65             }
66             CountLimitLRU::CacheWithCountLimitLRU<RefPtr<ResourceAdapter>>(
67                 key, resourceAdapter, cacheList_, cache_, capacity_);
68         }
69     }
70 
IsResourceAdapterRecord(const std::string & bundleName,const std::string & moduleName)71     bool IsResourceAdapterRecord(const std::string& bundleName, const std::string& moduleName)
72     {
73         std::shared_lock<std::shared_mutex> lock(mutex_);
74         auto key = MakeCacheKey(bundleName, moduleName);
75         if (resourceAdapters_.find(key) != resourceAdapters_.end()) {
76             return true;
77         }
78         return cache_.find(key) != cache_.end();
79     }
80 
GetResourceAdapter(const std::string & bundleName,const std::string & moduleName)81     RefPtr<ResourceAdapter> GetResourceAdapter(const std::string& bundleName, const std::string& moduleName)
82     {
83         std::unique_lock<std::shared_mutex> lock(mutex_);
84         auto key = MakeCacheKey(bundleName, moduleName);
85         auto mapIter = resourceAdapters_.find(key);
86         if (mapIter != resourceAdapters_.end()) {
87             return mapIter->second;
88         } else if (key == DEFAULT_RESOURCE_KEY) {
89             TAG_LOGW(AceLogTag::ACE_RESOURCE,
90                 "Get default resourceAdapter failed, don't get resource while UIContent not initialized yet");
91             return ResourceAdapter::Create();
92         }
93 
94         auto resAdapter = CountLimitLRU::GetCacheObjWithCountLimitLRU<RefPtr<ResourceAdapter>>(key, cacheList_, cache_);
95         if (resAdapter != nullptr) {
96             return resAdapter;
97         }
98 
99         return nullptr;
100     }
101 
GetResourceAdapter()102     RefPtr<ResourceAdapter> GetResourceAdapter()
103     {
104         std::shared_lock<std::shared_mutex> lock(mutex_);
105         auto key = MakeCacheKey("", "");
106         return resourceAdapters_.at(key);
107     }
108 
109     void UpdateResourceConfig(const ResourceConfiguration& config, bool themeFlag = false)
110     {
111         std::unique_lock<std::shared_mutex> lock(mutex_);
112         for (auto iter = resourceAdapters_.begin(); iter != resourceAdapters_.end(); ++iter) {
113             iter->second->UpdateConfig(config, themeFlag);
114         }
115         for (auto iter = cacheList_.begin(); iter != cacheList_.end(); ++iter) {
116             iter->cacheObj->UpdateConfig(config, themeFlag);
117         }
118     }
119 
RemoveResourceAdapter(const std::string & bundleName,const std::string & moduleName)120     void RemoveResourceAdapter(const std::string& bundleName, const std::string& moduleName)
121     {
122         std::unique_lock<std::shared_mutex> lock(mutex_);
123         std::string key = MakeCacheKey(bundleName, moduleName);
124         if (resourceAdapters_.find(key) != resourceAdapters_.end()) {
125             resourceAdapters_.erase(key);
126         }
127         if (!bundleName.empty() && !moduleName.empty()) {
128             CountLimitLRU::RemoveCacheObjFromCountLimitLRU<RefPtr<ResourceAdapter>>(key, cacheList_, cache_);
129         }
130     }
131 
Reset()132     void Reset()
133     {
134         std::unique_lock<std::shared_mutex> lock(mutex_);
135         cacheList_.clear();
136         cache_.clear();
137         TAG_LOGI(AceLogTag::ACE_RESOURCE, "The cache of Resource has been released!");
138     }
139 
UpdateColorMode(ColorMode colorMode)140     void UpdateColorMode(ColorMode colorMode)
141     {
142         std::unique_lock<std::shared_mutex> lock(mutex_);
143         for (auto iter = resourceAdapters_.begin(); iter != resourceAdapters_.end(); ++iter) {
144             iter->second->UpdateColorMode(colorMode);
145         }
146         for (auto iter = cacheList_.begin(); iter != cacheList_.end(); ++iter) {
147             iter->cacheObj->UpdateColorMode(colorMode);
148         }
149     }
150 
151     void RegisterMainResourceAdapter(
152         const std::string& bundleName, const std::string& moduleName, const RefPtr<ResourceAdapter>& resAdapter);
153 
154 private:
155     ResourceManager() = default;
156 
157     std::unordered_map<std::string, RefPtr<ResourceAdapter>> resourceAdapters_;
158     std::shared_mutex mutex_;
159 
160     std::atomic<size_t> capacity_ = 3;
161     std::list<CacheNode<RefPtr<ResourceAdapter>>> cacheList_;
162     std::unordered_map<std::string, std::list<CacheNode<RefPtr<ResourceAdapter>>>::iterator> cache_;
163 };
164 } // namespace OHOS::Ace
165 
166 #endif