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 #include "daily_db_helper.h"
16 
17 #include "file_util.h"
18 #include "hisysevent.h"
19 #include "hiview_db_util.h"
20 #include "hiview_logger.h"
21 #include "rdb_predicates.h"
22 #include "sql_util.h"
23 #include "time_util.h"
24 
25 namespace OHOS {
26 namespace HiviewDFX {
27 DEFINE_LOG_TAG("DailyController");
28 namespace {
29 const std::string EVENTS_TABLE = "events_count";
30 const std::string EVENTS_COLUMIN_DOMAIN = "domain";
31 const std::string EVENTS_COLUMIN_NAME = "name";
32 const std::string EVENTS_COLUMIN_COUNT = "count";
33 const std::string EVENTS_COLUMIN_EXCEED_TIME = "exceed_time";
34 
CreateEventsTable(NativeRdb::RdbStore & dbStore)35 int32_t CreateEventsTable(NativeRdb::RdbStore& dbStore)
36 {
37     /**
38      * table: events_count
39      *
40      * |-----|-----------|---------|-------|-------------|
41      * |  id |  domain   |  name   | count | exceed_time |
42      * |-----|-----------|---------|-------|-------------|
43      * | INT |  VARCHAR  | VARCHAR |  INT  |     INT     |
44      * |-----|-----------|---------|-------|-------------|
45      */
46     const std::vector<std::pair<std::string, std::string>> fields = {
47         {EVENTS_COLUMIN_DOMAIN, SqlUtil::COLUMN_TYPE_STR},
48         {EVENTS_COLUMIN_NAME, SqlUtil::COLUMN_TYPE_STR},
49         {EVENTS_COLUMIN_COUNT, SqlUtil::COLUMN_TYPE_INT},
50         {EVENTS_COLUMIN_EXCEED_TIME, SqlUtil::COLUMN_TYPE_INT},
51     };
52     std::string sql = SqlUtil::GenerateCreateSql(EVENTS_TABLE, fields);
53     if (auto ret = dbStore.ExecuteSql(sql); ret != NativeRdb::E_OK) {
54         HIVIEW_LOGW("failed to create table=%{public}s, ret=%{public}d", EVENTS_TABLE.c_str(), ret);
55         return ret;
56     }
57     return NativeRdb::E_OK;
58 }
59 }
OnCreate(NativeRdb::RdbStore & rdbStore)60 int32_t DailyDbHelper::DailyDbOpenCallback::OnCreate(NativeRdb::RdbStore& rdbStore)
61 {
62     HIVIEW_LOGI("create daily database");
63     return CreateEventsTable(rdbStore);
64 }
65 
OnUpgrade(NativeRdb::RdbStore & rdbStore,int32_t oldVersion,int32_t newVersion)66 int32_t DailyDbHelper::DailyDbOpenCallback::OnUpgrade(NativeRdb::RdbStore& rdbStore,
67     int32_t oldVersion, int32_t newVersion)
68 {
69     HIVIEW_LOGI("oldVersion=%{public}d, newVersion=%{public}d", oldVersion, newVersion);
70     return NativeRdb::E_OK;
71 }
72 
DailyDbHelper(const std::string & workPath)73 DailyDbHelper::DailyDbHelper(const std::string& workPath) : workPath_(workPath), dbStore_(nullptr)
74 {
75     InitDb();
76 }
77 
InitDb()78 void DailyDbHelper::InitDb()
79 {
80     if (!InitDbPath()) {
81         return;
82     }
83     InitDbStore();
84 }
85 
InitDbPath()86 bool DailyDbHelper::InitDbPath()
87 {
88     if (workPath_.empty()) {
89         HIVIEW_LOGW("db path is null");
90         return false;
91     }
92 
93     const std::string thresholdDir = "sys_event_threshold/";
94     std::string tempDbPath = FileUtil::IncludeTrailingPathDelimiter(workPath_).append(thresholdDir);
95     if (!FileUtil::IsDirectory(tempDbPath) && !FileUtil::ForceCreateDirectory(tempDbPath)) {
96         HIVIEW_LOGE("failed to create dir=%{public}s", tempDbPath.c_str());
97         return false;
98     }
99     tempDbPath.append(HiviewDbUtil::CreateFileNameByDate("events_"));
100     dbPath_ = tempDbPath;
101     HIVIEW_LOGI("succ to init db store path=%{public}s", dbPath_.c_str());
102     return true;
103 }
104 
InitDbStore()105 void DailyDbHelper::InitDbStore()
106 {
107     NativeRdb::RdbStoreConfig config(dbPath_);
108     config.SetSecurityLevel(NativeRdb::SecurityLevel::S1);
109     constexpr int32_t dbVersion = 1;
110     DailyDbOpenCallback callback;
111     auto ret = NativeRdb::E_OK;
112     dbStore_ = NativeRdb::RdbHelper::GetRdbStore(config, dbVersion, callback, ret);
113     if (ret != NativeRdb::E_OK || dbStore_ == nullptr) {
114         HIVIEW_LOGW("failed to create db, ret=%{public}d", ret);
115     }
116 }
117 
InsertEventInfo(const EventInfo & info)118 int32_t DailyDbHelper::InsertEventInfo(const EventInfo& info)
119 {
120     if (dbStore_ == nullptr) {
121         return -1;
122     }
123 
124     NativeRdb::ValuesBucket bucket;
125     bucket.PutString(EVENTS_COLUMIN_DOMAIN, info.domain);
126     bucket.PutString(EVENTS_COLUMIN_NAME, info.name);
127     bucket.PutInt(EVENTS_COLUMIN_COUNT, info.count);
128     bucket.PutLong(EVENTS_COLUMIN_EXCEED_TIME, info.exceedTime);
129     int64_t seq = 0;
130     if (auto ret = dbStore_->Insert(seq, EVENTS_TABLE, bucket); ret != NativeRdb::E_OK) {
131         HIVIEW_LOGW("failed to insert event, domain=%{public}s, name=%{public}s",
132             info.domain.c_str(), info.name.c_str());
133         return -1;
134     }
135     HIVIEW_LOGD("succ to insert event, domain=%{public}s, name=%{public}s",
136         info.domain.c_str(), info.name.c_str());
137     return 0;
138 }
139 
UpdateEventInfo(const EventInfo & info)140 int32_t DailyDbHelper::UpdateEventInfo(const EventInfo& info)
141 {
142     if (dbStore_ == nullptr) {
143         return -1;
144     }
145 
146     NativeRdb::ValuesBucket bucket;
147     bucket.PutInt(EVENTS_COLUMIN_COUNT, info.count);
148     if (info.exceedTime != 0) {
149         bucket.PutLong(EVENTS_COLUMIN_EXCEED_TIME, info.exceedTime);
150     }
151     NativeRdb::AbsRdbPredicates predicates(EVENTS_TABLE);
152     predicates.EqualTo(EVENTS_COLUMIN_DOMAIN, info.domain);
153     predicates.EqualTo(EVENTS_COLUMIN_NAME, info.name);
154     int32_t changeRows = 0;
155     if (dbStore_->Update(changeRows, bucket, predicates) != NativeRdb::E_OK || changeRows == 0) {
156         HIVIEW_LOGW("failed to update event, domain=%{public}s, name=%{public}s, count=%{public}d",
157             info.domain.c_str(), info.name.c_str(), info.count);
158         return -1;
159     }
160     return 0;
161 }
162 
QueryEventInfo(EventInfo & info)163 int32_t DailyDbHelper::QueryEventInfo(EventInfo& info)
164 {
165     if (dbStore_ == nullptr) {
166         return -1;
167     }
168 
169     NativeRdb::AbsRdbPredicates predicates(EVENTS_TABLE);
170     predicates.EqualTo(EVENTS_COLUMIN_DOMAIN, info.domain);
171     predicates.EqualTo(EVENTS_COLUMIN_NAME, info.name);
172     auto resultSet = dbStore_->Query(predicates, {EVENTS_COLUMIN_COUNT});
173     if (resultSet == nullptr) {
174         HIVIEW_LOGW("failed to query table, domain=%{public}s, name=%{public}s",
175             info.domain.c_str(), info.name.c_str());
176         return -1;
177     }
178 
179     // means that the event record is empty
180     if (resultSet->GoToNextRow() != NativeRdb::E_OK) {
181         resultSet->Close();
182         return 0;
183     }
184 
185     if (resultSet->GetInt(0, info.count) != NativeRdb::E_OK || info.count < 0) {
186         HIVIEW_LOGW("failed to get count value, domain=%{public}s, name=%{public}s",
187             info.domain.c_str(), info.name.c_str());
188         resultSet->Close();
189         return -1;
190     }
191     resultSet->Close();
192     HIVIEW_LOGD("succ to query event, domain=%{public}s, name=%{public}s, count=%{public}d",
193         info.domain.c_str(), info.name.c_str(), info.count);
194     return 0;
195 }
196 
NeedReport(int64_t nowTime)197 bool DailyDbHelper::NeedReport(int64_t nowTime)
198 {
199     std::string dateOfDbFile = HiviewDbUtil::GetDateFromDbFile(dbPath_);
200     std::string curDate = TimeUtil::TimestampFormatToDate(nowTime, "%Y%m%d");
201     return dateOfDbFile != curDate;
202 }
203 
Report()204 void DailyDbHelper::Report()
205 {
206     HIVIEW_LOGI("start to report event infos");
207     PrepareOldDbFilesBeforeReport();
208     ReportDailyEvent();
209     PrepareNewDbFilesAfterReport();
210 }
211 
PrepareOldDbFilesBeforeReport()212 void DailyDbHelper::PrepareOldDbFilesBeforeReport()
213 {
214     // 1. Close the current db file
215     CloseDbStore();
216 
217     // 2. Init upload directory
218     if (!HiviewDbUtil::InitDbUploadPath(dbPath_, uploadPath_)) {
219         return;
220     }
221 
222     // 3. Move the db file to the upload directory
223     HiviewDbUtil::MoveDbFilesToUploadDir(dbPath_, uploadPath_);
224 
225     // 4. Aging upload db files, only the latest 7 db files are retained
226     HiviewDbUtil::TryToAgeUploadDbFiles(uploadPath_);
227 }
228 
CloseDbStore()229 void DailyDbHelper::CloseDbStore()
230 {
231     dbStore_ = nullptr;
232 }
233 
ReportDailyEvent()234 void DailyDbHelper::ReportDailyEvent()
235 {
236     int32_t ret = HiSysEventWrite(HiSysEvent::Domain::HIVIEWDFX, "EVENTS_DAILY",
237         HiSysEvent::EventType::FAULT, "DATE", HiviewDbUtil::GetDateFromDbFile(dbPath_));
238     if (ret != 0) {
239         HIVIEW_LOGW("failed to report event, ret=%{public}d", ret);
240     }
241 }
242 
PrepareNewDbFilesAfterReport()243 void DailyDbHelper::PrepareNewDbFilesAfterReport()
244 {
245     InitDb();
246 }
247 } // namespace HiviewDFX
248 } // namespace OHOS
249