1 /*
2 * Copyright (C) 2022-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 #include "usage_event_report.h"
16
17 #include <sys/wait.h>
18
19 #include "ffrt.h"
20 #include "hiview_event_report.h"
21 #include "hiview_event_cacher.h"
22 #ifdef POWER_MANAGER_ENABLE
23 #include "hiview_shutdown_callback.h"
24 #endif
25 #include "display_manager.h"
26 #include "sys_event.h"
27 #include "hiview_logger.h"
28 #include "plugin_factory.h"
29 #include "securec.h"
30 #ifdef POWER_MANAGER_ENABLE
31 #include "shutdown/shutdown_client.h"
32 #endif
33 #include "string_util.h"
34 #include "time_util.h"
35 #include "usage_event_cacher.h"
36 #include "usage_event_common.h"
37
38 namespace OHOS {
39 namespace HiviewDFX {
40 REGISTER(UsageEventReport);
41 DEFINE_LOG_TAG("HiView-UsageEventReport");
42 uint64_t UsageEventReport::lastReportTime_ = 0;
43 uint64_t UsageEventReport::lastSysReportTime_ = 0;
44 uint64_t UsageEventReport::nextReportTime_ = 0;
45 std::string UsageEventReport::workPath_ = "";
46 namespace {
47 constexpr int TRIGGER_CYCLE = 5 * 60 * 1000 * 1000; // 5 min
48 constexpr uint32_t TRIGGER_ONE_HOUR = 12; // 1h = 5min * 12
49 }
50 using namespace OHOS::Rosen;
51 using namespace SysUsageDbSpace;
52 using namespace SysUsageEventSpace;
53
UsageEventReport()54 UsageEventReport::UsageEventReport() : callback_(nullptr), timeOutCnt_(0), isRunning_(false)
55 {}
56
OnLoad()57 void UsageEventReport::OnLoad()
58 {
59 HIVIEW_LOGI("start to init the env");
60 Init();
61 Start();
62 }
63
OnEvent(std::shared_ptr<Event> & event)64 bool UsageEventReport::OnEvent(std::shared_ptr<Event>& event)
65 {
66 if (event == nullptr || event->messageType_ != Event::MessageType::SYS_EVENT) {
67 HIVIEW_LOGI("event is invalid");
68 return false;
69 }
70 if (foldEventCacher_ != nullptr) {
71 auto sysEvent = Event::DownCastTo<SysEvent>(event);
72 foldEventCacher_->ProcessEvent(sysEvent);
73 }
74 return true;
75 }
76
OnUnload()77 void UsageEventReport::OnUnload()
78 {
79 HIVIEW_LOGI("start to clean up the env");
80 if (callback_ != nullptr) {
81 #ifdef POWER_MANAGER_ENABLE
82 PowerMgr::ShutdownClient::GetInstance().UnRegisterShutdownCallback(callback_);
83 #endif
84 callback_ = nullptr;
85 }
86 Stop();
87 }
88
IsRunning()89 bool UsageEventReport::IsRunning()
90 {
91 std::lock_guard lock(runningMutex_);
92 return isRunning_;
93 }
94
Init()95 void UsageEventReport::Init()
96 {
97 auto nowTime = TimeUtil::GetMilliseconds();
98 if (auto context = GetHiviewContext(); context != nullptr) {
99 workPath_ = context->GetHiViewDirectory(HiviewContext::DirectoryType::WORK_DIRECTORY);
100
101 // get plugin stats event from db if any
102 UsageEventCacher cacher(workPath_);
103 std::vector<std::shared_ptr<LoggerEvent>> pluginStatEvents;
104 cacher.GetPluginStatsEvents(pluginStatEvents);
105 HiviewEventCacher::GetInstance().AddPluginStatsEvent(pluginStatEvents);
106 HIVIEW_LOGI("get plugin stats event=%{public}zu", pluginStatEvents.size());
107
108 // get last report time from db if any
109 if (auto event = cacher.GetSysUsageEvent(LAST_SYS_USAGE_TABLE); event != nullptr) {
110 HIVIEW_LOGI("get cache sys usage event=%{public}s", event->ToJsonString().c_str());
111 lastReportTime_ = event->GetValue(KEY_OF_START).GetUint64();
112 } else {
113 lastReportTime_ = nowTime;
114 }
115
116 // get last sys report time from db if any
117 if (auto event = cacher.GetSysUsageEvent(); event != nullptr) {
118 HIVIEW_LOGI("get last sys usage event=%{public}s", event->ToJsonString().c_str());
119 lastSysReportTime_ = event->GetValue(KEY_OF_START).GetUint64();
120 } else {
121 lastSysReportTime_ = nowTime;
122 }
123 BindWorkLoop(context->GetSharedWorkLoop());
124 InitFoldEventCacher(workPath_);
125 }
126 nextReportTime_ = static_cast<uint64_t>(TimeUtil::Get0ClockStampMs()) + TimeUtil::MILLISECS_PER_DAY;
127
128 // more than one day since the last report
129 if (nowTime >= (lastReportTime_ + TimeUtil::MILLISECS_PER_DAY)) {
130 HIVIEW_LOGI("lastReportTime=%{public}" PRIu64 ", need to report daily event now", lastReportTime_);
131 ReportDailyEvent();
132 }
133
134 // more than one hours since the shutdown time
135 if (nowTime >= (lastSysReportTime_ + 3600000)) { // 3600000ms: 1h
136 HIVIEW_LOGI("lastSysReportTime=%{public}" PRIu64 ", need to report sys usage event now", lastReportTime_);
137 ReportSysUsageEvent();
138 }
139 }
140
InitFoldEventCacher(const std::string & workPath)141 void UsageEventReport::InitFoldEventCacher(const std::string& workPath)
142 {
143 if (!DisplayManager::GetInstance().IsFoldable()) {
144 HIVIEW_LOGI("unFoldable device");
145 return;
146 }
147 foldEventCacher_ = std::make_unique<FoldEventCacher>(workPath);
148 foldAppUsageFactory_ = std::make_unique<FoldAppUsageEventFactory>(workPath);
149 }
150
InitCallback()151 void UsageEventReport::InitCallback()
152 {
153 HIVIEW_LOGI("start to init shutdown callback");
154 #ifdef POWER_MANAGER_ENABLE
155 callback_ = new (std::nothrow) HiViewShutdownCallback();
156 PowerMgr::ShutdownClient::GetInstance().RegisterShutdownCallback(callback_,
157 PowerMgr::ShutdownPriority::HIGH);
158 #endif
159 }
160
Start()161 void UsageEventReport::Start()
162 {
163 {
164 std::lock_guard lock(runningMutex_);
165 isRunning_ = true;
166 }
167 RunTask();
168 }
169
Stop()170 void UsageEventReport::Stop()
171 {
172 std::lock_guard lock(runningMutex_);
173 isRunning_ = false;
174 }
175
RunTask()176 void UsageEventReport::RunTask()
177 {
178 auto task = bind(&UsageEventReport::TimeOut, this);
179 ffrt::submit(task, {}, {}, ffrt::task_attr().name("dft_ue_report").delay(TRIGGER_CYCLE));
180 }
181
TimeOut()182 void UsageEventReport::TimeOut()
183 {
184 if (!IsRunning()) {
185 HIVIEW_LOGI("task exit");
186 return;
187 }
188
189 HIVIEW_LOGD("start checking whether events need to be reported");
190 ReportTimeOutEvent();
191 ReportDailyEvent();
192
193 // init shutdown callback if necessary
194 if (callback_ == nullptr) {
195 InitCallback();
196 }
197
198 RunTask();
199 if (foldEventCacher_ != nullptr) {
200 foldEventCacher_->TimeOut();
201 }
202 }
203
ReportDailyEvent()204 void UsageEventReport::ReportDailyEvent()
205 {
206 // check whether time step occurs. If yes, update the next report time
207 auto nowTime = TimeUtil::GetMilliseconds();
208 if (nowTime > (nextReportTime_ + TimeUtil::MILLISECS_PER_DAY)
209 || nowTime < (nextReportTime_ - TimeUtil::MILLISECS_PER_DAY)) {
210 HIVIEW_LOGW("start to update the next daily report time");
211 nextReportTime_ = static_cast<uint64_t>(TimeUtil::Get0ClockStampMs()) + TimeUtil::MILLISECS_PER_DAY;
212 } else if (nowTime >= nextReportTime_) {
213 // report plugin stats event
214 HIVIEW_LOGI("start to report daily event");
215 HiviewEventReport::ReportPluginStats();
216 DeletePluginStatsEvents();
217
218 // report app usage event
219 StartServiceByOption("-A");
220 ReportFoldAppUsageEvent();
221
222 // update report time
223 lastReportTime_ = TimeUtil::GetMilliseconds();
224 nextReportTime_ += TimeUtil::MILLISECS_PER_DAY;
225 }
226 }
227
ReportTimeOutEvent()228 void UsageEventReport::ReportTimeOutEvent()
229 {
230 ++timeOutCnt_;
231 SaveSysUsageEvent();
232 if (timeOutCnt_ >= TRIGGER_ONE_HOUR) {
233 ReportSysUsageEvent();
234 timeOutCnt_ = 0;
235 }
236 }
237
ReportSysUsageEvent()238 void UsageEventReport::ReportSysUsageEvent()
239 {
240 StartServiceByOption("-S");
241 lastSysReportTime_ = TimeUtil::GetMilliseconds();
242 }
243
ReportFoldAppUsageEvent()244 void UsageEventReport::ReportFoldAppUsageEvent()
245 {
246 if (foldAppUsageFactory_ == nullptr) {
247 HIVIEW_LOGI("foldAppUsageFactory is nullptr");
248 return;
249 }
250 std::vector<std::unique_ptr<LoggerEvent>> foldAppUsageEvents;
251 foldAppUsageFactory_->Create(foldAppUsageEvents);
252 HIVIEW_LOGI("report fold app usage event num: %{public}zu", foldAppUsageEvents.size());
253 for (size_t i = 0; i < foldAppUsageEvents.size(); ++i) {
254 foldAppUsageEvents[i]->Report();
255 }
256 }
257
SaveEventToDb()258 void UsageEventReport::SaveEventToDb()
259 {
260 HIVIEW_LOGI("start to save the event to db");
261 SavePluginStatsEvents();
262 SaveSysUsageEvent();
263 }
264
SavePluginStatsEvents()265 void UsageEventReport::SavePluginStatsEvents()
266 {
267 std::vector<std::shared_ptr<LoggerEvent>> events;
268 HiviewEventCacher::GetInstance().GetPluginStatsEvents(events);
269 if (events.empty()) {
270 return;
271 }
272 UsageEventCacher cacher(workPath_);
273 cacher.SavePluginStatsEventsToDb(events);
274 }
275
DeletePluginStatsEvents()276 void UsageEventReport::DeletePluginStatsEvents()
277 {
278 UsageEventCacher cacher(workPath_);
279 cacher.DeletePluginStatsEventsFromDb();
280 }
281
SaveSysUsageEvent()282 void UsageEventReport::SaveSysUsageEvent()
283 {
284 StartServiceByOption("-s");
285 }
286
StartServiceByOption(const std::string & opt)287 void UsageEventReport::StartServiceByOption(const std::string& opt)
288 {
289 HIVIEW_LOGI("start service, opt=%{public}s", opt.c_str());
290 if (pid_t pid = fork(); pid < 0) {
291 HIVIEW_LOGE("failed to fork child process");
292 return;
293 } else if (pid == 0) {
294 const size_t len = 20; // 20: max_len(uint64_t) + '\0'
295 char lastRTBuf[len] = {0};
296 if (sprintf_s(lastRTBuf, len, "%" PRIu64, lastReportTime_) < 0) {
297 HIVIEW_LOGE("failed to convert lastReportTime_=%{public}" PRIu64 " to string", lastReportTime_);
298 _exit(-1);
299 }
300 char lastSRTBuf[len] = {0};
301 if (sprintf_s(lastSRTBuf, len, "%" PRIu64, lastSysReportTime_) < 0) {
302 HIVIEW_LOGE("failed to convert lastSysReportTime_=%{public}" PRIu64 " to string", lastSysReportTime_);
303 _exit(-1);
304 }
305 const std::string serviceName = "usage_report";
306 const std::string servicePath = "/system/bin/usage_report";
307 if (execl(servicePath.c_str(), serviceName.c_str(),
308 "-p", workPath_.c_str(),
309 "-t", lastRTBuf,
310 "-T", lastSRTBuf,
311 opt.c_str(), nullptr) < 0) {
312 HIVIEW_LOGE("failed to execute %{public}s", serviceName.c_str());
313 _exit(-1);
314 }
315 } else {
316 if (waitpid(pid, nullptr, 0) != pid) {
317 HIVIEW_LOGE("failed to waitpid, pid=%{public}d, err=%{public}d", pid, errno);
318 } else {
319 HIVIEW_LOGI("succ to waitpid, pid=%{public}d", pid);
320 }
321 }
322 }
323 } // namespace HiviewDFX
324 } // namespace OHOS
325