1 /*
2 * Copyright (C) 2022-2023 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 "hiview_event_report.h"
20 #include "hiview_event_cacher.h"
21 #ifdef POWER_MANAGER_ENABLE
22 #include "hiview_shutdown_callback.h"
23 #endif
24 #include "logger.h"
25 #include "plugin_factory.h"
26 #include "securec.h"
27 #ifdef POWER_MANAGER_ENABLE
28 #include "shutdown/shutdown_client.h"
29 #endif
30 #include "string_util.h"
31 #include "time_util.h"
32 #include "usage_event_cacher.h"
33 #include "usage_event_common.h"
34
35 namespace OHOS {
36 namespace HiviewDFX {
37 REGISTER(UsageEventReport);
38 DEFINE_LOG_TAG("HiView-UsageEventReport");
39 uint64_t UsageEventReport::lastReportTime_ = 0;
40 uint64_t UsageEventReport::lastSysReportTime_ = 0;
41 uint64_t UsageEventReport::nextReportTime_ = 0;
42 std::string UsageEventReport::workPath_ = "";
43 namespace {
44 constexpr int TRIGGER_CYCLE = 5 * 60; // 5 min
45 constexpr uint32_t TRIGGER_ONE_HOUR = 12; // 1h = 5min * 12
46 }
47 using namespace SysUsageDbSpace;
48 using namespace SysUsageEventSpace;
49
UsageEventReport()50 UsageEventReport::UsageEventReport() : callback_(nullptr), timeOutCnt_(0)
51 {}
52
OnLoad()53 void UsageEventReport::OnLoad()
54 {
55 HIVIEW_LOGI("start to init the env");
56 Init();
57 Start();
58 }
59
OnUnload()60 void UsageEventReport::OnUnload()
61 {
62 HIVIEW_LOGI("start to clean up the env");
63 if (workLoop_ != nullptr) {
64 workLoop_->StopLoop();
65 workLoop_.reset();
66 }
67 if (callback_ != nullptr) {
68 #ifdef POWER_MANAGER_ENABLE
69 PowerMgr::ShutdownClient::GetInstance().UnRegisterShutdownCallback(callback_);
70 #endif
71 callback_ = nullptr;
72 }
73 }
74
Init()75 void UsageEventReport::Init()
76 {
77 auto nowTime = TimeUtil::GetMilliseconds();
78 if (auto context = GetHiviewContext(); context != nullptr) {
79 workPath_ = context->GetHiViewDirectory(HiviewContext::DirectoryType::WORK_DIRECTORY);
80
81 // get plugin stats event from db if any
82 UsageEventCacher cacher(workPath_);
83 std::vector<std::shared_ptr<LoggerEvent>> pluginStatEvents;
84 cacher.GetPluginStatsEvents(pluginStatEvents);
85 HiviewEventCacher::GetInstance().AddPluginStatsEvent(pluginStatEvents);
86 HIVIEW_LOGI("get plugin stats event=%{public}d", pluginStatEvents.size());
87
88 // get last report time from db if any
89 if (auto event = cacher.GetSysUsageEvent(LAST_SYS_USAGE_TABLE); event != nullptr) {
90 HIVIEW_LOGI("get cache sys usage event=%{public}s", event->ToJsonString().c_str());
91 lastReportTime_ = event->GetValue(KEY_OF_START).GetUint64();
92 } else {
93 lastReportTime_ = nowTime;
94 }
95
96 // get last sys report time from db if any
97 if (auto event = cacher.GetSysUsageEvent(); event != nullptr) {
98 HIVIEW_LOGI("get last sys usage event=%{public}s", event->ToJsonString().c_str());
99 lastSysReportTime_ = event->GetValue(KEY_OF_START).GetUint64();
100 } else {
101 lastSysReportTime_ = nowTime;
102 }
103 }
104 nextReportTime_ = static_cast<uint64_t>(TimeUtil::Get0ClockStampMs()) + TimeUtil::MILLISECS_PER_DAY;
105
106 // more than one day since the last report
107 if (nowTime >= (lastReportTime_ + TimeUtil::MILLISECS_PER_DAY)) {
108 HIVIEW_LOGI("lastReportTime=%{public}" PRIu64 ", need to report daily event now", lastReportTime_);
109 ReportDailyEvent();
110 }
111
112 // more than one hours since the shutdown time
113 if (nowTime >= (lastSysReportTime_ + 3600000)) { // 3600000ms: 1h
114 HIVIEW_LOGI("lastSysReportTime=%{public}" PRIu64 ", need to report sys usage event now", lastReportTime_);
115 ReportSysUsageEvent();
116 }
117 }
118
InitCallback()119 void UsageEventReport::InitCallback()
120 {
121 HIVIEW_LOGI("start to init shutdown callback");
122 #ifdef POWER_MANAGER_ENABLE
123 callback_ = new (std::nothrow) HiViewShutdownCallback();
124 PowerMgr::ShutdownClient::GetInstance().RegisterShutdownCallback(callback_,
125 PowerMgr::ShutdownPriority::HIGH);
126 #endif
127 }
128
Start()129 void UsageEventReport::Start()
130 {
131 auto task = bind(&UsageEventReport::TimeOut, this);
132 workLoop_->AddTimerEvent(nullptr, nullptr, task, TRIGGER_CYCLE, true);
133 }
134
TimeOut()135 void UsageEventReport::TimeOut()
136 {
137 HIVIEW_LOGI("start checking whether events need to be reported");
138 ReportTimeOutEvent();
139 ReportDailyEvent();
140
141 // init shutdown callback if necessary
142 if (callback_ == nullptr) {
143 InitCallback();
144 }
145 }
146
ReportDailyEvent()147 void UsageEventReport::ReportDailyEvent()
148 {
149 // check whether time step occurs. If yes, update the next report time
150 auto nowTime = TimeUtil::GetMilliseconds();
151 if (nowTime > (nextReportTime_ + TimeUtil::MILLISECS_PER_DAY)
152 || nowTime < (nextReportTime_ - TimeUtil::MILLISECS_PER_DAY)) {
153 HIVIEW_LOGW("start to update the next daily report time");
154 nextReportTime_ = static_cast<uint64_t>(TimeUtil::Get0ClockStampMs()) + TimeUtil::MILLISECS_PER_DAY;
155 } else if (nowTime >= nextReportTime_) {
156 // report plugin stats event
157 HIVIEW_LOGI("start to report daily event");
158 HiviewEventReport::ReportPluginStats();
159 DeletePluginStatsEvents();
160
161 // report app usage event
162 StartServiceByOption("-A");
163
164 // update report time
165 lastReportTime_ = TimeUtil::GetMilliseconds();
166 nextReportTime_ += TimeUtil::MILLISECS_PER_DAY;
167 } else {
168 HIVIEW_LOGI("No need to report daily events");
169 }
170 }
171
ReportTimeOutEvent()172 void UsageEventReport::ReportTimeOutEvent()
173 {
174 ++timeOutCnt_;
175 SaveSysUsageEvent();
176 if (timeOutCnt_ >= TRIGGER_ONE_HOUR) {
177 ReportSysUsageEvent();
178 timeOutCnt_ = 0;
179 }
180 }
181
ReportSysUsageEvent()182 void UsageEventReport::ReportSysUsageEvent()
183 {
184 StartServiceByOption("-S");
185 lastSysReportTime_ = TimeUtil::GetMilliseconds();
186 }
187
SaveEventToDb()188 void UsageEventReport::SaveEventToDb()
189 {
190 HIVIEW_LOGI("start to save the event to db");
191 SavePluginStatsEvents();
192 SaveSysUsageEvent();
193 }
194
SavePluginStatsEvents()195 void UsageEventReport::SavePluginStatsEvents()
196 {
197 std::vector<std::shared_ptr<LoggerEvent>> events;
198 HiviewEventCacher::GetInstance().GetPluginStatsEvents(events);
199 if (events.empty()) {
200 return;
201 }
202 UsageEventCacher cacher(workPath_);
203 cacher.SavePluginStatsEventsToDb(events);
204 }
205
DeletePluginStatsEvents()206 void UsageEventReport::DeletePluginStatsEvents()
207 {
208 UsageEventCacher cacher(workPath_);
209 cacher.DeletePluginStatsEventsFromDb();
210 }
211
SaveSysUsageEvent()212 void UsageEventReport::SaveSysUsageEvent()
213 {
214 StartServiceByOption("-s");
215 }
216
StartServiceByOption(const std::string & opt)217 void UsageEventReport::StartServiceByOption(const std::string& opt)
218 {
219 HIVIEW_LOGI("start service, opt=%{public}s", opt.c_str());
220 if (pid_t pid = fork(); pid < 0) {
221 HIVIEW_LOGE("failed to fork child process");
222 return;
223 } else if (pid == 0) {
224 const size_t len = 20; // 20: max_len(uint64_t) + '\0'
225 char lastRTBuf[len] = {0};
226 if (sprintf_s(lastRTBuf, len, "%" PRIu64, lastReportTime_) < 0) {
227 HIVIEW_LOGE("failed to convert lastReportTime_=%{public}" PRIu64 " to string", lastReportTime_);
228 _exit(-1);
229 }
230 char lastSRTBuf[len] = {0};
231 if (sprintf_s(lastSRTBuf, len, "%" PRIu64, lastSysReportTime_) < 0) {
232 HIVIEW_LOGE("failed to convert lastSysReportTime_=%{public}" PRIu64 " to string", lastSysReportTime_);
233 _exit(-1);
234 }
235 const std::string serviceName = "usage_report";
236 const std::string servicePath = "/system/bin/usage_report";
237 if (execl(servicePath.c_str(), serviceName.c_str(),
238 "-p", workPath_.c_str(),
239 "-t", lastRTBuf,
240 "-T", lastSRTBuf,
241 opt.c_str(), nullptr) < 0) {
242 HIVIEW_LOGE("failed to execute %{public}s", serviceName.c_str());
243 _exit(-1);
244 }
245 } else {
246 if (waitpid(pid, nullptr, 0) != pid) {
247 HIVIEW_LOGE("failed to waitpid, pid=%{public}d, err=%{public}d", pid, errno);
248 } else {
249 HIVIEW_LOGI("succ to waitpid, pid=%{public}d", pid);
250 }
251 }
252 }
253 } // namespace HiviewDFX
254 } // namespace OHOS
255