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 #define LOG_TAG "RdbFaultHiViewReporter"
16
17 #include "rdb_fault_hiview_reporter.h"
18
19 #include <fcntl.h>
20 #include <unistd.h>
21
22 #include <chrono>
23 #include <iomanip>
24 #include <mutex>
25 #include <sstream>
26 #include <unordered_map>
27 #include <limits>
28
29 #include "connection.h"
30 #include "hisysevent_c.h"
31 #include "logger.h"
32 #include "rdb_errno.h"
33 #include "sqlite_global_config.h"
34 #include "sqlite_utils.h"
35 #include "rdb_time_utils.h"
36
37 namespace OHOS::NativeRdb {
38 using namespace OHOS::Rdb;
39 static constexpr const char *CORRUPTED_EVENT = "DATABASE_CORRUPTED";
40 static constexpr const char *FAULT_EVENT = "DISTRIBUTED_DATA_RDB_FAULT";
41 static constexpr const char *DISTRIBUTED_DATAMGR = "DISTDATAMGR";
42 static constexpr const char *DB_CORRUPTED_POSTFIX = ".corruptedflg";
43 static constexpr int MAX_FAULT_TIMES = 1;
44 static constexpr const char *RAG_FAULT_EVENT_NAME = "ARKDATA_RAG_FRAMEWORK_FAULT";
45 RdbFaultHiViewReporter::Collector RdbFaultHiViewReporter::collector_ = nullptr;
46
47 RdbFaultCode RdbFaultHiViewReporter::faultCounters_[] = {
48 { E_DATABASE_BUSY, 0 },
49 { E_CREATE_FOLDER_FAIL, 0 },
50 { E_WAL_SIZE_OVER_LIMIT, 0 },
51 { E_SQLITE_FULL, 0 },
52 { E_SQLITE_CORRUPT, 0 },
53 { E_SQLITE_PERM, 0 },
54 { E_SQLITE_BUSY, 0 },
55 { E_SQLITE_LOCKED, 0 },
56 { E_SQLITE_NOMEM, 0 },
57 { E_SQLITE_IOERR, 0 },
58 { E_SQLITE_CANTOPEN, 0 },
59 { E_SQLITE_CONSTRAINT, 0 },
60 { E_SQLITE_NOT_DB, 0 },
61 { E_ROOT_KEY_FAULT, 0 },
62 { E_ROOT_KEY_NOT_LOAD, 0 },
63 { E_WORK_KEY_FAIL, 0 },
64 { E_WORK_KEY_ENCRYPT_FAIL, 0 },
65 { E_WORK_KEY_DECRYPT_FAIL, 0 },
66 { E_SET_ENCRYPT_FAIL, 0 },
67 { E_SET_NEW_ENCRYPT_FAIL, 0 },
68 { E_SET_SERVICE_ENCRYPT_FAIL, 0 },
69 { E_CHECK_POINT_FAIL, 0 },
70 { E_SQLITE_META_RECOVERED, 0 },
71 { E_DFX_IS_NOT_CREATE, 0 },
72 { E_DFX_IS_DELETE, 0 },
73 { E_DFX_IS_RENAME, 0 },
74 { E_DFX_IS_NOT_EXIST, 0 },
75 { E_DFX_SQLITE_LOG, 0 },
76 { E_DFX_BATCH_INSERT_ARGS_SIZE, 0 },
77 { E_DFX_GET_JOURNAL_FAIL, 0 },
78 { E_DFX_SET_JOURNAL_FAIL, 0 },
79 { E_DFX_DUMP_INFO, 0 },
80 { E_DFX_GROUPID_INFO, 0 }
81 };
82
83 bool RdbFaultHiViewReporter::memCorruptReportedFlg_ = false;
84
ReportCorruptedOnce(const RdbCorruptedEvent & eventInfo)85 void RdbFaultHiViewReporter::ReportCorruptedOnce(const RdbCorruptedEvent &eventInfo)
86 {
87 if (IsReportCorruptedFault(eventInfo.path)) {
88 RdbCorruptedEvent eventInfoAppend = eventInfo;
89 eventInfoAppend.appendix += SqliteUtils::FormatDebugInfo(eventInfoAppend.debugInfos, "");
90 eventInfoAppend.appendix += SqliteUtils::FormatDfxInfo(eventInfo.dfxInfo);
91 LOG_WARN("Corrupted %{public}s errCode:0x%{public}x [%{public}s]",
92 SqliteUtils::Anonymous(eventInfoAppend.storeName).c_str(), eventInfoAppend.errorCode,
93 eventInfoAppend.appendix.c_str());
94 ReportCorrupted(eventInfoAppend);
95 CreateCorruptedFlag(eventInfo.path);
96 }
97 }
98
ReportRestore(const RdbCorruptedEvent & eventInfo,bool repair)99 void RdbFaultHiViewReporter::ReportRestore(const RdbCorruptedEvent &eventInfo, bool repair)
100 {
101 if (IsReportCorruptedFault(eventInfo.path) && repair) {
102 return;
103 }
104 RdbCorruptedEvent eventInfoAppend = eventInfo;
105 eventInfoAppend.appendix += SqliteUtils::FormatDebugInfo(eventInfoAppend.debugInfos, "");
106 LOG_INFO("Restored %{public}s errCode:0x%{public}x [%{public}s]",
107 SqliteUtils::Anonymous(eventInfo.storeName).c_str(), eventInfo.errorCode, eventInfoAppend.appendix.c_str());
108 ReportCorrupted(eventInfoAppend);
109 DeleteCorruptedFlag(eventInfo.path);
110 }
111
ReportCorrupted(const RdbCorruptedEvent & eventInfo)112 void RdbFaultHiViewReporter::ReportCorrupted(const RdbCorruptedEvent &eventInfo)
113 {
114 std::string bundleName = GetBundleName(eventInfo.bundleName, eventInfo.storeName);
115 std::string moduleName = eventInfo.moduleName;
116 std::string storeType = eventInfo.storeType;
117 std::string storeName = eventInfo.storeName;
118 uint32_t checkType = eventInfo.integrityCheck;
119 std::string appendInfo = eventInfo.appendix;
120 std::string occurTime = RdbTimeUtils::GetCurSysTimeWithMs();
121 HiSysEventParam params[] = {
122 { .name = "BUNDLE_NAME", .t = HISYSEVENT_STRING, .v = { .s = bundleName.data() }, .arraySize = 0 },
123 { .name = "MODULE_NAME", .t = HISYSEVENT_STRING, .v = { .s = moduleName.data() }, .arraySize = 0 },
124 { .name = "STORE_TYPE", .t = HISYSEVENT_STRING, .v = { .s = storeType.data() }, .arraySize = 0 },
125 { .name = "STORE_NAME", .t = HISYSEVENT_STRING, .v = { .s = storeName.data() }, .arraySize = 0 },
126 { .name = "SECURITY_LEVEL", .t = HISYSEVENT_UINT32, .v = { .ui32 = eventInfo.securityLevel }, .arraySize = 0 },
127 { .name = "PATH_AREA", .t = HISYSEVENT_UINT32, .v = { .ui32 = eventInfo.pathArea }, .arraySize = 0 },
128 { .name = "ENCRYPT_STATUS", .t = HISYSEVENT_UINT32, .v = { .ui32 = eventInfo.encryptStatus }, .arraySize = 0 },
129 { .name = "INTEGRITY_CHECK", .t = HISYSEVENT_UINT32, .v = { .ui32 = checkType }, .arraySize = 0 },
130 { .name = "ERROR_CODE", .t = HISYSEVENT_UINT32, .v = { .ui32 = eventInfo.errorCode }, .arraySize = 0 },
131 { .name = "ERRNO", .t = HISYSEVENT_INT32, .v = { .i32 = eventInfo.systemErrorNo }, .arraySize = 0 },
132 { .name = "APPENDIX", .t = HISYSEVENT_STRING, .v = { .s = appendInfo.data() }, .arraySize = 0 },
133 { .name = "ERROR_TIME", .t = HISYSEVENT_STRING, .v = { .s = occurTime.data() }, .arraySize = 0 },
134 };
135 auto size = sizeof(params) / sizeof(params[0]);
136 OH_HiSysEvent_Write(DISTRIBUTED_DATAMGR, CORRUPTED_EVENT, HISYSEVENT_FAULT, params, size);
137 }
138
ReportRAGFault(const std::string & errMsg,const std::string & functionName,const std::string & bundleName,const int faultType,const int errCode)139 void RdbFaultHiViewReporter::ReportRAGFault(const std::string &errMsg, const std::string &functionName,
140 const std::string &bundleName, const int faultType, const int errCode)
141 {
142 std::string appendix = "";
143 HiSysEventParam params[] = {
144 { .name = "FAULT_TYPE", .t = HISYSEVENT_INT32,
145 .v = { .ui32 = faultType}, .arraySize = 0 },
146 { .name = "ERROR_CODE", .t = HISYSEVENT_INT32,
147 .v = { .ui32 = errCode}, .arraySize = 0 },
148 { .name = "ERROR_MESSAGE", .t = HISYSEVENT_STRING,
149 .v = { .s = const_cast<char *>(errMsg.c_str()) }, .arraySize = 0 },
150 { .name = "BUNDLE_NAME", .t = HISYSEVENT_STRING,
151 .v = { .s = const_cast<char *>(bundleName.c_str()) }, .arraySize = 0 },
152 { .name = "FUNCTION_NAME", .t = HISYSEVENT_STRING,
153 .v = { .s = const_cast<char *>(functionName.c_str()) }, .arraySize = 0 },
154 { .name = "APPENDIX", .t = HISYSEVENT_STRING,
155 .v = { .s = const_cast<char *>(appendix.c_str()) }, .arraySize = 0 },
156 };
157
158 OH_HiSysEvent_Write(DISTRIBUTED_DATAMGR, RAG_FAULT_EVENT_NAME,
159 HISYSEVENT_FAULT, params, sizeof(params) / sizeof(params[0]));
160 }
161
IsReportCorruptedFault(const std::string & dbPath)162 bool RdbFaultHiViewReporter::IsReportCorruptedFault(const std::string &dbPath)
163 {
164 if (dbPath.empty() || memCorruptReportedFlg_) {
165 return false;
166 }
167
168 std::string flagFilename = dbPath + DB_CORRUPTED_POSTFIX;
169 if (access(flagFilename.c_str(), F_OK) == 0) {
170 return false;
171 }
172 return true;
173 }
174
CreateCorruptedFlag(const std::string & dbPath)175 void RdbFaultHiViewReporter::CreateCorruptedFlag(const std::string &dbPath)
176 {
177 memCorruptReportedFlg_ = true;
178 if (dbPath.empty()) {
179 return;
180 }
181 std::string flagFilename = dbPath + DB_CORRUPTED_POSTFIX;
182 int fd = creat(flagFilename.c_str(), S_IRUSR | S_IWUSR);
183 if (fd == -1) {
184 LOG_WARN("Creat corrupted flg fail, flgname=%{public}s, errno=%{public}d",
185 SqliteUtils::Anonymous(flagFilename).c_str(), errno);
186 return;
187 }
188 close(fd);
189 }
190
DeleteCorruptedFlag(const std::string & dbPath)191 void RdbFaultHiViewReporter::DeleteCorruptedFlag(const std::string &dbPath)
192 {
193 if (dbPath.empty()) {
194 return;
195 }
196 std::string flagFilename = dbPath + DB_CORRUPTED_POSTFIX;
197 int result = remove(flagFilename.c_str());
198 if (result != 0) {
199 LOG_WARN("Remove corrupted flg fail, flgname=%{public}s, errno=%{public}d",
200 SqliteUtils::Anonymous(flagFilename).c_str(), errno);
201 }
202 }
203
Create(const RdbStoreConfig & config,int32_t errCode,const std::string & appendix,bool needSyncParaFromSrv)204 RdbCorruptedEvent RdbFaultHiViewReporter::Create(
205 const RdbStoreConfig &config, int32_t errCode, const std::string &appendix, bool needSyncParaFromSrv)
206 {
207 RdbCorruptedEvent eventInfo;
208 eventInfo.bundleName = config.GetBundleName();
209 eventInfo.moduleName = config.GetModuleName();
210 eventInfo.storeType = config.GetDBType() == DB_SQLITE ? "RDB" : "VECTOR DB";
211 eventInfo.storeName = SqliteUtils::Anonymous(config.GetName());
212 eventInfo.securityLevel = static_cast<uint32_t>(config.GetSecurityLevel());
213 eventInfo.pathArea = static_cast<uint32_t>(config.GetArea());
214 eventInfo.encryptStatus = static_cast<uint32_t>(config.IsEncrypt());
215 eventInfo.integrityCheck = static_cast<uint32_t>(config.GetIntegrityCheck());
216 eventInfo.errorCode = static_cast<uint32_t>(errCode);
217 eventInfo.systemErrorNo = errCode == E_OK ? 0 : errno;
218 eventInfo.appendix = appendix;
219 eventInfo.errorOccurTime = time(nullptr);
220 eventInfo.debugInfos = Connection::Collect(config);
221 SqliteGlobalConfig::GetDbPath(config, eventInfo.path);
222 if (collector_ != nullptr && needSyncParaFromSrv) {
223 std::map<std::string, DistributedRdb::RdbDebugInfo> serviceDebugInfos;
224 if (collector_(config, serviceDebugInfos, eventInfo.dfxInfo) == E_OK) {
225 Update(eventInfo.debugInfos, serviceDebugInfos);
226 }
227 }
228 return eventInfo;
229 }
230
RegCollector(Collector collector)231 bool RdbFaultHiViewReporter::RegCollector(Collector collector)
232 {
233 if (collector_ != nullptr) {
234 return false;
235 }
236 collector_ = collector;
237 return true;
238 }
239
Update(std::map<std::string,DebugInfo> & localInfos,const std::map<std::string,DebugInfo> & infos)240 void RdbFaultHiViewReporter::Update(std::map<std::string, DebugInfo> &localInfos,
241 const std::map<std::string, DebugInfo> &infos)
242 {
243 auto &local = localInfos;
244 auto lIt = local.begin();
245 auto rIt = infos.begin();
246 for (; lIt != local.end() && rIt != infos.end();) {
247 if (lIt->first == rIt->first) {
248 if (lIt->second.inode_ != rIt->second.inode_) {
249 lIt->second.oldInode_ = rIt->second.inode_;
250 }
251 ++lIt;
252 ++rIt;
253 continue;
254 }
255 if (lIt->first < rIt->first) {
256 ++lIt;
257 } else {
258 ++rIt;
259 }
260 }
261 }
262
GetBundleName(const std::string & bundleName,const std::string & storeName)263 std::string RdbFaultHiViewReporter::GetBundleName(const std::string &bundleName, const std::string &storeName)
264 {
265 if (!bundleName.empty()) {
266 return bundleName;
267 }
268 return SqliteUtils::Anonymous(storeName);
269 }
270
GetFaultCounter(int32_t errCode)271 uint8_t *RdbFaultHiViewReporter::GetFaultCounter(int32_t errCode)
272 {
273 auto it = std::lower_bound(faultCounters_, faultCounters_ + sizeof(faultCounters_) / sizeof(RdbFaultCode), errCode,
274 [](const RdbFaultCode& faultCode, int32_t code) {
275 return faultCode.nativeCode < code;
276 });
277 if (it != faultCounters_ + sizeof(faultCounters_) / sizeof(RdbFaultCode) && it->nativeCode == errCode) {
278 return &it->faultCounter;
279 }
280 return nullptr;
281 }
282
IsReportFault(const std::string & bundleName,int32_t errCode)283 bool RdbFaultHiViewReporter::IsReportFault(const std::string &bundleName, int32_t errCode)
284 {
285 if (bundleName.empty()) {
286 return false;
287 }
288 uint8_t *counter = GetFaultCounter(errCode);
289 if (counter == nullptr) {
290 return false;
291 }
292 if (*counter < UINT8_MAX) {
293 (*counter)++;
294 }
295 return *counter <= MAX_FAULT_TIMES;
296 }
297
ReportFault(const RdbFaultEvent & faultEvent)298 void RdbFaultHiViewReporter::ReportFault(const RdbFaultEvent &faultEvent)
299 {
300 if (!IsReportFault(faultEvent.GetBundleName(), faultEvent.GetErrCode())) {
301 return;
302 }
303 faultEvent.Report();
304 }
305
RdbFaultEvent(const std::string & faultType,int32_t errorCode,const std::string & bundleName,const std::string & custLog)306 RdbFaultEvent::RdbFaultEvent(const std::string &faultType, int32_t errorCode, const std::string &bundleName,
307 const std::string &custLog)
308 {
309 faultType_ = faultType;
310 errorCode_ = errorCode;
311 bundleName_ = bundleName;
312 custLog_ = custLog;
313 }
314
Report() const315 void RdbFaultEvent::Report() const
316 {
317 std::string occurTime = RdbTimeUtils::GetCurSysTimeWithMs();
318 std::string bundleName = GetBundleName();
319 std::string faultType = GetFaultType();
320 std::string appendInfo = GetLogInfo();
321 HiSysEventParam params[] = {
322 { .name = "FAULT_TIME", .t = HISYSEVENT_STRING, .v = { .s = occurTime.data() }, .arraySize = 0 },
323 { .name = "FAULT_TYPE", .t = HISYSEVENT_STRING, .v = { .s = faultType.data() }, .arraySize = 0 },
324 { .name = "BUNDLE_NAME", .t = HISYSEVENT_STRING, .v = { .s = bundleName.data() }, .arraySize = 0 },
325 { .name = "ERROR_CODE", .t = HISYSEVENT_INT32, .v = { .ui32 = static_cast<uint32_t>(errorCode_) },
326 .arraySize = 0 },
327 { .name = "APPENDIX", .t = HISYSEVENT_STRING, .v = { .s = appendInfo.data() }, .arraySize = 0 },
328 };
329 auto size = sizeof(params) / sizeof(params[0]);
330 OH_HiSysEvent_Write(DISTRIBUTED_DATAMGR, FAULT_EVENT, HISYSEVENT_FAULT, params, size);
331 }
332
RdbFaultDbFileEvent(const std::string & faultType,int32_t errorCode,const RdbStoreConfig & config,const std::string & custLog,bool printDbInfo)333 RdbFaultDbFileEvent::RdbFaultDbFileEvent(const std::string &faultType, int32_t errorCode, const RdbStoreConfig &config,
334 const std::string &custLog, bool printDbInfo)
335 : RdbFaultEvent(faultType, errorCode, config.GetBundleName(), custLog), config_(config), printDbInfo_(printDbInfo)
336 {
337 }
338
Report() const339 void RdbFaultDbFileEvent::Report() const
340 {
341 std::string occurTime = RdbTimeUtils::GetCurSysTimeWithMs();
342 std::string bundleName = GetBundleName();
343 std::string faultType = GetFaultType();
344 std::string moduleName = config_.GetModuleName();
345 std::string storeName = config_.GetName();
346 std::string businessType = config_.GetDBType() == DB_SQLITE ? "SQLITE" : "VECTOR";
347 std::string appendInfo = BuildLogInfo();
348
349 HiSysEventParam params[] = {
350 { .name = "FAULT_TIME", .t = HISYSEVENT_STRING, .v = { .s = occurTime.data() }, .arraySize = 0 },
351 { .name = "FAULT_TYPE", .t = HISYSEVENT_STRING, .v = { .s = faultType.data() }, .arraySize = 0 },
352 { .name = "BUNDLE_NAME", .t = HISYSEVENT_STRING, .v = { .s = bundleName.data() }, .arraySize = 0 },
353 { .name = "MODULE_NAME", .t = HISYSEVENT_STRING, .v = { .s = moduleName.data() }, .arraySize = 0 },
354 { .name = "STORE_NAME", .t = HISYSEVENT_STRING, .v = { .s = storeName.data() }, .arraySize = 0 },
355 { .name = "BUSINESS_TYPE", .t = HISYSEVENT_STRING, .v = { .s = businessType.data() }, .arraySize = 0 },
356 { .name = "ERROR_CODE", .t = HISYSEVENT_INT32, .v = { .ui32 = static_cast<uint32_t>(GetErrCode())},
357 .arraySize = 0 },
358 { .name = "APPENDIX", .t = HISYSEVENT_STRING, .v = { .s = appendInfo.data() }, .arraySize = 0 },
359 };
360 auto size = sizeof(params) / sizeof(params[0]);
361 OH_HiSysEvent_Write(DISTRIBUTED_DATAMGR, FAULT_EVENT, HISYSEVENT_FAULT, params, size);
362 }
363
BuildConfigLog() const364 std::string RdbFaultDbFileEvent::BuildConfigLog() const
365 {
366 std::string errNoStr = std::to_string(static_cast<uint32_t>(errno));
367 std::string dbPath;
368 SqliteGlobalConfig::GetDbPath(config_, dbPath);
369 std::vector<std::pair<std::string, std::string>> logInfo;
370 logInfo.emplace_back("S_L", std::to_string(static_cast<uint32_t>(config_.GetSecurityLevel())));
371 logInfo.emplace_back("P_A", std::to_string(static_cast<uint32_t>(config_.GetArea())));
372 logInfo.emplace_back("E_S", std::to_string(static_cast<uint32_t>(config_.IsEncrypt())));
373 logInfo.emplace_back("I_C", std::to_string(static_cast<uint32_t>(config_.GetIntegrityCheck())));
374 logInfo.emplace_back("ENO", errNoStr);
375 logInfo.emplace_back("PATH", dbPath);
376 std::stringstream oss;
377 for (size_t i = 0; i < logInfo.size(); i++) {
378 oss << logInfo[i].first << ":" << logInfo[i].second;
379 if (i != logInfo.size() - 1) {
380 oss << "," << std::endl;
381 }
382 }
383 return oss.str();
384 }
385
BuildLogInfo() const386 std::string RdbFaultDbFileEvent::BuildLogInfo() const
387 {
388 std::string appendInfo = GetLogInfo();
389 if (GetErrCode() == E_SQLITE_NOT_DB) {
390 std::string dbPath;
391 SqliteGlobalConfig::GetDbPath(config_, dbPath);
392 appendInfo += SqliteUtils::ReadFileHeader(dbPath);
393 }
394 if (printDbInfo_) {
395 RdbCorruptedEvent eventInfo = RdbFaultHiViewReporter::Create(config_, GetErrCode());
396 appendInfo += ("\n" + BuildConfigLog() + "\n" + SqliteUtils::FormatDfxInfo(eventInfo.dfxInfo) + "\n" +
397 SqliteUtils::FormatDebugInfo(eventInfo.debugInfos, ""));
398 }
399 return appendInfo;
400 }
401 } // namespace OHOS::NativeRdb