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