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