1 /*
2 * Copyright (c) 2021 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 "base/resource/shared_image_manager.h"
17
18 #include "base/utils/utils.h"
19
20 namespace OHOS::Ace {
21 namespace {
22
23 constexpr uint32_t DELAY_TIME_FOR_IMAGE_DATA_CLEAN = 30000;
24 constexpr char MEMORY_IMAGE_HEAD[] = "memory://";
25
26 constexpr size_t MAX_SIZE_FOR_TOTAL_IMAGE = 10000000;
27
28 } // namespace
29
GenerateClearImageDataCallback(const std::string & name,size_t dataSize)30 std::function<void()> SharedImageManager::GenerateClearImageDataCallback(const std::string& name, size_t dataSize)
31 {
32 auto clearImageDataCallback = [wp = AceType::WeakClaim(this), picName = name, dataSize]() {
33 auto sharedImageManager = wp.Upgrade();
34 if (!sharedImageManager) {
35 return;
36 }
37 {
38 std::lock_guard<std::mutex> lockImageMap(sharedImageManager->sharedImageMapMutex_);
39 sharedImageManager->sharedImageMap_.erase(picName);
40 }
41 {
42 std::lock_guard<std::mutex> lockCancelableCallbackMap_(sharedImageManager->cancelableCallbackMapMutex_);
43 std::lock_guard<std::mutex> lockImageMap(sharedImageManager->sharedImageMapMutex_);
44 LOGW("clear image cache name: %{public}s", picName.c_str());
45 sharedImageManager->sharedImageTotalSize_ -= dataSize;
46 sharedImageManager->cancelableCallbackMap_.erase(picName);
47 }
48 };
49 return clearImageDataCallback;
50 }
51
PostDelayedTaskToClearImageData(const std::string & name,size_t dataSize)52 void SharedImageManager::PostDelayedTaskToClearImageData(const std::string& name, size_t dataSize)
53 {
54 auto taskExecutor = taskExecutor_.Upgrade();
55 CHECK_NULL_VOID(taskExecutor);
56 std::lock_guard<std::mutex> lockCancelableCallbackMap_(cancelableCallbackMapMutex_);
57 auto& cancelableCallback = cancelableCallbackMap_[name];
58 cancelableCallback.Reset(GenerateClearImageDataCallback(name, dataSize));
59 auto bkTask = [wp = taskExecutor_, cancelableCallback]() {
60 auto taskExecutor = wp.Upgrade();
61 CHECK_NULL_VOID(taskExecutor);
62 taskExecutor->PostTask(
63 cancelableCallback, TaskExecutor::TaskType::BACKGROUND, "ArkUIImageClearSharedImageData");
64 };
65 taskExecutor->PostDelayedTask(
66 bkTask, TaskExecutor::TaskType::UI, DELAY_TIME_FOR_IMAGE_DATA_CLEAN, "ArkUIImageClearSharedImageData");
67 }
68
AddSharedImage(const std::string & name,SharedImage && sharedImage)69 void SharedImageManager::AddSharedImage(const std::string& name, SharedImage&& sharedImage)
70 {
71 std::set<WeakPtr<ImageProviderLoader>> providerWpSet = std::set<WeakPtr<ImageProviderLoader>>();
72 // step1: lock provider map to search for record of current picture name
73 std::scoped_lock lock(providerMapMutex_, sharedImageMapMutex_);
74 auto providersToNotify = providerMapToReload_.find(name);
75 if (providersToNotify != providerMapToReload_.end()) {
76 for (const auto& providerWp : providersToNotify->second) {
77 auto provider = providerWp.Upgrade();
78 if (!provider) {
79 continue;
80 }
81 providerWpSet.emplace(provider);
82 }
83 providerMapToReload_.erase(providersToNotify);
84 }
85 // step2: lock image map to add shared image and notify [LazyMemoryImageProvider]s to update data and reload
86 // update image data when the name can be found in map
87 bool isClear = UpdateImageMap(name, sharedImage);
88 auto taskExecutor = taskExecutor_.Upgrade();
89 CHECK_NULL_VOID(taskExecutor);
90 taskExecutor->PostTask(
91 [isClear, providerWpSet, name, wp = AceType::WeakClaim(this)]() {
92 auto sharedImageManager = wp.Upgrade();
93 CHECK_NULL_VOID(sharedImageManager);
94 size_t dataSize = 0;
95 {
96 std::lock_guard<std::mutex> lockImageMap(sharedImageManager->sharedImageMapMutex_);
97 auto sharedImageMap = sharedImageManager->GetSharedImageMap();
98 auto imageDataIter = sharedImageMap.find(name);
99 if (imageDataIter == sharedImageMap.end()) {
100 LOGW("fail to find data of %{public}s in sharedImageMap, stop UpdateData", name.c_str());
101 return;
102 }
103 dataSize = imageDataIter->second.size();
104 for (const auto& providerWp : providerWpSet) {
105 auto provider = providerWp.Upgrade();
106 if (!provider) {
107 continue;
108 }
109 provider->UpdateData(std::string(MEMORY_IMAGE_HEAD).append(name), imageDataIter->second);
110 }
111 }
112 if (isClear) {
113 sharedImageManager->PostDelayedTaskToClearImageData(name, dataSize);
114 }
115 },
116 TaskExecutor::TaskType::UI, "ArkUIImageAddSharedImageData");
117 }
118
UpdateImageMap(const std::string & name,const SharedImage & sharedImage)119 bool SharedImageManager::UpdateImageMap(const std::string& name, const SharedImage& sharedImage)
120 {
121 bool isClear = false;
122 auto iter = sharedImageMap_.find(name);
123 if (iter != sharedImageMap_.end()) {
124 sharedImageTotalSize_ -= iter->second.size();
125 sharedImageTotalSize_ += sharedImage.size();
126 iter->second = sharedImage;
127 } else {
128 sharedImageTotalSize_ += sharedImage.size();
129 sharedImageMap_.emplace(name, sharedImage);
130 if (static_cast<int>(sharedImageMap_.size()) > sharedImageCacheThreshold_) {
131 LOGW("will clear %{public}s cache, sharedImageMap_ size %{public}d max cache: %{public}d",
132 name.c_str(), static_cast<int>(sharedImageMap_.size()), sharedImageCacheThreshold_);
133 isClear = true;
134 }
135 }
136 if (sharedImageTotalSize_ > MAX_SIZE_FOR_TOTAL_IMAGE) {
137 LOGW("will clear %{public}s cache, sharedImageTotalSize_ size %{public}d",
138 name.c_str(), static_cast<int32_t>(sharedImageTotalSize_));
139 isClear = true;
140 }
141 return isClear;
142 }
143
AddPictureNamesToReloadMap(std::string && name)144 void SharedImageManager::AddPictureNamesToReloadMap(std::string&& name)
145 {
146 // add names of memory image to be read from shared memory
147 std::lock_guard<std::mutex> lock(providerMapMutex_);
148 providerMapToReload_.try_emplace(name, std::set<WeakPtr<ImageProviderLoader>>());
149 }
150
FindImageInSharedImageMap(const std::string & name,const WeakPtr<ImageProviderLoader> & providerWp)151 bool SharedImageManager::FindImageInSharedImageMap(
152 const std::string& name, const WeakPtr<ImageProviderLoader>& providerWp)
153 {
154 LOGD("find image %{public}s in SharedImageMap", name.c_str());
155 auto loader = providerWp.Upgrade();
156 if (!loader) {
157 LOGW("image %{public}s loader nullptr", name.c_str());
158 return false;
159 }
160 std::lock_guard<std::mutex> lockImageMap(sharedImageMapMutex_);
161 auto iter = sharedImageMap_.find(name);
162 if (iter == sharedImageMap_.end()) {
163 LOGW("image data of %{private}s does not found in SharedImageMap", name.c_str());
164 return false;
165 }
166 loader->UpdateData(std::string(MEMORY_IMAGE_HEAD).append(name), iter->second);
167 return true;
168 }
169
RegisterLoader(const std::string & name,const WeakPtr<ImageProviderLoader> & providerWp)170 bool SharedImageManager::RegisterLoader(const std::string& name, const WeakPtr<ImageProviderLoader>& providerWp)
171 {
172 std::lock_guard<std::mutex> lockProviderMap(providerMapMutex_);
173 bool resourceInMap = (providerMapToReload_.find(name) != providerMapToReload_.end());
174 providerMapToReload_[name].emplace(providerWp);
175 return resourceInMap;
176 }
177
Remove(const std::string & name)178 bool SharedImageManager::Remove(const std::string& name)
179 {
180 std::lock_guard<std::mutex> lockImageMap(sharedImageMapMutex_);
181 auto iter = sharedImageMap_.find(name);
182 if (iter == sharedImageMap_.end()) {
183 LOGW("Remove failed: image data of %{private}s does not found in SharedImageMap", name.c_str());
184 return false;
185 }
186 sharedImageTotalSize_ -= iter->second.size();
187 LOGW("clear image cache name: %{public}s", name.c_str());
188 int res = static_cast<int>(sharedImageMap_.erase(name));
189 return (res != 0);
190 }
191 } // namespace OHOS::Ace
192