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 #define MLOG_TAG "DfxWorker"
16
17 #include "dfx_worker.h"
18
19 #include <pthread.h>
20
21 #include "cloud_media_asset_manager.h"
22 #include "media_file_utils.h"
23 #include "media_log.h"
24 #include "dfx_manager.h"
25 #include "preferences.h"
26 #include "preferences_helper.h"
27 #include "parameters.h"
28
29 using namespace std;
30 namespace OHOS {
31 namespace Media {
32 shared_ptr<DfxWorker> DfxWorker::dfxWorkerInstance_{nullptr};
33
GetInstance()34 shared_ptr<DfxWorker> DfxWorker::GetInstance()
35 {
36 if (dfxWorkerInstance_ == nullptr) {
37 dfxWorkerInstance_ = make_shared<DfxWorker>();
38 }
39 return dfxWorkerInstance_;
40 }
41
DfxWorker()42 DfxWorker::DfxWorker() : isThreadRunning_(false)
43 {
44 }
45
~DfxWorker()46 DfxWorker::~DfxWorker()
47 {
48 MEDIA_INFO_LOG("DfxWorker deconstructor");
49 isThreadRunning_ = false;
50 workCv_.notify_all();
51 if (delayThread_.joinable()) {
52 delayThread_.join();
53 }
54 dfxWorkerInstance_ = nullptr;
55 }
56
Init()57 void DfxWorker::Init()
58 {
59 MEDIA_INFO_LOG("init");
60 isThreadRunning_ = true;
61 delayThread_ = thread([this] { this->InitDelayThread(); });
62 }
63
HandleLoopTask(DfxData * data)64 static void HandleLoopTask(DfxData *data)
65 {
66 MEDIA_DEBUG_LOG("HandleLoopTask");
67 int32_t errCode;
68 shared_ptr<NativePreferences::Preferences> prefs =
69 NativePreferences::PreferencesHelper::GetPreferences(DFX_COMMON_XML, errCode);
70 if (!prefs) {
71 MEDIA_ERR_LOG("get preferences error: %{public}d", errCode);
72 return;
73 }
74 int64_t lastReportTime = prefs->GetLong(LAST_REPORT_TIME, 0);
75 int64_t lastMiddleReportTime = prefs->GetLong(LAST_MIDDLE_REPORT_TIME, 0);
76 DfxManager::GetInstance()->HandleFiveMinuteTask();
77 if (MediaFileUtils::UTCTimeSeconds() - lastMiddleReportTime >= SIX_HOUR) {
78 MEDIA_INFO_LOG("Report Middle Xml");
79 lastMiddleReportTime = DfxManager::GetInstance()->HandleMiddleReport();
80 prefs->PutLong(LAST_MIDDLE_REPORT_TIME, lastMiddleReportTime);
81 prefs->FlushSync();
82 }
83 if (MediaFileUtils::UTCTimeSeconds() - lastReportTime >= ONE_DAY) {
84 MEDIA_INFO_LOG("Report one day Xml");
85 lastReportTime = DfxManager::GetInstance()->HandleOneDayReport();
86 prefs->PutLong(LAST_REPORT_TIME, lastReportTime);
87 prefs->FlushSync();
88 }
89 CloudMediaAssetManager::GetInstance().CheckStorageAndRecoverDownloadTask();
90 }
91
Prepare()92 void DfxWorker::Prepare()
93 {
94 int32_t errCode;
95 shared_ptr<NativePreferences::Preferences> prefs =
96 NativePreferences::PreferencesHelper::GetPreferences(DFX_COMMON_XML, errCode);
97 if (!prefs) {
98 MEDIA_ERR_LOG("get preferences error: %{public}d", errCode);
99 return;
100 }
101 thumbnailVersion_ = prefs->GetInt(THUMBNAIL_ERROR_VERSION, 0);
102 deleteStatisticVersion_ = prefs->GetInt(DELETE_STATISTIC_VERSION, 0);
103 if (IsThumbnailUpdate()) {
104 thumbnailVersion_ = LATEST_THUMBNAIL_ERROR_VERSION;
105 prefs->PutInt(THUMBNAIL_ERROR_VERSION, LATEST_THUMBNAIL_ERROR_VERSION);
106 }
107 if (IsDeleteStatisticUpdate()) {
108 deleteStatisticVersion_ = LATEST_DELETE_STATISTIC_VERSION;
109 prefs->PutInt(DELETE_STATISTIC_VERSION, LATEST_DELETE_STATISTIC_VERSION);
110 }
111 prefs->FlushSync();
112 }
113
IsThumbnailUpdate()114 bool DfxWorker::IsThumbnailUpdate()
115 {
116 if (thumbnailVersion_ < LATEST_THUMBNAIL_ERROR_VERSION) {
117 MEDIA_INFO_LOG("update thumbnail version from %{public}d to %{public}d", thumbnailVersion_,
118 LATEST_THUMBNAIL_ERROR_VERSION);
119 int32_t errCode;
120 shared_ptr<NativePreferences::Preferences> prefs =
121 NativePreferences::PreferencesHelper::GetPreferences(THUMBNAIL_ERROR_XML, errCode);
122 if (!prefs) {
123 MEDIA_ERR_LOG("get preferences error: %{public}d", errCode);
124 return false;
125 }
126 prefs->Clear();
127 prefs->FlushSync();
128 return true;
129 }
130 return false;
131 }
132
IsDeleteStatisticUpdate()133 bool DfxWorker::IsDeleteStatisticUpdate()
134 {
135 if (deleteStatisticVersion_ < LATEST_DELETE_STATISTIC_VERSION) {
136 MEDIA_INFO_LOG("update delete statistic version from %{public}d to %{public}d", deleteStatisticVersion_,
137 LATEST_DELETE_STATISTIC_VERSION);
138 int32_t errCode;
139 shared_ptr<NativePreferences::Preferences> prefs =
140 NativePreferences::PreferencesHelper::GetPreferences(DELETE_BEHAVIOR_XML, errCode);
141 if (!prefs) {
142 MEDIA_ERR_LOG("get preferences error: %{public}d", errCode);
143 return false;
144 }
145 prefs->Clear();
146 prefs->FlushSync();
147 return true;
148 }
149 return false;
150 }
151
InitDelayThread()152 void DfxWorker::InitDelayThread()
153 {
154 Prepare();
155 bool isStartLoopTask = true;
156 MEDIA_INFO_LOG("InitDelayThread");
157 string name("DfxDelayThread");
158 pthread_setname_np(pthread_self(), name.c_str());
159 while (isThreadRunning_) {
160 if (isStartLoopTask) {
161 HandleLoopTask(nullptr);
162 StartLoopTaskDelay();
163 isStartLoopTask = false;
164 }
165 WaitForTask();
166 if (!isThreadRunning_) {
167 break;
168 }
169 if (IsTaskQueueEmpty()) {
170 continue;
171 }
172 auto now = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
173 auto executeTime = std::chrono::time_point_cast<std::chrono::milliseconds>(GetWaitTime());
174 auto delay = now.time_since_epoch().count() - executeTime.time_since_epoch().count();
175 if (delay < 0) {
176 continue;
177 }
178 shared_ptr<DfxTask> task = GetTask();
179 if (task == nullptr) {
180 continue;
181 }
182 task->executor_(task->data_);
183 if (task->isDelayTask_) {
184 StartLoopTaskDelay();
185 }
186 task = nullptr;
187 }
188 }
189
StartLoopTaskDelay()190 void DfxWorker::StartLoopTaskDelay()
191 {
192 auto loopTask = make_shared<DfxTask>(HandleLoopTask, nullptr);
193 AddTask(loopTask, FIVE_MINUTE);
194 }
195
compare(const shared_ptr<DfxTask> & taskOne,const shared_ptr<DfxTask> & taskTwo)196 static bool compare(const shared_ptr<DfxTask> &taskOne, const shared_ptr<DfxTask> &taskTwo)
197 {
198 auto firstTime = std::chrono::time_point_cast<std::chrono::milliseconds>(taskOne->executeTime_);
199 auto secondTime = std::chrono::time_point_cast<std::chrono::milliseconds>(taskTwo->executeTime_);
200 return firstTime.time_since_epoch().count() > secondTime.time_since_epoch().count();
201 }
202
AddTask(const shared_ptr<DfxTask> & task,int64_t delayTime)203 void DfxWorker::AddTask(const shared_ptr<DfxTask> &task, int64_t delayTime)
204 {
205 lock_guard<mutex> lockGuard(taskLock_);
206 if (delayTime > 0) {
207 task->executeTime_ = std::chrono::system_clock::now() + std::chrono::milliseconds(delayTime);
208 task->isDelayTask_ = true;
209 }
210 taskList_.push_back(task);
211 sort(taskList_.begin(), taskList_.end(), compare);
212 workCv_.notify_one();
213 }
214
IsTaskQueueEmpty()215 bool DfxWorker::IsTaskQueueEmpty()
216 {
217 lock_guard<mutex> lock_Guard(taskLock_);
218 return taskList_.empty();
219 }
220
WaitForTask()221 void DfxWorker::WaitForTask()
222 {
223 std::unique_lock<std::mutex> lock(workLock_);
224 if (IsTaskQueueEmpty()) {
225 workCv_.wait(lock,
226 [this]() { return !isThreadRunning_ || !IsTaskQueueEmpty(); });
227 } else {
228 workCv_.wait_until(lock, GetWaitTime(),
229 [this]() { return !isThreadRunning_ || !IsDelayTask(); });
230 }
231 }
232
GetTask()233 shared_ptr<DfxTask> DfxWorker::GetTask()
234 {
235 lock_guard<mutex> lockGuard(taskLock_);
236 if (taskList_.empty()) {
237 return nullptr;
238 }
239 shared_ptr<DfxTask> task = taskList_.back();
240 taskList_.pop_back();
241 return task;
242 }
243
244
IsDelayTask()245 bool DfxWorker::IsDelayTask()
246 {
247 lock_guard<mutex> lockGuard(taskLock_);
248 shared_ptr<DfxTask> task = taskList_.back();
249 return task->isDelayTask_;
250 }
251
GetWaitTime()252 std::chrono::system_clock::time_point DfxWorker::GetWaitTime()
253 {
254 lock_guard<mutex> lockGuard(taskLock_);
255 shared_ptr<DfxTask> task = taskList_.back();
256 return task->executeTime_;
257 }
258
End()259 void DfxWorker::End()
260 {
261 isEnd_ = true;
262 }
263 } // namespace Media
264 } // namespace OHOS