• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 <fstream>
17 #include <list>
18 
19 #include "dfx_utils.h"
20 #include "dfx_database_utils.h"
21 #include "file_utils.h"
22 #include "medialibrary_astc_stat.h"
23 #include "medialibrary_type_const.h"
24 #include "media_file_utils.h"
25 #include "media_log.h"
26 #include "thumbnail_const.h"
27 #include "thumbnail_generate_worker.h"
28 #include "thumbnail_generate_worker_manager.h"
29 
30 namespace OHOS {
31 namespace Media {
32 
GetInstance()33 MediaLibraryAstcStat &MediaLibraryAstcStat::GetInstance()
34 {
35     static MediaLibraryAstcStat instance;
36     return instance;
37 }
38 
39 template <typename T>
enum_to_value(T enumValue)40 auto enum_to_value(T enumValue) -> std::underlying_type_t<T>
41 {
42     return static_cast<std::underlying_type_t<T>>(enumValue);
43 }
44 
ConvertSceneStatToJson(const SceneStat & sceneStat,AstcGenScene sceneType)45 static nlohmann::json ConvertSceneStatToJson(const SceneStat &sceneStat, AstcGenScene sceneType)
46 {
47     nlohmann::json jsonSceneStat;
48     jsonSceneStat["scene"] = enum_to_value(sceneType);
49     jsonSceneStat["duration"] = sceneStat.duration_;
50     jsonSceneStat["astc"] = sceneStat.astcCount_;
51     return jsonSceneStat;
52 }
53 
ConvertPhaseStatToJson(const PhaseStat & phaseStat,AstcPhase phaseType)54 static nlohmann::json ConvertPhaseStatToJson(const PhaseStat &phaseStat, AstcPhase phaseType)
55 {
56     nlohmann::json jsonPhaseStat;
57     jsonPhaseStat["phase"] = enum_to_value(phaseType);
58     jsonPhaseStat["phase_start_time"] = phaseStat.startTime_;
59     jsonPhaseStat["phase_end_time"] = phaseStat.endTime_;
60     jsonPhaseStat["interruptArr"] = nlohmann::json::array();
61     for (const auto &[retValue, retCount] : phaseStat.retValues_) {
62         nlohmann::json jsonRetStat;
63         jsonRetStat[retValue] = retCount;
64         jsonPhaseStat["interruptArr"].emplace_back(jsonRetStat);
65     }
66     nlohmann::json scenesJson;
67     for (const auto &[sceneType, sceneStat] : phaseStat.scenes_) {
68         std::string key = "scene" + std::to_string(enum_to_value(sceneType));
69         jsonPhaseStat[key] = ConvertSceneStatToJson(sceneStat, sceneType);
70     }
71     return jsonPhaseStat;
72 }
73 
ConvertToJson(nlohmann::json & jsonPhasesStat,const PhasesStat & phasesStat,int32_t totalAstcCount)74 bool MediaLibraryAstcStat::ConvertToJson(nlohmann::json& jsonPhasesStat, const PhasesStat& phasesStat,
75     int32_t totalAstcCount)
76 {
77     jsonPhasesStat["totalAstcCount"] = totalAstcCount;
78     for (const auto &[phaseType, phaseStat] : phasesStat.phases_) {
79         std::string key = "phase" + std::to_string(enum_to_value(phaseType));
80         jsonPhasesStat[key] = ConvertPhaseStatToJson(phaseStat, phaseType);
81     }
82     return true;
83 }
84 
ConvertRetStatToStruct(const nlohmann::json & jsonPhaseStat,PhaseStat & phaseStat)85 static bool ConvertRetStatToStruct(const nlohmann::json &jsonPhaseStat, PhaseStat &phaseStat)
86 {
87     for (const auto& jsonRetStat : jsonPhaseStat["interruptArr"]) {
88         for (const auto& [key, value] : jsonRetStat.items()) {
89             phaseStat.retValues_[key] = 0;
90             if (value.is_number_integer()) {
91                 phaseStat.retValues_[key] = value.get<int32_t>();
92             }
93         }
94     }
95     return true;
96 }
97 
ConvertSceneStatToStruct(const nlohmann::json & jsonSceneStat,SceneStat & sceneStat,AstcGenScene & sceneType)98 static bool ConvertSceneStatToStruct(const nlohmann::json &jsonSceneStat, SceneStat &sceneStat, AstcGenScene& sceneType)
99 {
100     if (jsonSceneStat.contains("scene") && jsonSceneStat["scene"].is_number_integer()) {
101         sceneType = static_cast<AstcGenScene>(jsonSceneStat["scene"].get<int32_t>());
102         sceneStat.sceneKey_ = sceneType;
103     }
104     if (jsonSceneStat.contains("duration") && jsonSceneStat["duration"].is_number_integer()) {
105         sceneStat.duration_ = jsonSceneStat["duration"].get<int64_t>();
106     }
107     if (jsonSceneStat.contains("astc") && jsonSceneStat["astc"].is_number_integer()) {
108         sceneStat.astcCount_ = static_cast<uint32_t>(jsonSceneStat["astc"].get<int32_t>());
109     }
110 
111     return true;
112 }
113 
ConvertPhaseStatToStruct(const nlohmann::json & jsonPhaseStat,PhaseStat & phaseStat,AstcPhase & photoSyncPhase)114 static bool ConvertPhaseStatToStruct(const nlohmann::json &jsonPhaseStat, PhaseStat &phaseStat,
115     AstcPhase& photoSyncPhase)
116 {
117     if (jsonPhaseStat.contains("phase") && jsonPhaseStat["phase"].is_number_integer()) {
118         photoSyncPhase = static_cast<AstcPhase>(jsonPhaseStat["phase"].get<int32_t>());
119         phaseStat.phase_ = photoSyncPhase;
120     }
121     if (jsonPhaseStat.contains("phase_start_time") && jsonPhaseStat["phase_start_time"].is_number_integer()) {
122         phaseStat.startTime_ = jsonPhaseStat["phase_start_time"].get<int64_t>();
123     }
124     if (jsonPhaseStat.contains("phase_end_time") && jsonPhaseStat["phase_end_time"].is_number_integer()) {
125         phaseStat.endTime_ = jsonPhaseStat["phase_end_time"].get<int64_t>();
126     }
127     if (jsonPhaseStat.contains("interruptArr") && jsonPhaseStat["interruptArr"].is_array()) {
128         ConvertRetStatToStruct(jsonPhaseStat, phaseStat);
129     }
130     for (int i = 0; i <= static_cast<int>(AstcGenScene::CHARGING_SCREENOFF); i++) {
131         std::string key = "scene" + std::to_string(i);
132         if (jsonPhaseStat.contains(key)) {
133             const auto& jsonSceneStat = jsonPhaseStat[key];
134             SceneStat sceneStat{};
135             AstcGenScene sceneType{AstcGenScene::DEFAULT};
136             ConvertSceneStatToStruct(jsonSceneStat, sceneStat, sceneType);
137             if (phaseStat.scenes_.count(sceneType) == 0) {
138                 phaseStat.scenes_[sceneType] = sceneStat;
139             } else {
140                 phaseStat.scenes_[sceneType] += sceneStat;
141             }
142         }
143     }
144     return true;
145 }
146 
ConvertToStruct(const nlohmann::json & jsonPhasesStat,PhasesStat & phasesStat,int32_t & totalAstcCount)147 bool MediaLibraryAstcStat::ConvertToStruct(const nlohmann::json &jsonPhasesStat, PhasesStat &phasesStat,
148     int32_t& totalAstcCount)
149 {
150     if (jsonPhasesStat.contains("totalAstcCount") && jsonPhasesStat["totalAstcCount"].is_number_integer()) {
151         totalAstcCount = jsonPhasesStat["totalAstcCount"].get<int32_t>();
152     }
153     for (int i = static_cast<int>(AstcPhase::PHASE1); i <= static_cast<int>(AstcPhase::PHASE5); i++) {
154         std::string key = "phase" + std::to_string(i);
155         if (jsonPhasesStat.contains(key)) {
156             const auto& jsonPhaseStat = jsonPhasesStat[key];
157             PhaseStat phaseStat{};
158             AstcPhase phaseType{AstcPhase::DEFAULT};
159             ConvertPhaseStatToStruct(jsonPhaseStat, phaseStat, phaseType);
160             if (phasesStat.phases_.count(phaseType) == 0) {
161                 phasesStat.phases_[phaseType] = phaseStat;
162             } else {
163                 phasesStat.phases_[phaseType] += phaseStat;
164             }
165         }
166     }
167     return true;
168 }
169 
ReadAstcInfoFromJsonFile(PhasesStat & phasesStat,int32_t & totalAstcCount)170 bool MediaLibraryAstcStat::ReadAstcInfoFromJsonFile(PhasesStat& phasesStat, int32_t& totalAstcCount)
171 {
172     nlohmann::json jsonPhaseStat{};
173     if (not ReadJsonFile(ASTC_JSON_FILE_PATH, jsonPhaseStat)) {
174         MEDIA_ERR_LOG("ReadJsonFile failed!");
175         return false;
176     }
177     if (not ConvertToStruct(jsonPhaseStat, phasesStat, totalAstcCount)) {
178         MEDIA_ERR_LOG("convert from json to struct failed!");
179         return false;
180     }
181     return true;
182 }
183 
WriteAstcInfoToJsonFile(const PhasesStat & phasesStat,int32_t totalAstcCount)184 bool MediaLibraryAstcStat::WriteAstcInfoToJsonFile(const PhasesStat& phasesStat, int32_t totalAstcCount)
185 {
186     nlohmann::json jsonPhaseStat{};
187     if (not ConvertToJson(jsonPhaseStat, phasesStat, totalAstcCount)) {
188         MEDIA_ERR_LOG("convert from struct to json failed!");
189         return false;
190     }
191     if (not WriteJsonFile(ASTC_JSON_FILE_PATH, jsonPhaseStat)) {
192         MEDIA_ERR_LOG("WriteJsonFile failed!");
193         return false;
194     }
195     return true;
196 }
197 
WriteJsonFile(const std::string & filePath,const nlohmann::json & j)198 bool MediaLibraryAstcStat::WriteJsonFile(const std::string &filePath, const nlohmann::json &j)
199 {
200     const std::string parentDir = MediaFileUtils::GetParentPath(filePath);
201     if (!MediaFileUtils::CreateDirectory(parentDir)) {
202         MEDIA_ERR_LOG("CreateDirectory failed, dir = %{public}s", DfxUtils::GetSafePath(parentDir).c_str());
203         return false;
204     }
205 
206     std::ofstream outFile(filePath, std::ofstream::out | std::ofstream::trunc);
207     CHECK_AND_RETURN_RET_LOG(outFile.is_open(), false, "open filePath: %{private}s failed", filePath.c_str());
208     outFile << j << std::endl;
209     outFile.close();
210     return true;
211 }
212 
ReadJsonFile(const std::string & filePath,nlohmann::json & j)213 bool MediaLibraryAstcStat::ReadJsonFile(const std::string &filePath, nlohmann::json &j)
214 {
215     std::ifstream inFile(filePath);
216     CHECK_AND_RETURN_RET_LOG(inFile.is_open(), false, "open filePath: %{private}s failed", filePath.c_str());
217 
218     std::string buffer = std::string((std::istreambuf_iterator<char>(inFile)), std::istreambuf_iterator<char>());
219     j = nlohmann::json::parse(buffer, nullptr, false);
220     inFile.close();
221     return !j.is_discarded();
222 }
223 
GetAstcPhase(int32_t totalAstcCount,GenerateScene genScene)224 AstcPhase MediaLibraryAstcStat::GetAstcPhase(int32_t totalAstcCount, GenerateScene genScene)
225 {
226     AstcPhase phaseKey = AstcPhase::DEFAULT;
227     constexpr int32_t phase1MaxCount = 100;
228     constexpr int32_t phase2MaxCount = 2000;
229     constexpr int32_t phase3MaxCount = 20000;
230     constexpr int32_t phase4MaxCount = 200000;
231     if (totalAstcCount == phase1MaxCount || totalAstcCount == phase2MaxCount ||
232         totalAstcCount == phase3MaxCount || totalAstcCount == phase4MaxCount) {
233         GetJsonStr();
234     }
235 
236     if (totalAstcCount <= phase1MaxCount) {
237         phaseKey = AstcPhase::PHASE1;
238     } else if (totalAstcCount <= phase2MaxCount && totalAstcCount > phase1MaxCount) {
239         phaseKey = AstcPhase::PHASE2;
240     } else if (totalAstcCount <= phase3MaxCount && totalAstcCount > phase2MaxCount) {
241         phaseKey = AstcPhase::PHASE3;
242     } else if (totalAstcCount <= phase4MaxCount && totalAstcCount > phase3MaxCount) {
243         phaseKey = AstcPhase::PHASE4;
244     } else {
245         phaseKey = AstcPhase::PHASE5;
246     }
247 
248     return phaseKey;
249 }
250 
IsBackupGroundTaskEmpty()251 static bool IsBackupGroundTaskEmpty()
252 {
253     std::shared_ptr<ThumbnailGenerateWorker> thumbnailWorker =
254         ThumbnailGenerateWorkerManager::GetInstance().GetThumbnailWorker(ThumbnailTaskType::BACKGROUND);
255     CHECK_AND_RETURN_RET_LOG(thumbnailWorker != nullptr, true, "thumbnailWorker is null");
256     return thumbnailWorker->IsLowerQueueEmpty();
257 }
258 
GetInterruptInfo(bool isScreenOff,bool isCharging,bool isPowerSufficient,bool isThermalLow)259 void MediaLibraryAstcStat::GetInterruptInfo(bool isScreenOff, bool isCharging,
260     bool isPowerSufficient, bool isThermalLow)
261 {
262     if (IsBackupGroundTaskEmpty()) {
263         return;
264     }
265     std::string screenOn = "screenOn";
266     std::string notCharging = "notCharging";
267     std::string powerNotSufficient = "powerNotSufficient";
268     std::string thermalHigh = "thermalHigh";
269 
270     std::lock_guard<std::mutex> lock(mutex_);
271     AstcPhase phaseKey = GetAstcPhase(totalAstcCount_ + 1, GenerateScene::BACKGROUND);
272     if (!phasesStat_.phases_.count(phaseKey)) {
273         PhaseStat phase;
274         phasesStat_.phases_[phaseKey] = phase;
275     }
276     auto &interruptStat = phasesStat_.phases_[phaseKey].retValues_;
277     if (!isScreenOff) {
278         if (interruptStat.count(screenOn)) {
279             interruptStat[screenOn]++;
280         } else {
281             interruptStat[screenOn] = 1;
282         }
283     }
284     if (!isCharging) {
285         if (interruptStat.count(notCharging)) {
286             interruptStat[notCharging]++;
287         } else {
288             interruptStat[notCharging] = 1;
289         }
290     }
291     if (!isPowerSufficient) {
292         if (interruptStat.count(powerNotSufficient)) {
293             interruptStat[powerNotSufficient]++;
294         } else {
295             interruptStat[powerNotSufficient] = 1;
296         }
297     }
298     if (!isThermalLow) {
299         if (interruptStat.count(thermalHigh)) {
300             interruptStat[thermalHigh]++;
301         } else {
302             interruptStat[thermalHigh] = 1;
303         }
304     }
305 }
306 
GetScene(int64_t duration,AstcGenScene sceneKey)307 static SceneStat GetScene(int64_t duration, AstcGenScene sceneKey)
308 {
309     SceneStat scene;
310     scene.sceneKey_ = sceneKey;
311     scene.duration_ = duration;
312     scene.astcCount_ = 1;
313     return scene;
314 }
315 
TryToReadAstcInfoFromJsonFile()316 void MediaLibraryAstcStat::TryToReadAstcInfoFromJsonFile()
317 {
318     if (FileUtils::IsFileExist(ASTC_JSON_FILE_PATH)) {
319         ReadAstcInfoFromJsonFile(phasesStat_, totalAstcCount_);
320     } else {
321         totalAstcCount_ = DfxDatabaseUtils::QueryASTCThumb(true) + DfxDatabaseUtils::QueryASTCThumb(false);
322     }
323 }
324 
CheckId(const std::string & id)325 bool MediaLibraryAstcStat::CheckId(const std::string &id)
326 {
327     static std::list<std::string> idList;
328     constexpr int32_t maxSize = 2000;
329     constexpr int32_t removeCount = 100;
330     if (id == "") {
331         return false;
332     }
333     std::lock_guard<std::mutex> lock(mutex_);
334     if (std::find(idList.begin(), idList.end(), id) != idList.end()) {
335         MEDIA_INFO_LOG("have statted id %{public}s", id.c_str());
336         return true;
337     }
338     if (idList.size() >= maxSize) {
339         for (size_t i = 0; i < removeCount; ++i) {
340             if (idList.empty()) {
341                 break;
342             }
343             idList.pop_front();
344         }
345     }
346     idList.push_back(id);
347     return false;
348 }
349 
AddAstcInfo(int64_t startTime,GenerateScene genScene,AstcGenScene sceneKey,const std::string & id)350 void MediaLibraryAstcStat::AddAstcInfo(int64_t startTime, GenerateScene genScene, AstcGenScene sceneKey,
351     const std::string &id)
352 {
353     if (CheckId(id)) {
354         return;
355     }
356     int64_t endTime = MediaFileUtils::UTCTimeMilliSeconds();
357     AstcPhase phaseKey = GetAstcPhase(totalAstcCount_ + 1, genScene);
358     MEDIA_DEBUG_LOG("phaseKey %{public}d GenerateScene %{public}d sceneKey %{public}d", static_cast<int32_t>(phaseKey),
359         static_cast<int32_t>(genScene), static_cast<int32_t>(sceneKey));
360 
361     PhaseStat phase;
362     phase.phase_ = phaseKey;
363     phase.scenes_[sceneKey] = GetScene(endTime - startTime, sceneKey);
364     phase.startTime_ = startTime;
365     phase.endTime_ = endTime;
366     std::lock_guard<std::mutex> lock(mutex_);
367     if (totalAstcCount_ == 0) {
368         TryToReadAstcInfoFromJsonFile();
369     }
370     totalAstcCount_++;
371     if (phasesStat_.phases_.count(phaseKey)) {
372         PhaseStat &phaseStat = phasesStat_.phases_[phaseKey];
373         phaseStat += phase;
374     } else {
375         phasesStat_.phases_[phaseKey] = phase;
376     }
377     int64_t currentTime = MediaFileUtils::UTCTimeSeconds();
378     constexpr int64_t oneHour = 3600;
379     if (currentTime - lastReportTime_ > oneHour) {
380         WriteAstcInfoToJsonFile(phasesStat_, totalAstcCount_);
381         lastReportTime_ = currentTime;
382     }
383 }
384 
GetJson()385 std::string MediaLibraryAstcStat::GetJson()
386 {
387     std::lock_guard<std::mutex> lock(mutex_);
388     return GetJsonStr();
389 }
390 
GetJsonStr()391 std::string MediaLibraryAstcStat::GetJsonStr()
392 {
393     nlohmann::json jsn;
394     ConvertToJson(jsn, phasesStat_, totalAstcCount_);
395     MEDIA_INFO_LOG("json %{public}s", jsn.dump().c_str());
396     return jsn.dump();
397 }
398 
ClearOldData()399 void MediaLibraryAstcStat::ClearOldData()
400 {
401     std::lock_guard<std::mutex> lock(mutex_);
402     phasesStat_.phases_.clear();
403     totalAstcCount_ = 0;
404     if (FileUtils::IsFileExist(ASTC_JSON_FILE_PATH)) {
405         FileUtils::DeleteFile(ASTC_JSON_FILE_PATH);
406     }
407 }
408 } // namespace Media
409 } // namespace OHOS
410