1 /*
2 * Copyright (c) 2024 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
16 #include "panic_report_recovery.h"
17
18 #include <regex>
19 #include <cstdlib>
20
21 #include "file_util.h"
22 #include "hiview_logger.h"
23 #include "hiview_zip_util.h"
24 #include "hisysevent.h"
25 #include "hisysevent_util.h"
26 #include "parameters.h"
27 #include "string_util.h"
28 #include "tbox.h"
29
30 namespace OHOS {
31 namespace HiviewDFX {
32 namespace PanicReport {
33 DEFINE_LOG_LABEL(0xD002D11, "PanicReport");
34
35 #ifdef UNITTEST
36 constexpr const char* BBOX_PARAM_PATH = "/data/test/bbox/bbox.save.log.flags";
37 constexpr const char* PANIC_LOG_PATH = "/data/test/bbox/panic_log/";
38 #else
39 constexpr const char* BBOX_PARAM_PATH = "/log/reliability/bbox/bbox.save.log.flags";
40 constexpr const char* PANIC_LOG_PATH = "/log/reliability/bbox/panic_log/";
41 #endif
42 constexpr const char* FACTORY_RECOVERY_TIME_PATH = "/log/reliability/bbox/factory.recovery.time";
43 constexpr const char* CMD_LINE = "/proc/cmdline";
44
45 constexpr const char* LAST_FASTBOOT_LOG = "/ap_log/last_fastboot_log";
46 constexpr const char* HM_KLOG = "/ap_log/hm_klog.txt";
47 constexpr const char* HM_SNAPSHOT = "/ap_log/hm_snapshot.txt";
48
49 constexpr const char* BOOTEVENT_BOOT_COMPLETED = "bootevent.boot.completed";
50 constexpr const char* LAST_BOOTUP_KEYPOINT = "last_bootup_keypoint";
51
52 constexpr const char* HAPPEN_TIME = "happentime";
53 constexpr const char* FACTORY_RECOVERY_TIME = "factoryRecoveryTime";
54 constexpr const char* IS_PANIC_UPLOADED = "isPanicUploaded";
55 constexpr const char* IS_STARTUP_SHORT = "isStartUpShort";
56 constexpr const char* SOFTWARE_VERSION = "softwareVersion";
57
58 constexpr const char* REGEX_FORMAT = R"(=((".*?")|(\S*)))";
59
60 constexpr int COMPRESSION_RATION = 9;
61 constexpr int ZIP_FILE_SIZE_LIMIT = 5 * 1024 * 1024; // 5MB
62
63 static bool g_isLastStartUpShort = false;
64
InitPanicConfigFile()65 bool InitPanicConfigFile()
66 {
67 if (FileUtil::CreateFile(BBOX_PARAM_PATH, FileUtil::FILE_PERM_640) != 0) {
68 return false;
69 }
70 BboxSaveLogFlags bboxSaveLogFlags = LoadBboxSaveFlagFromFile();
71 g_isLastStartUpShort = bboxSaveLogFlags.isStartUpShort;
72 bboxSaveLogFlags.isStartUpShort = true;
73 return SaveBboxLogFlagsToFile(bboxSaveLogFlags);
74 }
75
LoadBboxSaveFlagFromFile()76 BboxSaveLogFlags LoadBboxSaveFlagFromFile()
77 {
78 std::string content;
79 if (!FileUtil::LoadStringFromFile(BBOX_PARAM_PATH, content)) {
80 HIVIEW_LOGE("Failed to load file: %{public}s.", BBOX_PARAM_PATH);
81 return {};
82 }
83 return {
84 .happenTime = GetParamValueFromString(content, HAPPEN_TIME),
85 .factoryRecoveryTime = GetParamValueFromString(content, FACTORY_RECOVERY_TIME),
86 .softwareVersion = GetParamValueFromString(content, SOFTWARE_VERSION),
87 .isPanicUploaded = GetParamValueFromString(content, IS_PANIC_UPLOADED) != "false",
88 .isStartUpShort = GetParamValueFromString(content, IS_STARTUP_SHORT) == "true"
89 };
90 }
91
SaveBboxLogFlagsToFile(const BboxSaveLogFlags & bboxSaveLogFlags)92 bool SaveBboxLogFlagsToFile(const BboxSaveLogFlags& bboxSaveLogFlags)
93 {
94 std::stringstream ss;
95 ss << HAPPEN_TIME << "=" << bboxSaveLogFlags.happenTime <<
96 " " << FACTORY_RECOVERY_TIME << "=" << bboxSaveLogFlags.factoryRecoveryTime <<
97 " " << SOFTWARE_VERSION << "=" << bboxSaveLogFlags.softwareVersion <<
98 " " << IS_PANIC_UPLOADED << "=" << (bboxSaveLogFlags.isPanicUploaded ? "true" : "false") <<
99 " " << IS_STARTUP_SHORT << "=" << (bboxSaveLogFlags.isStartUpShort ? "true" : "false");
100 if (!FileUtil::SaveStringToFile(BBOX_PARAM_PATH, ss.str())) {
101 HIVIEW_LOGE("failed to save the msg to file: %{public}s", BBOX_PARAM_PATH);
102 return false;
103 }
104 return true;
105 }
106
InitPanicReport()107 bool InitPanicReport()
108 {
109 auto fileSize = FileUtil::GetFolderSize(PANIC_LOG_PATH);
110 if (fileSize > ZIP_FILE_SIZE_LIMIT) {
111 HIVIEW_LOGW("zip file size: %{public}" PRIu64 " is over limit", fileSize);
112 ClearFilesInDir(PANIC_LOG_PATH);
113 }
114 return InitPanicConfigFile() ;
115 }
116
ClearFilesInDir(const std::filesystem::path & dirPath)117 bool ClearFilesInDir(const std::filesystem::path& dirPath)
118 {
119 if (!std::filesystem::is_directory(dirPath)) {
120 HIVIEW_LOGE("The file %{public}s is not a directory.", dirPath.c_str());
121 return false;
122 }
123 bool ret = true;
124 for (const auto& entry : std::filesystem::directory_iterator(dirPath)) {
125 std::error_code errorCode;
126 if (!std::filesystem::remove_all(entry.path(), errorCode)) {
127 HIVIEW_LOGE("Failed to deleted %{public}s errorCode: %{public}d",
128 entry.path().c_str(), errorCode.value());
129 ret = false;
130 }
131 }
132 return ret;
133 }
134
IsBootCompleted()135 bool IsBootCompleted()
136 {
137 return OHOS::system::GetParameter(BOOTEVENT_BOOT_COMPLETED, "false") == "true";
138 }
139
IsLastShortStartUp()140 bool IsLastShortStartUp()
141 {
142 if (g_isLastStartUpShort) {
143 return true;
144 }
145 std::string lastBootUpKeyPoint = GetParamValueFromFile(CMD_LINE, LAST_BOOTUP_KEYPOINT);
146 if (lastBootUpKeyPoint.empty()) {
147 return false;
148 }
149 constexpr int normalNum = 250;
150 return atoi(lastBootUpKeyPoint.c_str()) < normalNum;
151 }
152
IsRecoveryPanicEvent(const std::shared_ptr<SysEvent> & sysEvent)153 bool IsRecoveryPanicEvent(const std::shared_ptr<SysEvent>& sysEvent)
154 {
155 std::string logPath = sysEvent->GetEventValue("LOG_PATH");
156 return logPath.find(PANIC_LOG_PATH) == 0;
157 }
158
GetLastRecoveryTime()159 std::string GetLastRecoveryTime()
160 {
161 std::string factoryRecoveryTime;
162 FileUtil::LoadStringFromFile(FACTORY_RECOVERY_TIME_PATH, factoryRecoveryTime);
163 return std::string("\"") + factoryRecoveryTime + "\"";
164 }
165
GetCurrentVersion()166 std::string GetCurrentVersion()
167 {
168 std::string currentVersion = OHOS::system::GetParameter("const.product.software.version", "unknown");
169 return std::string("\"") + currentVersion + "\"";
170 }
171
GetBackupFilePath(const std::string & timeStr)172 std::string GetBackupFilePath(const std::string& timeStr)
173 {
174 return std::string(PANIC_LOG_PATH) + "panic_log_" + timeStr + ".zip";
175 }
176
GetParamValueFromString(const std::string & content,const std::string & param)177 std::string GetParamValueFromString(const std::string& content, const std::string& param)
178 {
179 std::smatch matchStr;
180 if (!std::regex_search(content, matchStr, std::regex(param + REGEX_FORMAT))) {
181 return "";
182 }
183 return matchStr[1].str();
184 }
185
GetParamValueFromFile(const std::string & filePath,const std::string & param)186 std::string GetParamValueFromFile(const std::string& filePath, const std::string& param)
187 {
188 std::string content;
189 if (!FileUtil::LoadStringFromFile(filePath, content)) {
190 HIVIEW_LOGE("Failed to load file: %{public}s.", filePath.c_str());
191 return "";
192 }
193 return GetParamValueFromString(content, param);
194 }
195
AddFileToZip(HiviewZipUnit & hiviewZipUnit,const std::string & path)196 void AddFileToZip(HiviewZipUnit& hiviewZipUnit, const std::string& path)
197 {
198 if (hiviewZipUnit.AddFileInZip(path, ZipFileLevel::KEEP_NONE_PARENT_PATH) != 0) {
199 HIVIEW_LOGW("Failed to add file: %{public}s to zip", path.c_str());
200 }
201 }
202
CompressAndCopyLogFiles(const std::string & srcPath,const std::string & timeStr)203 void CompressAndCopyLogFiles(const std::string& srcPath, const std::string& timeStr)
204 {
205 if (!FileUtil::FileExists(PANIC_LOG_PATH)) {
206 HIVIEW_LOGE("The path of target file: %{public}s is not existed", PANIC_LOG_PATH);
207 return;
208 }
209 ClearFilesInDir(PANIC_LOG_PATH);
210 HiviewZipUnit hiviewZipUnit(GetBackupFilePath(timeStr));
211 std::string lastFastBootLog = srcPath + LAST_FASTBOOT_LOG;
212 AddFileToZip(hiviewZipUnit, lastFastBootLog);
213 std::string hmKLog = srcPath + HM_KLOG;
214 AddFileToZip(hiviewZipUnit, hmKLog);
215 std::string hmSnapShot = srcPath + HM_SNAPSHOT;
216 uint64_t sourceFileSize = FileUtil::GetFileSize(lastFastBootLog) + FileUtil::GetFileSize(hmKLog) +
217 FileUtil::GetFileSize(hmSnapShot);
218 if (sourceFileSize < COMPRESSION_RATION * ZIP_FILE_SIZE_LIMIT) {
219 AddFileToZip(hiviewZipUnit, hmSnapShot);
220 } else {
221 HIVIEW_LOGW("sourceFileSize size: %{public}" PRIu64 " is over limit, dropping hmSnapShot.", sourceFileSize);
222 }
223 uint64_t zipFileSize = FileUtil::GetFolderSize(PANIC_LOG_PATH);
224 if (zipFileSize > ZIP_FILE_SIZE_LIMIT) {
225 HIVIEW_LOGW("zip file size: %{public}" PRIu64 " is over limit", zipFileSize);
226 ClearFilesInDir(PANIC_LOG_PATH);
227 return;
228 }
229 BboxSaveLogFlags bboxSaveLogFlags = LoadBboxSaveFlagFromFile();
230 bboxSaveLogFlags.happenTime = timeStr;
231 bboxSaveLogFlags.factoryRecoveryTime = GetLastRecoveryTime();
232 bboxSaveLogFlags.isPanicUploaded = false;
233 bboxSaveLogFlags.softwareVersion = GetCurrentVersion();
234 SaveBboxLogFlagsToFile(bboxSaveLogFlags);
235 }
236
ReportPanicEventAfterRecovery(const BboxSaveLogFlags & bboxSaveLogFlags)237 void ReportPanicEventAfterRecovery(const BboxSaveLogFlags& bboxSaveLogFlags)
238 {
239 const std::string& timeStr = bboxSaveLogFlags.happenTime;
240 int64_t happenTime = Tbox::GetHappenTime(StringUtil::GetRleftSubstr(timeStr, "-"),
241 "(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})");
242 HiSysEventWrite(
243 HisysEventUtil::KERNEL_VENDOR,
244 "PANIC",
245 HiSysEvent::EventType::FAULT,
246 "MODULE", "AP",
247 "REASON", "HM_PANIC:HM_PANIC_SYSMGR",
248 "LOG_PATH", GetBackupFilePath(timeStr),
249 "SUB_LOG_PATH", timeStr,
250 "HAPPEN_TIME", happenTime,
251 "FIRST_FRAME", "RECOVERY_PANIC",
252 "LAST_FRAME", bboxSaveLogFlags.softwareVersion,
253 "FINGERPRINT", Tbox::CalcFingerPrint(timeStr + bboxSaveLogFlags.softwareVersion, 0, FP_BUFFER)
254 );
255 }
256
TryToReportRecoveryPanicEvent()257 bool TryToReportRecoveryPanicEvent()
258 {
259 BboxSaveLogFlags bboxSaveLogFlags = LoadBboxSaveFlagFromFile();
260 bool ret = false;
261 if (!bboxSaveLogFlags.isPanicUploaded && bboxSaveLogFlags.factoryRecoveryTime != GetLastRecoveryTime()) {
262 if (FileUtil::FileExists(GetBackupFilePath(bboxSaveLogFlags.happenTime))) {
263 ReportPanicEventAfterRecovery(bboxSaveLogFlags);
264 ret = true;
265 }
266 }
267 bboxSaveLogFlags.isStartUpShort = false;
268 SaveBboxLogFlagsToFile(bboxSaveLogFlags);
269 return ret;
270 }
271
ConfirmReportResult()272 void ConfirmReportResult()
273 {
274 BboxSaveLogFlags bboxSaveLogFlags = LoadBboxSaveFlagFromFile();
275 const std::string& timeStr = bboxSaveLogFlags.happenTime;
276 if (HisysEventUtil::IsEventProcessed("PANIC", "LOG_PATH", GetBackupFilePath(timeStr))) {
277 bboxSaveLogFlags.isPanicUploaded = true;
278 SaveBboxLogFlagsToFile(bboxSaveLogFlags);
279 }
280 }
281 }
282 }
283 }