1 /*
2 * Copyright (c) 2021-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 #include "core/common/ace_engine.h"
17
18 #include <csignal>
19 #include "base/thread/background_task_executor.h"
20 #ifdef PLUGIN_COMPONENT_SUPPORTED
21 #include "core/common/plugin_manager.h"
22 #endif
23
24 namespace OHOS::Ace {
25 namespace {
26
27 #ifdef OHOS_STANDARD_SYSTEM
28 enum class SignalType {
29 SIGNAL_JSHEAP_OLD,
30 SIGNAL_JSHEAP,
31 SIGNAL_JSHEAP_PRIV,
32 SIGNAL_NO_TRIGGERID,
33 SIGNAL_NO_TRIGGERID_PRIV,
34 SIGNAL_FORCE_FULLGC,
35 };
36
37 void HandleSignal(int signal, [[maybe_unused]] siginfo_t *siginfo, void *context)
38 {
39 LOGW("HandleSignal start, signal is %{public}d", signal);
40 if (signal != MUSL_SIGNAL_JSHEAP) {
41 LOGW("HandleSignal failed, signal is %{public}d", signal);
42 return;
43 }
44 LOGW("HandleSignal sival_int is %{public}d", siginfo->si_value.sival_int);
45 switch (static_cast<SignalType>(siginfo->si_value.sival_int)) {
46 case SignalType::SIGNAL_JSHEAP_OLD: {
47 AceEngine::Get().DumpJsHeap(false);
48 break;
49 }
50 case SignalType::SIGNAL_JSHEAP: {
51 AceEngine::Get().DumpJsHeap(false);
52 break;
53 }
54 case SignalType::SIGNAL_JSHEAP_PRIV: {
55 AceEngine::Get().DumpJsHeap(true);
56 break;
57 }
58 case SignalType::SIGNAL_NO_TRIGGERID: {
59 AceEngine::Get().DumpJsHeap(false);
60 AceEngine::Get().DestroyHeapProfiler();
61 break;
62 }
63 case SignalType::SIGNAL_NO_TRIGGERID_PRIV: {
64 AceEngine::Get().DumpJsHeap(true);
65 AceEngine::Get().DestroyHeapProfiler();
66 break;
67 }
68 case SignalType::SIGNAL_FORCE_FULLGC: {
69 AceEngine::Get().ForceFullGC();
70 break;
71 }
72 default:
73 break;
74 }
75 }
76 #endif
77
78 } // namespace
79
AceEngine()80 AceEngine::AceEngine()
81 {
82 if (!SystemProperties::GetHookModeEnabled()) {
83 watchDog_ = AceType::MakeRefPtr<WatchDog>();
84 }
85 }
86
~AceEngine()87 AceEngine::~AceEngine() {}
88
Get()89 AceEngine& AceEngine::Get()
90 {
91 static AceEngine engine;
92 return engine;
93 }
94
InitJsDumpHeadSignal()95 void AceEngine::InitJsDumpHeadSignal()
96 {
97 #ifdef OHOS_STANDARD_SYSTEM
98 struct sigaction sigAct;
99 sigemptyset(&sigAct.sa_mask);
100 sigAct.sa_flags = SA_SIGINFO;
101 sigAct.sa_sigaction = HandleSignal;
102 sigaction(MUSL_SIGNAL_JSHEAP, &sigAct, NULL);
103 #endif
104 }
105
AddContainer(int32_t instanceId,const RefPtr<Container> & container)106 void AceEngine::AddContainer(int32_t instanceId, const RefPtr<Container>& container)
107 {
108 std::unique_lock<std::shared_mutex> lock(mutex_);
109 containerMap_.try_emplace(instanceId, container);
110 }
111
RemoveContainer(int32_t instanceId)112 void AceEngine::RemoveContainer(int32_t instanceId)
113 {
114 size_t num = 0;
115 {
116 std::unique_lock<std::shared_mutex> lock(mutex_);
117 num = containerMap_.erase(instanceId);
118 }
119 if (num == 0) {
120 LOGW("container not found with instance id: %{public}d", instanceId);
121 }
122 }
123
GetContainer(int32_t instanceId)124 RefPtr<Container> AceEngine::GetContainer(int32_t instanceId)
125 {
126 #ifdef PLUGIN_COMPONENT_SUPPORTED
127 if (instanceId >= MIN_PLUGIN_SUBCONTAINER_ID) {
128 instanceId = PluginManager::GetInstance().GetPluginParentContainerId(instanceId);
129 }
130 #endif
131 std::shared_lock<std::shared_mutex> lock(mutex_);
132 auto container = containerMap_.find(instanceId);
133 if (container != containerMap_.end()) {
134 return container->second;
135 } else {
136 return nullptr;
137 }
138 }
139
HasContainer(int32_t containerId) const140 bool AceEngine::HasContainer(int32_t containerId) const
141 {
142 std::shared_lock<std::shared_mutex> lock(mutex_);
143 auto iter = containerMap_.find(containerId);
144 return iter != containerMap_.end();
145 }
146
RegisterToWatchDog(int32_t instanceId,const RefPtr<TaskExecutor> & taskExecutor,bool useUIAsJSThread)147 void AceEngine::RegisterToWatchDog(int32_t instanceId, const RefPtr<TaskExecutor>& taskExecutor, bool useUIAsJSThread)
148 {
149 CHECK_NULL_VOID(watchDog_);
150 watchDog_->Register(instanceId, taskExecutor, useUIAsJSThread);
151 }
152
UnRegisterFromWatchDog(int32_t instanceId)153 void AceEngine::UnRegisterFromWatchDog(int32_t instanceId)
154 {
155 CHECK_NULL_VOID(watchDog_);
156 watchDog_->Unregister(instanceId);
157 }
158
BuriedBomb(int32_t instanceId,uint64_t bombId)159 void AceEngine::BuriedBomb(int32_t instanceId, uint64_t bombId)
160 {
161 CHECK_NULL_VOID(watchDog_);
162 watchDog_->BuriedBomb(instanceId, bombId);
163 }
164
DefusingBomb(int32_t instanceId)165 void AceEngine::DefusingBomb(int32_t instanceId)
166 {
167 CHECK_NULL_VOID(watchDog_);
168 watchDog_->DefusingBomb(instanceId);
169 }
170
TriggerGarbageCollection()171 void AceEngine::TriggerGarbageCollection()
172 {
173 decltype(containerMap_) copied;
174 {
175 std::shared_lock<std::shared_mutex> lock(mutex_);
176 if (containerMap_.empty()) {
177 return;
178 }
179 copied = containerMap_;
180 }
181
182 auto taskExecutor = copied.begin()->second->GetTaskExecutor();
183 taskExecutor->PostTask([] { PurgeMallocCache(); },
184 TaskExecutor::TaskType::PLATFORM, "ArkUIPurgeMallocCache");
185 #if defined(OHOS_PLATFORM) && defined(ENABLE_NATIVE_VIEW)
186 // GPU and IO thread is shared while enable native view
187 taskExecutor->PostTask([] { PurgeMallocCache(); },
188 TaskExecutor::TaskType::GPU, "ArkUIPurgeMallocCache");
189 taskExecutor->PostTask([] { PurgeMallocCache(); },
190 TaskExecutor::TaskType::IO, "ArkUIPurgeMallocCache");
191 #endif
192
193 for (const auto& container : copied) {
194 container.second->TriggerGarbageCollection();
195 }
196
197 ImageCache::Purge();
198 BackgroundTaskExecutor::GetInstance().TriggerGarbageCollection();
199 PurgeMallocCache();
200 }
201
NotifyContainers(const std::function<void (const RefPtr<Container> &)> & callback)202 void AceEngine::NotifyContainers(const std::function<void(const RefPtr<Container>&)>& callback)
203 {
204 CHECK_NULL_VOID(callback);
205 decltype(containerMap_) copied;
206 {
207 std::shared_lock<std::shared_mutex> lock(mutex_);
208 copied = containerMap_;
209 }
210 for (const auto& [first, second] : copied) {
211 // first = container ID
212 ContainerScope scope(first);
213 callback(second);
214 }
215 }
216
NotifyContainersOrderly(const std::function<void (const RefPtr<Container> &)> & callback)217 void AceEngine::NotifyContainersOrderly(const std::function<void(const RefPtr<Container>&)>& callback)
218 {
219 CHECK_NULL_VOID(callback);
220 std::map<int32_t, RefPtr<Container>> copied;
221 {
222 std::shared_lock<std::shared_mutex> lock(mutex_);
223 for (const auto& pair : containerMap_) {
224 copied.insert(pair);
225 }
226 }
227 for (const auto& [first, second] : copied) {
228 // first = container ID
229 ContainerScope scope(first);
230 callback(second);
231 }
232 }
233
DumpJsHeap(bool isPrivate) const234 void AceEngine::DumpJsHeap(bool isPrivate) const
235 {
236 decltype(containerMap_) copied;
237 {
238 std::shared_lock<std::shared_mutex> lock(mutex_);
239 copied = containerMap_;
240 }
241 for (const auto& container : copied) {
242 container.second->DumpHeapSnapshot(isPrivate);
243 }
244 }
245
DestroyHeapProfiler() const246 void AceEngine::DestroyHeapProfiler() const
247 {
248 decltype(containerMap_) copied;
249 {
250 std::shared_lock<std::shared_mutex> lock(mutex_);
251 copied = containerMap_;
252 }
253 for (const auto& container : copied) {
254 container.second->DestroyHeapProfiler();
255 }
256 }
257
ForceFullGC() const258 void AceEngine::ForceFullGC() const
259 {
260 decltype(containerMap_) copied;
261 {
262 std::shared_lock<std::shared_mutex> lock(mutex_);
263 copied = containerMap_;
264 }
265 for (const auto& container : copied) {
266 container.second->ForceFullGC();
267 }
268 }
269
270 } // namespace OHOS::Ace
271