• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }