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