• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 #include "core/components_ng/manager/memory/memory_manager.h"
16 
17 #include "core/components_ng/pattern/image/image_pattern.h"
18 #include "core/pipeline_ng/pipeline_context.h"
19 #include "frameworks/core/common/container.h"
20 
21 namespace {
22 constexpr int32_t BACKGROUND_RECYCLE_WAIT_TIME_MS = 500;
23 constexpr int32_t RECYCLE_PAGE_IMAGE_NUM = 20;
24 }
25 namespace OHOS::Ace::NG {
MemoryManager()26 MemoryManager::MemoryManager()
27 {
28     isTrimMemWork_ = false;
29 }
30 
AddRecyclePageNode(const RefPtr<FrameNode> & node)31 void MemoryManager::AddRecyclePageNode(const RefPtr<FrameNode>& node)
32 {
33     if (!isTrimMemWork_) {
34         return;
35     }
36     CHECK_NULL_VOID(node);
37     auto weak = WeakClaim(RawPtr(node));
38     if (std::find(pageNodes_.begin(), pageNodes_.end(), weak) == pageNodes_.end()) {
39         pageNodes_.emplace_back(weak);
40     }
41 }
42 
RemoveRecyclePageNode(int32_t nodeId)43 void MemoryManager::RemoveRecyclePageNode(int32_t nodeId)
44 {
45     if (!isTrimMemWork_ || pageNodes_.empty()) {
46         return;
47     }
48     pageNodes_.remove_if([nodeId](const WeakPtr<FrameNode>& node) {
49         return !node.Upgrade() || nodeId == node.Upgrade()->GetId();
50     });
51 }
52 
RecycleImage(const RefPtr<UINode> & node,int & recycleNum)53 void MemoryManager::RecycleImage(const RefPtr<UINode>& node, int& recycleNum)
54 {
55     CHECK_NULL_VOID(node);
56     const auto& children = node->GetChildren(true);
57     if (children.empty() || (recycleNum <= 0)) {
58         return;
59     }
60     for (const auto& child : children) {
61         auto childNode = AceType::DynamicCast<FrameNode>(child);
62         if (childNode && (childNode->GetTag() == V2::IMAGE_ETS_TAG)) {
63             auto imagePattern = childNode->GetPattern<ImagePattern>();
64             if ((!imagePattern) || (!imagePattern->RecycleImageData())) {
65                 continue;
66             }
67             recycleNum--;
68             if (recycleNum <= 0) {
69                 return;
70             }
71         } else {
72             RecycleImage(child, recycleNum);
73         }
74     }
75 }
76 
RecycleImageByPage(const RefPtr<FrameNode> & node)77 void MemoryManager::RecycleImageByPage(const RefPtr<FrameNode>& node)
78 {
79     CHECK_NULL_VOID(node);
80     node->SetTrimMemRecycle(true);
81     int32_t recycleNum = RECYCLE_PAGE_IMAGE_NUM;
82     RecycleImage(node, recycleNum);
83 }
84 
RebuildImageByPage(const RefPtr<FrameNode> & node)85 void MemoryManager::RebuildImageByPage(const RefPtr<FrameNode>& node)
86 {
87     CHECK_NULL_VOID(node);
88     if (!isTrimMemWork_ || !node->IsTrimMemRecycle()) {
89         return;
90     }
91     ACE_SCOPED_TRACE("memory manager rebuild image by page");
92     node->SetTrimMemRecycle(false);
93     RebuildImage(node);
94 }
95 
RebuildImage(const RefPtr<UINode> & node)96 void MemoryManager::RebuildImage(const RefPtr<UINode>& node)
97 {
98     CHECK_NULL_VOID(node);
99     const auto& children = node->GetChildren(true);
100     if (children.empty()) {
101         return;
102     }
103     for (const auto& child : children) {
104         auto childNode = AceType::DynamicCast<FrameNode>(child);
105         if (childNode && childNode->GetTag() == V2::IMAGE_ETS_TAG) {
106             auto imagePattern = childNode->GetPattern<ImagePattern>();
107             if ((!imagePattern) || (!childNode->IsTrimMemRecycle())) {
108                 continue;
109             }
110             TAG_LOGI(AceLogTag::ACE_IMAGE, "start rebuild image: %{public}d", childNode->GetId());
111             imagePattern->LoadImageDataIfNeed();
112             childNode->SetTrimMemRecycle(false);
113         } else {
114             RebuildImage(child);
115         }
116     }
117 }
118 
PostMemRecycleTask()119 void MemoryManager::PostMemRecycleTask()
120 {
121     auto container = Container::Current();
122     if (!isTrimMemWork_ || (container && container->IsSceneBoardWindow())) {
123         return;
124     }
125     auto pipeline = PipelineContext::GetCurrentContext();
126     CHECK_NULL_VOID(pipeline);
127     auto taskExecutor = pipeline->GetTaskExecutor();
128     CHECK_NULL_VOID(taskExecutor);
129     taskExecutor->PostDelayedTask([weak = WeakClaim(this)] {
130             auto memMgr = weak.Upgrade();
131             CHECK_NULL_VOID(memMgr);
132             memMgr->TrimMemRecycle();
133         },
134         TaskExecutor::TaskType::UI,
135         BACKGROUND_RECYCLE_WAIT_TIME_MS,
136         "TrimMemManagerToRecycleImage");
137 }
138 
TrimMemRecycle()139 void MemoryManager::TrimMemRecycle()
140 {
141     if (pageNodes_.empty()) {
142         return;
143     }
144     TAG_LOGI(AceLogTag::ACE_IMAGE, "start recycle image from page");
145     for (auto iter = pageNodes_.begin(); iter != pageNodes_.end(); ++iter) {
146         auto frameNode = iter->Upgrade();
147         if (!frameNode) {
148             iter = pageNodes_.erase(iter);
149             continue;
150         }
151         if (frameNode->IsVisible() || frameNode->IsTrimMemRecycle()) {
152             continue;
153         }
154         RecycleImageByPage(frameNode);
155     }
156 }
157 
Reset()158 void MemoryManager::Reset()
159 {
160     if (!isTrimMemWork_) {
161         return;
162     }
163     pageNodes_.clear();
164 }
165 } // namespace OHOS::Ace::NG
166