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 }
76
OnUnload()77 void BBoxDetectorPlugin::OnUnload()
78 {
79 HIVIEW_LOGI("BBoxDetectorPlugin OnUnload");
80 RemoveDetectBootCompletedTask();
81 }
82
OnEvent(std::shared_ptr<Event> & event)83 bool BBoxDetectorPlugin::OnEvent(std::shared_ptr<Event> &event)
84 {
85 if (event == nullptr || event->domain_ != "KERNEL_VENDOR") {
86 return false;
87 }
88 auto sysEvent = Event::DownCastTo<SysEvent>(event);
89 HandleBBoxEvent(sysEvent);
90 return true;
91 }
92
WaitForLogs(const std::string & logDir)93 void BBoxDetectorPlugin::WaitForLogs(const std::string& logDir)
94 {
95 std::string doneFile = logDir + "/DONE";
96 if (!Tbox::WaitForDoneFile(doneFile, 60)) { // 60s
97 HIVIEW_LOGE("can not find file: %{public}s", doneFile.c_str());
98 }
99 }
100
HandleBBoxEvent(std::shared_ptr<SysEvent> & sysEvent)101 void BBoxDetectorPlugin::HandleBBoxEvent(std::shared_ptr<SysEvent> &sysEvent)
102 {
103 if (PanicReport::IsRecoveryPanicEvent(sysEvent)) {
104 return;
105 }
106 string eventName = sysEvent->GetEventName();
107 if (eventName == "CUSTOM") {
108 std::string bboxTime = sysEvent->GetEventValue("BBOX_TIME");
109 std::string bboxSysreset = sysEvent->GetEventValue("BBOX_SYSRESET");
110 PanicErrorInfoHandle::RKTransData(bboxTime, bboxSysreset);
111 }
112 std::string event = sysEvent->GetEventValue("REASON");
113 std::string module = sysEvent->GetEventValue("MODULE");
114 std::string timeStr = sysEvent->GetEventValue("SUB_LOG_PATH");
115 std::string logPath = sysEvent->GetEventValue("LOG_PATH");
116 std::string name = sysEvent->GetEventValue("name_");
117
118 std::string dynamicPaths = ((!logPath.empty() && logPath[logPath.size() - 1] == '/') ?
119 logPath : logPath + '/') + timeStr;
120 if (HisysEventUtil::IsEventProcessed(name, "LOG_PATH", dynamicPaths)) {
121 HIVIEW_LOGE("HandleBBoxEvent is processed event path is %{public}s", dynamicPaths.c_str());
122 return;
123 }
124 if (name == "PANIC" && PanicReport::IsLastShortStartUp()) {
125 PanicReport::CompressAndCopyLogFiles(dynamicPaths, timeStr);
126 }
127 if ((module == "AP") && (event == "BFM_S_NATIVE_DATA_FAIL")) {
128 sysEvent->OnFinish();
129 }
130 auto happenTime = static_cast<uint64_t>(Tbox::GetHappenTime(StringUtil::GetRleftSubstr(timeStr, "-"),
131 "(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})"));
132 sysEvent->SetEventValue("HAPPEN_TIME", happenTime);
133
134 WaitForLogs(dynamicPaths);
135 auto eventInfos = SmartParser::Analysis(dynamicPaths, LOGPARSECONFIG, name);
136 Tbox::FilterTrace(eventInfos);
137
138 sysEvent->SetEventValue("FIRST_FRAME", eventInfos["FIRST_FRAME"].empty() ? "/" :
139 StringUtil::EscapeJsonStringValue(eventInfos["FIRST_FRAME"]));
140 sysEvent->SetEventValue("SECOND_FRAME", eventInfos["SECOND_FRAME"].empty() ? "/" :
141 StringUtil::EscapeJsonStringValue(eventInfos["SECOND_FRAME"]));
142 sysEvent->SetEventValue("LAST_FRAME", eventInfos["LAST_FRAME"].empty() ? "/ " :
143 StringUtil::EscapeJsonStringValue(eventInfos["LAST_FRAME"]));
144 sysEvent->SetEventValue("FINGERPRINT", Tbox::CalcFingerPrint(event + module + eventInfos["FIRST_FRAME"] +
145 eventInfos["SECOND_FRAME"] + eventInfos["LAST_FRAME"], 0, FP_BUFFER));
146 sysEvent->SetEventValue("LOG_PATH", dynamicPaths);
147 HIVIEW_LOGI("HandleBBoxEvent event: %{public}s is success ", name.c_str());
148 }
149
StartBootScan()150 void BBoxDetectorPlugin::StartBootScan()
151 {
152 for (auto historyLog : HISTORYLOGLIST) {
153 int num = READ_LINE_NUM;
154 string line;
155
156 if (FileUtil::FileExists(historyLog) && historyLog.find(HISIPATH) != std::string::npos) {
157 hisiHistoryPath_ = true;
158 }
159
160 ifstream fin(historyLog, ios::ate);
161 while (FileUtil::GetLastLine(fin, line) && num > 0) {
162 num--;
163 std::map<std::string, std::string> historyMap = GetValueFromHistory(line);
164 string name = historyMap["category"];
165 if (name.empty() || name == "NORMALBOOT") {
166 continue;
167 }
168 if (name.find(":") != std::string::npos) {
169 name = StringUtil::GetRleftSubstr(name, ":");
170 }
171 auto time_now = static_cast<int64_t>(TimeUtil::GetMilliseconds());
172 auto time_event = hisiHistoryPath_ ?
173 static_cast<int64_t>(TimeUtil::StrToTimeStamp(StringUtil::GetMidSubstr(line, "time [", "-"),
174 "%Y%m%d%H%M%S")) * MILLSECONDS :
175 static_cast<int64_t>(TimeUtil::StrToTimeStamp(StringUtil::GetMidSubstr(line, "time[", "-"),
176 "%Y%m%d%H%M%S")) * MILLSECONDS;
177 if (abs(time_now - abs(time_event)) > ONE_DAY ||
178 HisysEventUtil::IsEventProcessed(name, "LOG_PATH", historyMap["dynamicPaths"])) {
179 continue;
180 }
181 auto happenTime = GetHappenTime(line);
182 int res = CheckAndHiSysEventWrite(name, historyMap, happenTime);
183 HIVIEW_LOGI("BBox write history line is %{public}s write result = %{public}d", line.c_str(), res);
184 }
185 }
186 }
187
GetHappenTime(std::string & line)188 uint64_t BBoxDetectorPlugin::GetHappenTime(std::string& line)
189 {
190 auto happenTime = hisiHistoryPath_ ?
191 static_cast<uint64_t>(Tbox::GetHappenTime(StringUtil::GetMidSubstr(line, "time [", "-"),
192 "(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})")) :
193 static_cast<uint64_t>(Tbox::GetHappenTime(StringUtil::GetMidSubstr(line, "time[", "-"),
194 "(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})"));
195
196 return happenTime;
197 }
198
CheckAndHiSysEventWrite(std::string & name,std::map<std::string,std::string> & historyMap,uint64_t & happenTime)199 int BBoxDetectorPlugin::CheckAndHiSysEventWrite(std::string& name, std::map<std::string, std::string>& historyMap,
200 uint64_t& happenTime)
201 {
202 int res = HiSysEventWrite(HisysEventUtil::KERNEL_VENDOR, name, HiSysEvent::EventType::FAULT,
203 "MODULE", historyMap["module"],
204 "REASON", historyMap["reason"],
205 "LOG_PATH", historyMap["logPath"],
206 "SUB_LOG_PATH", historyMap["subLogPath"],
207 "HAPPEN_TIME", happenTime,
208 "SUMMARY", "bootup_keypoint:" + historyMap["bootup_keypoint"]);
209 if (res == 0 || (res < 0 && name.find("UNKNOWNS") != std::string::npos)) {
210 return res;
211 } else if (res < 0) {
212 name = "UNKNOWNS";
213 CheckAndHiSysEventWrite(name, historyMap, happenTime);
214 }
215
216 return res;
217 }
218
GetValueFromHistory(std::string & line)219 std::map<std::string, std::string> BBoxDetectorPlugin::GetValueFromHistory(std::string& line)
220 {
221 std::map<std::string, std::string> historyMap = {
222 {"category", hisiHistoryPath_ ? StringUtil::GetMidSubstr(line, "category [", "]") :
223 StringUtil::GetMidSubstr(line, "category[", "]")},
224 {"module", hisiHistoryPath_ ? StringUtil::GetMidSubstr(line, "core [", "]") :
225 StringUtil::GetMidSubstr(line, "module[", "]")},
226 {"reason", hisiHistoryPath_ ? StringUtil::GetMidSubstr(line, "reason [", "]") :
227 StringUtil::GetMidSubstr(line, "event[", "]")},
228 {"bootup_keypoint", hisiHistoryPath_ ? StringUtil::GetMidSubstr(line, "bootup_keypoint [", "]") :
229 StringUtil::GetMidSubstr(line, "errdesc[", "]")},
230 {"dynamicPaths", hisiHistoryPath_ ? HISIPATH + StringUtil::GetMidSubstr(line, "time [", "]") :
231 BBOXPATH + StringUtil::GetMidSubstr(line, "time[", "]")},
232 {"logPath", hisiHistoryPath_ ? HISIPATH : BBOXPATH},
233 {"subLogPath", hisiHistoryPath_ ? StringUtil::GetMidSubstr(line, "time [", "]") :
234 StringUtil::GetMidSubstr(line, "time[", "]")}
235 };
236
237 return historyMap;
238 }
239
AddDetectBootCompletedTask()240 void BBoxDetectorPlugin::AddDetectBootCompletedTask()
241 {
242 std::lock_guard<std::mutex> lock(lock_);
243 if (workLoop_ && !timeEventAdded_) {
244 timeEventId_ = workLoop_->AddTimerEvent(nullptr, nullptr, [this] {
245 if (PanicReport::IsBootCompleted()) {
246 NotifyBootCompleted();
247 }
248 }, 1, true);
249 timeEventAdded_ = true;
250 }
251 }
252
RemoveDetectBootCompletedTask()253 void BBoxDetectorPlugin::RemoveDetectBootCompletedTask()
254 {
255 std::lock_guard<std::mutex> lock(lock_);
256 if (workLoop_ && timeEventAdded_) {
257 workLoop_->RemoveEvent(timeEventId_);
258 timeEventId_ = 0;
259 timeEventAdded_ = false;
260 }
261 }
262
NotifyBootStable()263 void BBoxDetectorPlugin::NotifyBootStable()
264 {
265 if (PanicReport::TryToReportRecoveryPanicEvent()) {
266 constexpr int timeout = 10; // 10s
267 workLoop_->AddTimerEvent(nullptr, nullptr, [] {
268 PanicReport::ConfirmReportResult();
269 }, timeout, false);
270 }
271 }
272
NotifyBootCompleted()273 void BBoxDetectorPlugin::NotifyBootCompleted()
274 {
275 HIVIEW_LOGI("System boot completed, remove the task");
276 RemoveDetectBootCompletedTask();
277 constexpr int timeout = 60 * 10; // 10min
278 workLoop_->AddTimerEvent(nullptr, nullptr, [this] {
279 NotifyBootStable();
280 }, timeout, false);
281 }
282
InitPanicReporter()283 void BBoxDetectorPlugin::InitPanicReporter()
284 {
285 if (!PanicReport::InitPanicReport()) {
286 return;
287 }
288 AddDetectBootCompletedTask();
289 }
290
AddBootScanEvent()291 void BBoxDetectorPlugin::AddBootScanEvent()
292 {
293 if (workLoop_ == nullptr) {
294 HIVIEW_LOGE("workLoop_ is nullptr.");
295 return;
296 }
297
298 auto task = [this]() {
299 StartBootScan();
300 };
301 workLoop_->AddTimerEvent(nullptr, nullptr, task, SECONDS, false); // delay 60s
302 }
303
BBoxListener(BBoxDetectorPlugin & bBoxDetector)304 BBoxDetectorPlugin::BBoxListener::BBoxListener(BBoxDetectorPlugin& bBoxDetector) : bBoxDetector_(bBoxDetector)
305 {
306 AddListenerInfo(Event::MessageType::PLUGIN_MAINTENANCE);
307 }
308
OnUnorderedEvent(const Event & msg)309 void BBoxDetectorPlugin::BBoxListener::OnUnorderedEvent(const Event &msg)
310 {
311 if (msg.messageType_ != Event::MessageType::PLUGIN_MAINTENANCE ||
312 msg.eventId_ != Event::EventId::PLUGIN_LOADED) {
313 HIVIEW_LOGE("messageType_(%{public}u), eventId_(%{public}u).", msg.messageType_, msg.eventId_);
314 return;
315 }
316 bBoxDetector_.AddBootScanEvent();
317 }
318
GetListenerName()319 std::string BBoxDetectorPlugin::BBoxListener::GetListenerName()
320 {
321 return "BBoxListener";
322 }
323 }
324 }
325