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 "bbox_detector_plugin.h"
16
17 #include <fstream>
18 #include <securec.h>
19
20 #include "common_defines.h"
21 #include "event.h"
22 #include "event_loop.h"
23 #include "file_util.h"
24 #include "hisysevent.h"
25 #include "hiview_logger.h"
26 #include "panic_report_recovery.h"
27 #include "panic_error_info_handle.h"
28 #include "plugin_factory.h"
29 #include "hisysevent_util.h"
30 #include "smart_parser.h"
31 #include "string_util.h"
32 #include "tbox.h"
33 #include "time_util.h"
34
35 namespace OHOS {
36 namespace HiviewDFX {
37 using namespace std;
38 REGISTER(BBoxDetectorPlugin);
39 DEFINE_LOG_LABEL(0xD002D11, "BBoxDetectorPlugin");
40
41 namespace {
42 const std::string HISIPATH = "/data/hisi_logs/";
43 const std::string BBOXPATH = "/data/log/bbox/";
44 const std::string LOGPARSECONFIG = "/system/etc/hiview";
45 const std::vector<std::string> HISTORYLOGLIST = {
46 "/data/hisi_logs/history.log",
47 "/data/log/bbox/history.log"
48 };
49 }
50
51 class BBoxDetectorPlugin::BBoxListener : public EventListener {
52 public:
53 explicit BBoxListener(BBoxDetectorPlugin& bBoxDetector);
~BBoxListener()54 ~BBoxListener() {}
55 void OnUnorderedEvent(const Event &msg) override;
56 std::string GetListenerName() override;
57
58 private:
59 BBoxDetectorPlugin& bBoxDetector_;
60 };
61
OnLoad()62 void BBoxDetectorPlugin::OnLoad()
63 {
64 SetName("BBoxDetectorPlugin");
65 SetVersion("BBoxDetector1.0");
66 auto context = GetHiviewContext();
67 if (context == nullptr) {
68 HIVIEW_LOGE("GetHiviewContext failed.");
69 return;
70 }
71 InitPanicReporter();
72
73 eventListener_ = std::make_shared<BBoxListener>(*this);
74 context->RegisterUnorderedEventListener(eventListener_);
75 eventRecorder_ = std::make_shared<BboxEventRecorder>();
76 }
77
OnUnload()78 void BBoxDetectorPlugin::OnUnload()
79 {
80 HIVIEW_LOGI("BBoxDetectorPlugin OnUnload");
81 RemoveDetectBootCompletedTask();
82 }
83
OnEvent(std::shared_ptr<Event> & event)84 bool BBoxDetectorPlugin::OnEvent(std::shared_ptr<Event> &event)
85 {
86 if (event == nullptr || event->domain_ != "KERNEL_VENDOR") {
87 return false;
88 }
89 auto sysEvent = Event::DownCastTo<SysEvent>(event);
90 HandleBBoxEvent(sysEvent);
91 return true;
92 }
93
WaitForLogs(const std::string & logDir)94 void BBoxDetectorPlugin::WaitForLogs(const std::string& logDir)
95 {
96 std::string doneFile = logDir + "/DONE";
97 if (!Tbox::WaitForDoneFile(doneFile, 60)) { // 60s
98 HIVIEW_LOGE("can not find file: %{public}s", doneFile.c_str());
99 }
100 }
101
HandleBBoxEvent(std::shared_ptr<SysEvent> & sysEvent)102 void BBoxDetectorPlugin::HandleBBoxEvent(std::shared_ptr<SysEvent> &sysEvent)
103 {
104 if (PanicReport::IsRecoveryPanicEvent(sysEvent)) {
105 return;
106 }
107 string eventName = sysEvent->GetEventName();
108 if (eventName == "CUSTOM") {
109 std::string bboxTime = sysEvent->GetEventValue("BBOX_TIME");
110 std::string bboxSysreset = sysEvent->GetEventValue("BBOX_SYSRESET");
111 PanicErrorInfoHandle::RKTransData(bboxTime, bboxSysreset);
112 }
113 std::string event = sysEvent->GetEventValue("REASON");
114 std::string module = sysEvent->GetEventValue("MODULE");
115 std::string timeStr = sysEvent->GetEventValue("SUB_LOG_PATH");
116 std::string logPath = sysEvent->GetEventValue("LOG_PATH");
117 std::string name = sysEvent->GetEventValue("name_");
118
119 std::string dynamicPaths = ((!logPath.empty() && logPath[logPath.size() - 1] == '/') ?
120 logPath : logPath + '/') + timeStr;
121 auto happenTime = static_cast<uint64_t>(Tbox::GetHappenTime(StringUtil::GetRleftSubstr(timeStr, "-"),
122 "(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})"));
123 if (HisysEventUtil::IsEventProcessed(name, "LOG_PATH", dynamicPaths) ||
124 (eventRecorder_ != nullptr && eventRecorder_->IsExistEvent(name, happenTime, dynamicPaths))) {
125 HIVIEW_LOGE("HandleBBoxEvent is processed event path is %{public}s", dynamicPaths.c_str());
126 return;
127 }
128 if (name == "PANIC" && PanicReport::IsLastShortStartUp()) {
129 PanicReport::CompressAndCopyLogFiles(dynamicPaths, timeStr);
130 }
131 if ((module == "AP") && (event == "BFM_S_NATIVE_DATA_FAIL")) {
132 sysEvent->OnFinish();
133 }
134 sysEvent->SetEventValue("HAPPEN_TIME", happenTime);
135
136 WaitForLogs(dynamicPaths);
137 auto eventInfos = SmartParser::Analysis(dynamicPaths, LOGPARSECONFIG, name);
138 Tbox::FilterTrace(eventInfos);
139
140 sysEvent->SetEventValue("FIRST_FRAME", eventInfos["FIRST_FRAME"].empty() ? "/" :
141 StringUtil::EscapeJsonStringValue(eventInfos["FIRST_FRAME"]));
142 sysEvent->SetEventValue("SECOND_FRAME", eventInfos["SECOND_FRAME"].empty() ? "/" :
143 StringUtil::EscapeJsonStringValue(eventInfos["SECOND_FRAME"]));
144 sysEvent->SetEventValue("LAST_FRAME", eventInfos["LAST_FRAME"].empty() ? "/ " :
145 StringUtil::EscapeJsonStringValue(eventInfos["LAST_FRAME"]));
146 sysEvent->SetEventValue("FINGERPRINT", Tbox::CalcFingerPrint(event + module + eventInfos["FIRST_FRAME"] +
147 eventInfos["SECOND_FRAME"] + eventInfos["LAST_FRAME"], 0, FP_BUFFER));
148 sysEvent->SetEventValue("LOG_PATH", dynamicPaths);
149 if (eventRecorder_ != nullptr) {
150 eventRecorder_->AddEventToMaps(name, happenTime, dynamicPaths);
151 }
152 HIVIEW_LOGI("HandleBBoxEvent event: %{public}s is success. happenTime %{public}" PRIu64, name.c_str(), happenTime);
153 }
154
StartBootScan()155 void BBoxDetectorPlugin::StartBootScan()
156 {
157 constexpr int oneDaySecond = 60 * 60 * 24;
158 bool hisiHistory = false;
159 for (auto historyLog : HISTORYLOGLIST) {
160 int num = READ_LINE_NUM;
161 string line;
162 if (FileUtil::FileExists(historyLog) && historyLog.find(HISIPATH) != std::string::npos) {
163 hisiHistory = true;
164 }
165
166 ifstream fin(historyLog, ios::ate);
167 while (FileUtil::GetLastLine(fin, line) && num > 0) {
168 num--;
169 std::map<std::string, std::string> historyMap = GetValueFromHistory(line, hisiHistory);
170 string name = historyMap["category"];
171 if (name.empty() || name == "NORMALBOOT") {
172 continue;
173 }
174 if (name.find(":") != std::string::npos) {
175 name = StringUtil::GetRleftSubstr(name, ":");
176 }
177 auto timeNow = TimeUtil::GetSeconds();
178 auto happenTime = GetHappenTime(line, hisiHistory);
179 if (abs(timeNow - static_cast<int64_t>(happenTime)) > oneDaySecond ||
180 HisysEventUtil::IsEventProcessed(name, "LOG_PATH", historyMap["dynamicPaths"]) ||
181 (eventRecorder_ != nullptr &&
182 eventRecorder_->IsExistEvent(name, happenTime, historyMap["dynamicPaths"]))) {
183 HIVIEW_LOGI("Skip (%{public}s:%{public}" PRIu64 ")", name.c_str(), happenTime);
184 continue;
185 }
186 int res = CheckAndHiSysEventWrite(name, historyMap, happenTime);
187 HIVIEW_LOGI("BBox write history line is %{public}s write result = %{public}d", line.c_str(), res);
188 if (eventRecorder_ != nullptr) {
189 eventRecorder_->AddEventToMaps(name, happenTime, historyMap["dynamicPaths"]);
190 }
191 }
192 }
193 eventRecorder_.reset();
194 }
195
GetHappenTime(std::string & line,bool isHisiHistory)196 uint64_t BBoxDetectorPlugin::GetHappenTime(std::string& line, bool isHisiHistory)
197 {
198 auto happenTime = isHisiHistory ?
199 static_cast<uint64_t>(Tbox::GetHappenTime(StringUtil::GetMidSubstr(line, "time [", "-"),
200 "(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})")) :
201 static_cast<uint64_t>(Tbox::GetHappenTime(StringUtil::GetMidSubstr(line, "time[", "-"),
202 "(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})"));
203
204 return happenTime;
205 }
206
CheckAndHiSysEventWrite(std::string & name,std::map<std::string,std::string> & historyMap,uint64_t & happenTime)207 int BBoxDetectorPlugin::CheckAndHiSysEventWrite(std::string& name, std::map<std::string, std::string>& historyMap,
208 uint64_t& happenTime)
209 {
210 int res = HiSysEventWrite(HisysEventUtil::KERNEL_VENDOR, name, HiSysEvent::EventType::FAULT,
211 "MODULE", historyMap["module"],
212 "REASON", historyMap["reason"],
213 "LOG_PATH", historyMap["logPath"],
214 "SUB_LOG_PATH", historyMap["subLogPath"],
215 "HAPPEN_TIME", happenTime,
216 "SUMMARY", "bootup_keypoint:" + historyMap["bootup_keypoint"]);
217 if (res == 0 || (res < 0 && name.find("UNKNOWNS") != std::string::npos)) {
218 return res;
219 } else if (res < 0) {
220 name = "UNKNOWNS";
221 CheckAndHiSysEventWrite(name, historyMap, happenTime);
222 }
223
224 return res;
225 }
226
GetValueFromHistory(std::string & line,bool isHisiHistory)227 std::map<std::string, std::string> BBoxDetectorPlugin::GetValueFromHistory(std::string& line, bool isHisiHistory)
228 {
229 std::map<std::string, std::string> historyMap = {
230 {"category", isHisiHistory ? StringUtil::GetMidSubstr(line, "category [", "]") :
231 StringUtil::GetMidSubstr(line, "category[", "]")},
232 {"module", isHisiHistory ? StringUtil::GetMidSubstr(line, "core [", "]") :
233 StringUtil::GetMidSubstr(line, "module[", "]")},
234 {"reason", isHisiHistory ? StringUtil::GetMidSubstr(line, "reason [", "]") :
235 StringUtil::GetMidSubstr(line, "event[", "]")},
236 {"bootup_keypoint", isHisiHistory ? StringUtil::GetMidSubstr(line, "bootup_keypoint [", "]") :
237 StringUtil::GetMidSubstr(line, "errdesc[", "]")},
238 {"dynamicPaths", isHisiHistory ? HISIPATH + StringUtil::GetMidSubstr(line, "time [", "]") :
239 BBOXPATH + StringUtil::GetMidSubstr(line, "time[", "]")},
240 {"logPath", isHisiHistory ? HISIPATH : BBOXPATH},
241 {"subLogPath", isHisiHistory ? StringUtil::GetMidSubstr(line, "time [", "]") :
242 StringUtil::GetMidSubstr(line, "time[", "]")}
243 };
244
245 return historyMap;
246 }
247
AddDetectBootCompletedTask()248 void BBoxDetectorPlugin::AddDetectBootCompletedTask()
249 {
250 std::lock_guard<std::mutex> lock(lock_);
251 if (workLoop_ && !timeEventAdded_) {
252 timeEventId_ = workLoop_->AddTimerEvent(nullptr, nullptr, [this] {
253 if (PanicReport::IsBootCompleted()) {
254 NotifyBootCompleted();
255 }
256 }, 1, true);
257 timeEventAdded_ = true;
258 }
259 }
260
RemoveDetectBootCompletedTask()261 void BBoxDetectorPlugin::RemoveDetectBootCompletedTask()
262 {
263 std::lock_guard<std::mutex> lock(lock_);
264 if (workLoop_ && timeEventAdded_) {
265 workLoop_->RemoveEvent(timeEventId_);
266 timeEventId_ = 0;
267 timeEventAdded_ = false;
268 }
269 }
270
NotifyBootStable()271 void BBoxDetectorPlugin::NotifyBootStable()
272 {
273 if (PanicReport::TryToReportRecoveryPanicEvent()) {
274 constexpr int timeout = 10; // 10s
275 workLoop_->AddTimerEvent(nullptr, nullptr, [] {
276 PanicReport::ConfirmReportResult();
277 }, timeout, false);
278 }
279 }
280
NotifyBootCompleted()281 void BBoxDetectorPlugin::NotifyBootCompleted()
282 {
283 HIVIEW_LOGI("System boot completed, remove the task");
284 RemoveDetectBootCompletedTask();
285 constexpr int timeout = 60 * 10; // 10min
286 workLoop_->AddTimerEvent(nullptr, nullptr, [this] {
287 NotifyBootStable();
288 }, timeout, false);
289 }
290
InitPanicReporter()291 void BBoxDetectorPlugin::InitPanicReporter()
292 {
293 if (!PanicReport::InitPanicReport()) {
294 return;
295 }
296 AddDetectBootCompletedTask();
297 }
298
AddBootScanEvent()299 void BBoxDetectorPlugin::AddBootScanEvent()
300 {
301 if (workLoop_ == nullptr) {
302 HIVIEW_LOGE("workLoop_ is nullptr.");
303 return;
304 }
305
306 auto task = [this]() {
307 StartBootScan();
308 };
309 workLoop_->AddTimerEvent(nullptr, nullptr, task, SECONDS, false); // delay 60s
310 }
311
BBoxListener(BBoxDetectorPlugin & bBoxDetector)312 BBoxDetectorPlugin::BBoxListener::BBoxListener(BBoxDetectorPlugin& bBoxDetector) : bBoxDetector_(bBoxDetector)
313 {
314 AddListenerInfo(Event::MessageType::PLUGIN_MAINTENANCE);
315 }
316
OnUnorderedEvent(const Event & msg)317 void BBoxDetectorPlugin::BBoxListener::OnUnorderedEvent(const Event &msg)
318 {
319 if (msg.messageType_ != Event::MessageType::PLUGIN_MAINTENANCE ||
320 msg.eventId_ != Event::EventId::PLUGIN_LOADED) {
321 HIVIEW_LOGE("messageType_(%{public}u), eventId_(%{public}u).", msg.messageType_, msg.eventId_);
322 return;
323 }
324 bBoxDetector_.AddBootScanEvent();
325 }
326
GetListenerName()327 std::string BBoxDetectorPlugin::BBoxListener::GetListenerName()
328 {
329 return "BBoxListener";
330 }
331 }
332 }
333