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