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