• 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 "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