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 "plugin_factory.h"
28 #include "hisysevent_util.h"
29 #include "smart_parser.h"
30 #include "string_util.h"
31 #include "tbox.h"
32 #include "time_util.h"
33 
34 namespace OHOS {
35 namespace HiviewDFX {
36 using namespace std;
37 REGISTER(BBoxDetectorPlugin);
38 DEFINE_LOG_LABEL(0xD002D11, "BBoxDetectorPlugin");
39 
40 namespace {
41     const std::string HISIPATH = "/data/hisi_logs/";
42     const std::string BBOXPATH = "/data/log/bbox/";
43     const std::string LOGPARSECONFIG = "/system/etc/hiview";
44     const std::vector<std::string> HISTORYLOGLIST = {
45         "/data/hisi_logs/history.log",
46         "/data/log/bbox/history.log"
47     };
48 }
49 
OnLoad()50 void BBoxDetectorPlugin::OnLoad()
51 {
52     SetName("BBoxDetectorPlugin");
53     SetVersion("BBoxDetector1.0");
54     eventLoop_ = GetHiviewContext()->GetSharedWorkLoop();
55     if (eventLoop_ != nullptr) {
56         eventLoop_->AddTimerEvent(nullptr, nullptr, [&]() {
57             StartBootScan();
58         }, SECONDS, false); // delay 60s
59     }
60     InitPanicReporter();
61 }
62 
OnUnload()63 void BBoxDetectorPlugin::OnUnload()
64 {
65     HIVIEW_LOGI("BBoxDetectorPlugin OnUnload");
66     RemoveDetectBootCompletedTask();
67 }
68 
OnEvent(std::shared_ptr<Event> & event)69 bool BBoxDetectorPlugin::OnEvent(std::shared_ptr<Event> &event)
70 {
71     if (event == nullptr || event->domain_ != "KERNEL_VENDOR") {
72         return false;
73     }
74     auto sysEvent = Event::DownCastTo<SysEvent>(event);
75     HandleBBoxEvent(sysEvent);
76     return true;
77 }
78 
WaitForLogs(const std::string & logDir)79 void BBoxDetectorPlugin::WaitForLogs(const std::string& logDir)
80 {
81     std::string doneFile = logDir + "/DONE";
82     if (!Tbox::WaitForDoneFile(doneFile, 60)) { // 60s
83         HIVIEW_LOGE("can not find file: %{public}s", doneFile.c_str());
84     }
85 }
86 
HandleBBoxEvent(std::shared_ptr<SysEvent> & sysEvent)87 void BBoxDetectorPlugin::HandleBBoxEvent(std::shared_ptr<SysEvent> &sysEvent)
88 {
89     if (PanicReport::IsRecoveryPanicEvent(sysEvent)) {
90         return;
91     }
92     std::string event = sysEvent->GetEventValue("REASON");
93     std::string module = sysEvent->GetEventValue("MODULE");
94     std::string timeStr = sysEvent->GetEventValue("SUB_LOG_PATH");
95     std::string LOG_PATH = sysEvent->GetEventValue("LOG_PATH");
96     std::string name = sysEvent->GetEventValue("name_");
97 
98     std::string dynamicPaths = ((!LOG_PATH.empty() && LOG_PATH[LOG_PATH.size() - 1] == '/') ?
99                                   LOG_PATH : LOG_PATH + '/') + timeStr;
100     if (HisysEventUtil::IsEventProcessed(name, "LOG_PATH", dynamicPaths)) {
101         HIVIEW_LOGE("HandleBBoxEvent is processed event path is %{public}s", dynamicPaths.c_str());
102         return;
103     }
104     if (name == "PANIC" && PanicReport::IsLastShortStartUp()) {
105         PanicReport::CompressAndCopyLogFiles(dynamicPaths, timeStr);
106     }
107     if ((module == "AP") && (event == "BFM_S_NATIVE_DATA_FAIL")) {
108         sysEvent->OnFinish();
109     }
110     auto happenTime = static_cast<uint64_t>(Tbox::GetHappenTime(StringUtil::GetRleftSubstr(timeStr, "-"),
111         "(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})"));
112     sysEvent->SetEventValue("HAPPEN_TIME", happenTime);
113 
114     WaitForLogs(dynamicPaths);
115     auto eventInfos = SmartParser::Analysis(dynamicPaths, LOGPARSECONFIG, name);
116     Tbox::FilterTrace(eventInfos);
117 
118     sysEvent->SetEventValue("FIRST_FRAME", eventInfos["FIRST_FRAME"].empty() ? "/" :
119                                 StringUtil::EscapeJsonStringValue(eventInfos["FIRST_FRAME"]));
120     sysEvent->SetEventValue("SECOND_FRAME", eventInfos["SECOND_FRAME"].empty() ? "/" :
121                                 StringUtil::EscapeJsonStringValue(eventInfos["SECOND_FRAME"]));
122     sysEvent->SetEventValue("LAST_FRAME", eventInfos["LAST_FRAME"].empty() ? "/ " :
123                                 StringUtil::EscapeJsonStringValue(eventInfos["LAST_FRAME"]));
124     sysEvent->SetEventValue("FINGERPRINT", Tbox::CalcFingerPrint(event + module + eventInfos["FIRST_FRAME"] +
125         eventInfos["SECOND_FRAME"] + eventInfos["LAST_FRAME"], 0, FP_BUFFER));
126     sysEvent->SetEventValue("LOG_PATH", dynamicPaths);
127     HIVIEW_LOGI("HandleBBoxEvent event: %{public}s is success ", name.c_str());
128 }
129 
StartBootScan()130 void BBoxDetectorPlugin::StartBootScan()
131 {
132     for (auto historyLog : HISTORYLOGLIST) {
133         int num = READ_LINE_NUM;
134         string line;
135 
136         if (FileUtil::FileExists(historyLog) && historyLog.find(HISIPATH) != std::string::npos) {
137             hisiHistoryPath_ = true;
138         }
139 
140         ifstream fin(historyLog, ios::ate);
141         while (FileUtil::GetLastLine(fin, line) && num > 0) {
142             num--;
143             std::map<std::string, std::string> historyMap = GetValueFromHistory(line);
144             string name = historyMap["category"];
145             if (name.empty() || name == "NORMALBOOT") {
146                 continue;
147             }
148             if (name.find(":") != std::string::npos) {
149                 name = StringUtil::GetRleftSubstr(name, ":");
150             }
151             auto time_now = static_cast<int64_t>(TimeUtil::GetMilliseconds());
152             auto time_event = hisiHistoryPath_ ?
153                 static_cast<int64_t>(TimeUtil::StrToTimeStamp(StringUtil::GetMidSubstr(line, "time [", "-"),
154                 "%Y%m%d%H%M%S")) * MILLSECONDS :
155                 static_cast<int64_t>(TimeUtil::StrToTimeStamp(StringUtil::GetMidSubstr(line, "time[", "-"),
156                 "%Y%m%d%H%M%S")) * MILLSECONDS;
157             if (abs(time_now - abs(time_event)) > ONE_DAY  ||
158                 HisysEventUtil::IsEventProcessed(name, "LOG_PATH", historyMap["dynamicPaths"])) {
159                 continue;
160             }
161             auto happenTime = GetHappenTime(line);
162             int res = CheckAndHiSysEventWrite(name, historyMap, happenTime);
163             HIVIEW_LOGI("BBox write history line is %{public}s write result =  %{public}d", line.c_str(), res);
164         }
165     }
166 }
167 
GetHappenTime(std::string & line)168 uint64_t BBoxDetectorPlugin::GetHappenTime(std::string& line)
169 {
170     auto happenTime = hisiHistoryPath_ ?
171         static_cast<uint64_t>(Tbox::GetHappenTime(StringUtil::GetMidSubstr(line, "time [", "-"),
172             "(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})")) :
173         static_cast<uint64_t>(Tbox::GetHappenTime(StringUtil::GetMidSubstr(line, "time[", "-"),
174             "(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})"));
175 
176     return happenTime;
177 }
178 
CheckAndHiSysEventWrite(std::string & name,std::map<std::string,std::string> & historyMap,uint64_t & happenTime)179 int BBoxDetectorPlugin::CheckAndHiSysEventWrite(std::string& name, std::map<std::string, std::string>& historyMap,
180     uint64_t& happenTime)
181 {
182     int res = HiSysEventWrite(HisysEventUtil::KERNEL_VENDOR, name, HiSysEvent::EventType::FAULT,
183         "MODULE", historyMap["module"],
184         "REASON", historyMap["reason"],
185         "LOG_PATH", historyMap["logPath"],
186         "SUB_LOG_PATH", historyMap["subLogPath"],
187         "HAPPEN_TIME", happenTime,
188         "SUMMARY", "bootup_keypoint:" + historyMap["bootup_keypoint"]);
189     if (res == 0 || (res < 0 && name.find("UNKNOWNS") != std::string::npos)) {
190         return res;
191     } else if (res < 0) {
192         name = "UNKNOWNS";
193         CheckAndHiSysEventWrite(name, historyMap, happenTime);
194     }
195 
196     return res;
197 }
198 
GetValueFromHistory(std::string & line)199 std::map<std::string, std::string> BBoxDetectorPlugin::GetValueFromHistory(std::string& line)
200 {
201     std::map<std::string, std::string> historyMap = {
202         {"category", hisiHistoryPath_ ? StringUtil::GetMidSubstr(line, "category [", "]") :
203             StringUtil::GetMidSubstr(line, "category[", "]")},
204         {"module", hisiHistoryPath_ ? StringUtil::GetMidSubstr(line, "core [", "]") :
205             StringUtil::GetMidSubstr(line, "module[", "]")},
206         {"reason", hisiHistoryPath_ ? StringUtil::GetMidSubstr(line, "reason [", "]") :
207             StringUtil::GetMidSubstr(line, "event[", "]")},
208         {"bootup_keypoint", hisiHistoryPath_ ? StringUtil::GetMidSubstr(line, "bootup_keypoint [", "]") :
209             StringUtil::GetMidSubstr(line, "errdesc[", "]")},
210         {"dynamicPaths", hisiHistoryPath_ ? HISIPATH + StringUtil::GetMidSubstr(line, "time [", "]") :
211             BBOXPATH + StringUtil::GetMidSubstr(line, "time[", "]")},
212         {"logPath", hisiHistoryPath_ ? HISIPATH : BBOXPATH},
213         {"subLogPath", hisiHistoryPath_ ? StringUtil::GetMidSubstr(line, "time [", "]") :
214             StringUtil::GetMidSubstr(line, "time[", "]")}
215     };
216 
217     return historyMap;
218 }
219 
AddDetectBootCompletedTask()220 void BBoxDetectorPlugin::AddDetectBootCompletedTask()
221 {
222     std::lock_guard<std::mutex> lock(lock_);
223     if (eventLoop_ && !timeEventAdded_) {
224         timeEventId_ = eventLoop_->AddTimerEvent(nullptr, nullptr, [this] {
225             if (PanicReport::IsBootCompleted()) {
226                 NotifyBootCompleted();
227             }
228         }, 1, true);
229         timeEventAdded_ = true;
230     }
231 }
232 
RemoveDetectBootCompletedTask()233 void BBoxDetectorPlugin::RemoveDetectBootCompletedTask()
234 {
235     std::lock_guard<std::mutex> lock(lock_);
236     if (eventLoop_ && timeEventAdded_) {
237         eventLoop_->RemoveEvent(timeEventId_);
238         timeEventId_ = 0;
239         timeEventAdded_ = false;
240     }
241 }
242 
NotifyBootStable()243 void BBoxDetectorPlugin::NotifyBootStable()
244 {
245     if (PanicReport::TryToReportRecoveryPanicEvent()) {
246         constexpr int timeout = 10; // 10s
247         eventLoop_->AddTimerEvent(nullptr, nullptr, [] {
248             PanicReport::ConfirmReportResult();
249         }, timeout, false);
250     }
251 }
252 
NotifyBootCompleted()253 void BBoxDetectorPlugin::NotifyBootCompleted()
254 {
255     HIVIEW_LOGI("System boot completed, remove the task");
256     RemoveDetectBootCompletedTask();
257     constexpr int timeout = 60 * 10; // 10min
258     eventLoop_->AddTimerEvent(nullptr, nullptr, [this] {
259         NotifyBootStable();
260     }, timeout, false);
261 }
262 
InitPanicReporter()263 void BBoxDetectorPlugin::InitPanicReporter()
264 {
265     if (!PanicReport::InitPanicReport()) {
266         HIVIEW_LOGE("Failed to init panic reporter");
267         return;
268     }
269     AddDetectBootCompletedTask();
270 }
271 }
272 }
273