• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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