• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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