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