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 = false;
86         auto iter = sharedImageMap_.find(name);
87         if (iter != sharedImageMap_.end()) {
88             iter->second = std::move(sharedImage);
89         } else {
90             sharedImageMap_.emplace(name, std::move(sharedImage));
91             if (sharedImageMap_.size() > MAX_NUM_OF_IMAGE) {
92                 isClear = true;
93             }
94         }
95         if (sharedImage.size() > MAX_SIZE_FOR_EACH_IMAGE) {
96             isClear = true;
97         }
98         auto taskExecutor = taskExecutor_.Upgrade();
99         CHECK_NULL_VOID(taskExecutor);
100         taskExecutor->PostTask(
101             [isClear, providerWpSet, name, wp = AceType::WeakClaim(this)]() {
102                 auto sharedImageManager = wp.Upgrade();
103                 CHECK_NULL_VOID(sharedImageManager);
104                 size_t dataSize = 0;
105                 {
106                     std::lock_guard<std::mutex> lockImageMap(sharedImageManager->sharedImageMapMutex_);
107                     auto sharedImageMap = sharedImageManager->GetSharedImageMap();
108                     auto imageDataIter = sharedImageMap.find(name);
109                     if (imageDataIter == sharedImageMap.end()) {
110                         LOGW("fail to find data of %{public}s in sharedImageMap, stop UpdateData", name.c_str());
111                         return;
112                     }
113                     dataSize = imageDataIter->second.size();
114                     for (const auto& providerWp : providerWpSet) {
115                         auto provider = providerWp.Upgrade();
116                         if (!provider) {
117                             continue;
118                         }
119                         provider->UpdateData(std::string(MEMORY_IMAGE_HEAD).append(name), imageDataIter->second);
120                     }
121                 }
122                 if (isClear) {
123                     sharedImageManager->PostDelayedTaskToClearImageData(name, dataSize);
124                 }
125             },
126             TaskExecutor::TaskType::UI, "ArkUIImageAddSharedImageData");
127 }
128 
AddPictureNamesToReloadMap(std::string && name)129 void SharedImageManager::AddPictureNamesToReloadMap(std::string&& name)
130 {
131     // add names of memory image to be read from shared memory
132     std::lock_guard<std::mutex> lock(providerMapMutex_);
133     providerMapToReload_.try_emplace(name, std::set<WeakPtr<ImageProviderLoader>>());
134 }
135 
FindImageInSharedImageMap(const std::string & name,const WeakPtr<ImageProviderLoader> & providerWp)136 bool SharedImageManager::FindImageInSharedImageMap(
137     const std::string& name, const WeakPtr<ImageProviderLoader>& providerWp)
138 {
139     auto loader = providerWp.Upgrade();
140     if (!loader) {
141         return false;
142     }
143     std::lock_guard<std::mutex> lockImageMap(sharedImageMapMutex_);
144     auto iter = sharedImageMap_.find(name);
145     if (iter == sharedImageMap_.end()) {
146         LOGW("image data of %{private}s does not found in SharedImageMap", name.c_str());
147         return false;
148     }
149     loader->UpdateData(std::string(MEMORY_IMAGE_HEAD).append(name), iter->second);
150     return true;
151 }
152 
RegisterLoader(const std::string & name,const WeakPtr<ImageProviderLoader> & providerWp)153 bool SharedImageManager::RegisterLoader(const std::string& name, const WeakPtr<ImageProviderLoader>& providerWp)
154 {
155     std::lock_guard<std::mutex> lockProviderMap(providerMapMutex_);
156     bool resourceInMap = (providerMapToReload_.find(name) != providerMapToReload_.end());
157     providerMapToReload_[name].emplace(providerWp);
158     return resourceInMap;
159 }
160 
Remove(const std::string & name)161 bool SharedImageManager::Remove(const std::string& name)
162 {
163     int res = static_cast<int>(sharedImageMap_.erase(name));
164     return (res != 0);
165 }
166 } // namespace OHOS::Ace
167