1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
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 "player_mem_manage.h"
17 #include <unistd.h>
18 #include <functional>
19 #include "media_log.h"
20 #include "media_errors.h"
21 #include "mem_mgr_client.h"
22 #include "hisysevent.h"
23
24 namespace {
25 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_PLAYER, "PlayerMemManage"};
26 }
27
28 namespace OHOS {
29 namespace Media {
30 constexpr double APP_BACK_GROUND_DESTROY_MEMERY_TIME = 60.0;
31 constexpr double APP_FRONT_GROUND_DESTROY_MEMERY_TIME = 120.0;
32
33 // HiSysEvent
34 const std::string PURGEABLE_EVENT_NAME = "MEMORY_PURGEABLE_INFO";
35 const std::string PURGEABLE_TYPE_NAME = "PlayerMemManage";
36 constexpr int32_t LEVEL_REBUILD = 10;
37
GetInstance()38 PlayerMemManage& PlayerMemManage::GetInstance()
39 {
40 static PlayerMemManage instance;
41 instance.Init();
42 return instance;
43 }
44
PlayerMemManage()45 PlayerMemManage::PlayerMemManage()
46 {
47 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
48 }
49
~PlayerMemManage()50 PlayerMemManage::~PlayerMemManage()
51 {
52 Memory::MemMgrClient::GetInstance().UnsubscribeAppState(*appStateListener_);
53 if (isProbeTaskCreated_) {
54 isProbeTaskCreated_ = false;
55 probeTaskQueue_->Stop();
56 probeTaskQueue_ = nullptr;
57 }
58 playerManage_.clear();
59 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
60 }
61
FindBackGroundPlayerFromVec(AppPlayerInfo & appPlayerInfo)62 void PlayerMemManage::FindBackGroundPlayerFromVec(AppPlayerInfo &appPlayerInfo)
63 {
64 if (appPlayerInfo.appState == static_cast<int32_t>(AppState::APP_STATE_BACK_GROUND)) {
65 std::chrono::duration<double> durationCost = std::chrono::duration_cast<
66 std::chrono::duration<double>>(std::chrono::steady_clock::now() - appPlayerInfo.appEnterBackTime);
67 if (durationCost.count() > APP_BACK_GROUND_DESTROY_MEMERY_TIME) {
68 for (auto iter = appPlayerInfo.memRecallStructVec.begin();
69 iter != appPlayerInfo.memRecallStructVec.end(); iter++) {
70 ((*iter).resetBackGroundRecall)();
71 }
72 }
73 }
74 }
75
FindFrontGroundPlayerFromVec(AppPlayerInfo & appPlayerInfo)76 void PlayerMemManage::FindFrontGroundPlayerFromVec(AppPlayerInfo &appPlayerInfo)
77 {
78 if (appPlayerInfo.appState == static_cast<int32_t>(AppState::APP_STATE_FRONT_GROUND)) {
79 std::chrono::duration<double> durationCost = std::chrono::duration_cast<
80 std::chrono::duration<double>>(std::chrono::steady_clock::now() - appPlayerInfo.appEnterFrontTime);
81 if (durationCost.count() > APP_FRONT_GROUND_DESTROY_MEMERY_TIME) {
82 for (auto iter = appPlayerInfo.memRecallStructVec.begin();
83 iter != appPlayerInfo.memRecallStructVec.end(); iter++) {
84 ((*iter).resetFrontGroundRecall)();
85 }
86 }
87 }
88 }
89
FindProbeTaskPlayer()90 void PlayerMemManage::FindProbeTaskPlayer()
91 {
92 std::lock_guard<std::recursive_mutex> lock(recMutex_);
93 for (auto &[uid, pidPlayersInfo] : playerManage_) {
94 for (auto &[pid, appPlayerInfo] : pidPlayersInfo) {
95 FindFrontGroundPlayerFromVec(appPlayerInfo);
96 FindBackGroundPlayerFromVec(appPlayerInfo);
97 }
98 }
99 }
100
ProbeTask()101 void PlayerMemManage::ProbeTask()
102 {
103 while (isProbeTaskCreated_) {
104 FindProbeTaskPlayer();
105 sleep(1); // 1 : one second interval check
106 }
107 }
108
Init()109 bool PlayerMemManage::Init()
110 {
111 std::lock_guard<std::recursive_mutex> lock(recMutex_);
112 if (isParsed_) {
113 if (appStateListener_ != nullptr && isAppStateListenerRemoteDied_) {
114 MEDIA_LOGE("MemMgrClient died, SubscribeAppState again");
115 Memory::MemMgrClient::GetInstance().SubscribeAppState(*appStateListener_);
116 }
117 return true;
118 }
119 MEDIA_LOGI("Create PlayerMemManage");
120 playerManage_.clear();
121
122 appStateListener_ = std::make_shared<AppStateListener>();
123 CHECK_AND_RETURN_RET_LOG(appStateListener_ != nullptr, false, "failed to new AppStateListener");
124
125 Memory::MemMgrClient::GetInstance().SubscribeAppState(*appStateListener_);
126 isParsed_ = true;
127 return true;
128 }
129
RegisterPlayerServer(int32_t uid,int32_t pid,const MemManageRecall & memRecallStruct)130 int32_t PlayerMemManage::RegisterPlayerServer(int32_t uid, int32_t pid, const MemManageRecall &memRecallStruct)
131 {
132 {
133 std::lock_guard<std::recursive_mutex> lock(recMutex_);
134 MEDIA_LOGI("Register PlayerServerTask uid:%{public}d, pid:%{public}d", uid, pid);
135 auto objIter = playerManage_.find(uid);
136 if (objIter == playerManage_.end()) {
137 MEDIA_LOGI("new user in uid:%{public}d", uid);
138 auto ret = playerManage_.emplace(uid, PidPlayersInfo {});
139 objIter = ret.first;
140 }
141
142 auto &pidPlayersInfo = objIter->second;
143 auto pidIter = pidPlayersInfo.find(pid);
144 if (pidIter == pidPlayersInfo.end()) {
145 MEDIA_LOGI("new app in pid:%{public}d", pid);
146 auto ret = pidPlayersInfo.emplace(pid, AppPlayerInfo {std::vector<MemManageRecall>(),
147 static_cast<int32_t>(AppState::APP_STATE_FRONT_GROUND),
148 std::chrono::steady_clock::now(), std::chrono::steady_clock::now()});
149 Memory::MemMgrClient::GetInstance().RegisterActiveApps(pid, uid);
150 pidIter = ret.first;
151 }
152
153 auto &appPlayerInfo = pidIter->second;
154 appPlayerInfo.memRecallStructVec.push_back(memRecallStruct);
155 }
156
157 {
158 std::lock_guard<std::recursive_mutex> lock(recTaskMutex_);
159 if (!isProbeTaskCreated_) {
160 MEDIA_LOGI("Start probe task");
161 isProbeTaskCreated_ = true;
162 probeTaskQueue_ = std::make_unique<TaskQueue>("probeTaskQueue");
163 CHECK_AND_RETURN_RET_LOG(probeTaskQueue_->Start() == MSERR_OK, false, "init task failed");
164 auto task = std::make_shared<TaskHandler<void>>([this] {
165 ProbeTask();
166 });
167 }
168 }
169
170 return MSERR_OK;
171 }
172
FindDeregisterPlayerFromVec(bool & isFind,AppPlayerInfo & appPlayerInfo,const MemManageRecall & memRecallStruct)173 void PlayerMemManage::FindDeregisterPlayerFromVec(bool &isFind, AppPlayerInfo &appPlayerInfo,
174 const MemManageRecall &memRecallStruct)
175 {
176 for (auto iter = appPlayerInfo.memRecallStructVec.begin(); iter != appPlayerInfo.memRecallStructVec.end();) {
177 if ((*iter).signAddr == memRecallStruct.signAddr) {
178 iter = appPlayerInfo.memRecallStructVec.erase(iter);
179 MEDIA_LOGI("Remove PlayerServerTask from vector size:%{public}u",
180 static_cast<uint32_t>(appPlayerInfo.memRecallStructVec.size()));
181 isFind = true;
182 break;
183 } else {
184 iter++;
185 }
186 }
187 }
188
DeregisterPlayerServer(const MemManageRecall & memRecallStruct)189 int32_t PlayerMemManage::DeregisterPlayerServer(const MemManageRecall &memRecallStruct)
190 {
191 bool isFind = false;
192 {
193 std::lock_guard<std::recursive_mutex> lock(recMutex_);
194 MEDIA_LOGD("Deregister PlayerServerTask");
195 for (auto &[uid, pidPlayersInfo] : playerManage_) {
196 for (auto &[pid, appPlayerInfo] : pidPlayersInfo) {
197 FindDeregisterPlayerFromVec(isFind, appPlayerInfo, memRecallStruct);
198 if (appPlayerInfo.memRecallStructVec.size() == 0) {
199 Memory::MemMgrClient::GetInstance().DeregisterActiveApps(pid, uid);
200 MEDIA_LOGI("DeregisterActiveApps pid:%{public}d uid:%{public}d pidPlayersInfo size:%{public}u",
201 pid, uid, static_cast<uint32_t>(pidPlayersInfo.size()));
202 pidPlayersInfo.erase(pid);
203 break;
204 }
205 }
206 if (pidPlayersInfo.size() == 0) {
207 MEDIA_LOGI("remove uid:%{public}d playerManage_ size:%{public}u",
208 uid, static_cast<uint32_t>(playerManage_.size()));
209 playerManage_.erase(uid);
210 break;
211 }
212 }
213 }
214
215 {
216 std::lock_guard<std::recursive_mutex> lock(recTaskMutex_);
217 if (isProbeTaskCreated_ && playerManage_.size() == 0) {
218 MEDIA_LOGI("Stop probe task");
219 isProbeTaskCreated_ = false;
220 probeTaskQueue_->Stop();
221 probeTaskQueue_ = nullptr;
222 }
223 }
224
225 if (!isFind) {
226 MEDIA_LOGW("0x%{public}06" PRIXPTR " Not find memRecallPair, maybe already deregister", FAKE_POINTER(this));
227 return MSERR_INVALID_OPERATION;
228 }
229
230 return MSERR_OK;
231 }
232
233 /* mem_mgr_client : currently dose not support the trigger this interface */
HandleForceReclaim(int32_t uid,int32_t pid)234 int32_t PlayerMemManage::HandleForceReclaim(int32_t uid, int32_t pid)
235 {
236 std::lock_guard<std::recursive_mutex> lock(recMutex_);
237
238 MEDIA_LOGI("Enter ForceReclaim pid:%{public}d uid:%{public}d", pid, uid);
239 for (auto &[findUid, pidPlayersInfo] : playerManage_) {
240 if (findUid != uid) {
241 continue;
242 }
243 for (auto &[findPid, appPlayerInfo] : pidPlayersInfo) {
244 if (findPid != pid) {
245 continue;
246 }
247 if (appPlayerInfo.appState != static_cast<int32_t>(AppState::APP_STATE_BACK_GROUND)) {
248 MEDIA_LOGE("HandleForceReclaim appState not allow");
249 return MSERR_INVALID_OPERATION;
250 }
251 for (auto iter = appPlayerInfo.memRecallStructVec.begin();
252 iter != appPlayerInfo.memRecallStructVec.end(); iter++) {
253 ((*iter).resetMemmgrRecall)();
254 MEDIA_LOGI("call ResetForMemManageRecall success");
255 }
256 return MSERR_OK;
257 }
258 }
259 return MSERR_OK;
260 }
261
HandleOnTrimLevelLow()262 void PlayerMemManage::HandleOnTrimLevelLow()
263 {
264 for (auto &[findUid, pidPlayersInfo] : playerManage_) {
265 for (auto &[findPid, appPlayerInfo] : pidPlayersInfo) {
266 if (appPlayerInfo.appState != static_cast<int32_t>(AppState::APP_STATE_BACK_GROUND)) {
267 continue;
268 }
269 for (auto iter = appPlayerInfo.memRecallStructVec.begin();
270 iter != appPlayerInfo.memRecallStructVec.end(); iter++) {
271 ((*iter).resetMemmgrRecall)();
272 MEDIA_LOGI("call ResetForMemManageRecall success");
273 }
274 }
275 }
276 }
277
HandleOnTrim(Memory::SystemMemoryLevel level)278 int32_t PlayerMemManage::HandleOnTrim(Memory::SystemMemoryLevel level)
279 {
280 std::lock_guard<std::recursive_mutex> lock(recMutex_);
281 MEDIA_LOGI("Enter OnTrim level:%{public}d", level);
282
283 auto startTime = std::chrono::steady_clock::now();
284 switch (level) {
285 case Memory::SystemMemoryLevel::MEMORY_LEVEL_MODERATE: // remain 800MB trigger
286 HandleOnTrimLevelLow();
287 break;
288
289 case Memory::SystemMemoryLevel::MEMORY_LEVEL_LOW: // remain 700MB trigger
290 HandleOnTrimLevelLow();
291 break;
292
293 case Memory::SystemMemoryLevel::MEMORY_LEVEL_CRITICAL: // remain 600MB trigger
294 HandleOnTrimLevelLow();
295 break;
296
297 default:
298 break;
299 }
300
301 auto endTime = std::chrono::steady_clock::now();
302 int32_t useTime = std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count();
303 WritePurgeableEvent(int32_t(level), useTime);
304
305 return MSERR_OK;
306 }
307
AwakeFrontGroundAppMedia(AppPlayerInfo & appPlayerInfo)308 void PlayerMemManage::AwakeFrontGroundAppMedia(AppPlayerInfo &appPlayerInfo)
309 {
310 for (auto iter = appPlayerInfo.memRecallStructVec.begin();
311 iter != appPlayerInfo.memRecallStructVec.end(); iter++) {
312 ((*iter).recoverRecall)();
313 }
314 MEDIA_LOGI("call RecoverByMemManageRecall success");
315 }
316
SetAppPlayerInfo(AppPlayerInfo & appPlayerInfo,int32_t state)317 void PlayerMemManage::SetAppPlayerInfo(AppPlayerInfo &appPlayerInfo, int32_t state)
318 {
319 if (appPlayerInfo.appState != state) {
320 appPlayerInfo.appState = state;
321 if (state == static_cast<int32_t>(AppState::APP_STATE_FRONT_GROUND)) {
322 appPlayerInfo.appEnterFrontTime = std::chrono::steady_clock::now();
323 AwakeFrontGroundAppMedia(appPlayerInfo);
324 auto endTime = std::chrono::steady_clock::now();
325 int32_t useTime = std::chrono::duration_cast<std::chrono::microseconds>(endTime -
326 appPlayerInfo.appEnterFrontTime).count();
327 WritePurgeableEvent(LEVEL_REBUILD, useTime);
328 } else if (state == static_cast<int32_t>(AppState::APP_STATE_BACK_GROUND)) {
329 appPlayerInfo.appEnterBackTime = std::chrono::steady_clock::now();
330 }
331 }
332 }
333
RecordAppState(int32_t uid,int32_t pid,int32_t state)334 int32_t PlayerMemManage::RecordAppState(int32_t uid, int32_t pid, int32_t state)
335 {
336 std::lock_guard<std::recursive_mutex> lock(recMutex_);
337 MEDIA_LOGD("Enter OnAppStateChanged pid:%{public}d uid:%{public}d state:%{public}d", pid, uid, state);
338 for (auto &[findUid, pidPlayersInfo] : playerManage_) {
339 if (findUid != uid) {
340 continue;
341 }
342 for (auto &[findPid, appPlayerInfo] : pidPlayersInfo) {
343 if (findPid == pid) {
344 SetAppPlayerInfo(appPlayerInfo, state);
345 return MSERR_OK;
346 }
347 }
348 }
349
350 return MSERR_OK;
351 }
352
RemoteDieAgainRegisterActiveApps()353 void PlayerMemManage::RemoteDieAgainRegisterActiveApps()
354 {
355 MEDIA_LOGI("Enter");
356 for (auto &[findUid, pidPlayersInfo] : playerManage_) {
357 for (auto &[findPid, appPlayerInfo] : pidPlayersInfo) {
358 MEDIA_LOGI("Again RegisterActiveApps uid:%{public}d, pid:%{public}d", findUid, findPid);
359 Memory::MemMgrClient::GetInstance().RegisterActiveApps(findPid, findUid);
360 }
361 }
362 }
363
HandleOnConnected()364 void PlayerMemManage::HandleOnConnected()
365 {
366 std::lock_guard<std::recursive_mutex> lock(recMutex_);
367 MEDIA_LOGI("Enter RemoteDied:%{public}d", isAppStateListenerRemoteDied_);
368 isAppStateListenerConnected_ = true;
369 if (isAppStateListenerRemoteDied_) {
370 RemoteDieAgainRegisterActiveApps();
371 isAppStateListenerRemoteDied_ = false;
372 }
373 }
374
HandleOnDisconnected()375 void PlayerMemManage::HandleOnDisconnected()
376 {
377 std::lock_guard<std::recursive_mutex> lock(recMutex_);
378 MEDIA_LOGI("Enter");
379 isAppStateListenerConnected_ = false;
380 }
381
HandleOnRemoteDied(const wptr<IRemoteObject> & object)382 void PlayerMemManage::HandleOnRemoteDied(const wptr<IRemoteObject> &object)
383 {
384 (void)object;
385 std::lock_guard<std::recursive_mutex> lock(recMutex_);
386 MEDIA_LOGI("Enter");
387 isAppStateListenerRemoteDied_ = true;
388 isAppStateListenerConnected_ = false;
389
390 for (auto &[findUid, pidPlayersInfo] : playerManage_) {
391 for (auto &[findPid, appPlayerInfo] : pidPlayersInfo) {
392 MEDIA_LOGI("Set all App front ground, uid:%{public}d, pid:%{public}d", findUid, findPid);
393 appPlayerInfo.appState = static_cast<int32_t>(AppState::APP_STATE_FRONT_GROUND);
394 appPlayerInfo.appEnterFrontTime = std::chrono::steady_clock::now();
395 }
396 }
397 }
398
WritePurgeableEvent(int32_t level,int32_t useTime)399 void PlayerMemManage::WritePurgeableEvent(int32_t level, int32_t useTime)
400 {
401 MEDIA_LOGD("WritePurgeableEvent: level = %{public}d, useTime = %{public}d", level, useTime);
402 int32_t res = HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::MEMMGR, PURGEABLE_EVENT_NAME.c_str(),
403 HiviewDFX::HiSysEvent::EventType::STATISTIC, "TYPE", PURGEABLE_TYPE_NAME.c_str(),
404 "LEVEL", level, "USETIME", useTime);
405 if (res != 0) {
406 MEDIA_LOGE("write hiSysEvent error, res:%{public}d", res);
407 }
408 }
409 }
410 }