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