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