1 /*
2 * Copyright (C) 2023-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 <algorithm>
16 #include <cinttypes>
17 #include <cmath>
18
19 #include "file_util.h"
20 #include "hisysevent.h"
21 #include "hiview_logger.h"
22 #include "process_status.h"
23 #include "rdb_helper.h"
24 #include "sql_util.h"
25 #include "string_util.h"
26 #include "trace_storage.h"
27
28 using namespace OHOS::HiviewDFX::UCollectUtil;
29
30 namespace OHOS {
31 namespace HiviewDFX {
32 namespace {
33 DEFINE_LOG_TAG("UCollectUtil-TraceCollector");
34 constexpr int32_t DB_VERSION = 2;
35 const std::string TABLE_NAME = "trace_flow_control";
36 const std::string COLUMN_SYSTEM_TIME = "system_time";
37 const std::string COLUMN_CALLER_NAME = "caller_name";
38 const std::string COLUMN_USED_SIZE = "used_size";
39
GetBucket(const TraceFlowRecord & traceFlowRecord)40 NativeRdb::ValuesBucket GetBucket(const TraceFlowRecord& traceFlowRecord)
41 {
42 NativeRdb::ValuesBucket bucket;
43 bucket.PutString(COLUMN_SYSTEM_TIME, traceFlowRecord.systemTime);
44 bucket.PutString(COLUMN_CALLER_NAME, traceFlowRecord.callerName);
45 bucket.PutLong(COLUMN_USED_SIZE, traceFlowRecord.usedSize);
46 return bucket;
47 }
48 }
49
50 class TraceDbStoreCallback : public NativeRdb::RdbOpenCallback {
51 public:
52 int OnCreate(NativeRdb::RdbStore &rdbStore) override;
53 int OnUpgrade(NativeRdb::RdbStore &rdbStore, int oldVersion, int newVersion) override;
54 };
55
CreateTraceFlowControlTable(NativeRdb::RdbStore & rdbStore)56 int32_t CreateTraceFlowControlTable(NativeRdb::RdbStore& rdbStore)
57 {
58 /**
59 * table: trace_flow_control
60 *
61 * describe: store data that has been used
62 * |-----|-------------|-------------|-----------|
63 * | id | system_time | caller_name | used_size |
64 * |-----|-------------|-------------|-----------|
65 * | INT | VARCHAR | VARCHAR | INT64 |
66 * |-----|-------------|-------------|-----------|
67 */
68 const std::vector<std::pair<std::string, std::string>> fields = {
69 {COLUMN_SYSTEM_TIME, SqlUtil::COLUMN_TYPE_STR},
70 {COLUMN_CALLER_NAME, SqlUtil::COLUMN_TYPE_STR},
71 {COLUMN_USED_SIZE, SqlUtil::COLUMN_TYPE_INT},
72 };
73 std::string sql = SqlUtil::GenerateCreateSql(TABLE_NAME, fields);
74 if (rdbStore.ExecuteSql(sql) != NativeRdb::E_OK) {
75 HIVIEW_LOGE("failed to create table, sql=%{public}s", sql.c_str());
76 return -1;
77 }
78 return 0;
79 }
80
OnCreate(NativeRdb::RdbStore & rdbStore)81 int TraceDbStoreCallback::OnCreate(NativeRdb::RdbStore& rdbStore)
82 {
83 HIVIEW_LOGD("create dbStore");
84 if (auto ret = CreateTraceFlowControlTable(rdbStore); ret != NativeRdb::E_OK) {
85 HIVIEW_LOGE("failed to create table trace_flow_control");
86 return ret;
87 }
88 return NativeRdb::E_OK;
89 }
90
OnUpgrade(NativeRdb::RdbStore & rdbStore,int oldVersion,int newVersion)91 int TraceDbStoreCallback::OnUpgrade(NativeRdb::RdbStore& rdbStore, int oldVersion, int newVersion)
92 {
93 HIVIEW_LOGD("oldVersion=%{public}d, newVersion=%{public}d", oldVersion, newVersion);
94 std::string sql = SqlUtil::GenerateDropSql(TABLE_NAME);
95 if (int ret = rdbStore.ExecuteSql(sql); ret != NativeRdb::E_OK) {
96 HIVIEW_LOGE("failed to drop table %{public}s, ret=%{public}d", TABLE_NAME.c_str(), ret);
97 return -1;
98 }
99 return OnCreate(rdbStore);
100 }
101
TraceStorage(const std::string & dbStorePath)102 TraceStorage::TraceStorage(const std::string& dbStorePath) : dbStorePath_(dbStorePath)
103 {
104 InitDbStore();
105 }
106
InitDbStore()107 void TraceStorage::InitDbStore()
108 {
109 dbStorePath_.append(TABLE_NAME).append(".db"); // trace_flow_control.db
110 NativeRdb::RdbStoreConfig config(dbStorePath_);
111 config.SetSecurityLevel(NativeRdb::SecurityLevel::S1);
112 TraceDbStoreCallback callback;
113 auto ret = NativeRdb::E_OK;
114 dbStore_ = NativeRdb::RdbHelper::GetRdbStore(config, DB_VERSION, callback, ret);
115 if (ret != NativeRdb::E_OK) {
116 HIVIEW_LOGE("failed to init db store, db store path=%{public}s", dbStorePath_.c_str());
117 dbStore_ = nullptr;
118 return;
119 }
120
121 appTaskStore_ = std::make_shared<AppEventTaskStorage>(dbStore_);
122 appTaskStore_->InitAppTask();
123 }
124
Store(const TraceFlowRecord & traceFlowRecord)125 void TraceStorage::Store(const TraceFlowRecord& traceFlowRecord)
126 {
127 if (dbStore_ == nullptr) {
128 HIVIEW_LOGE("db store is null, path=%{public}s", dbStorePath_.c_str());
129 return;
130 }
131 TraceFlowRecord tmpTraceFlowRecord = {.callerName = traceFlowRecord.callerName};
132 Query(tmpTraceFlowRecord);
133 if (!tmpTraceFlowRecord.systemTime.empty()) { // time not empty means record exist
134 UpdateTable(traceFlowRecord);
135 } else {
136 InsertTable(traceFlowRecord);
137 }
138 }
139
UpdateTable(const TraceFlowRecord & traceFlowRecord)140 void TraceStorage::UpdateTable(const TraceFlowRecord& traceFlowRecord)
141 {
142 NativeRdb::ValuesBucket bucket = GetBucket(traceFlowRecord);
143 NativeRdb::AbsRdbPredicates predicates(TABLE_NAME);
144 predicates.EqualTo(COLUMN_CALLER_NAME, traceFlowRecord.callerName);
145 int changeRows = 0;
146 if (dbStore_->Update(changeRows, bucket, predicates) != NativeRdb::E_OK) {
147 HIVIEW_LOGW("failed to update table");
148 }
149 }
150
InsertTable(const TraceFlowRecord & traceFlowRecord)151 void TraceStorage::InsertTable(const TraceFlowRecord& traceFlowRecord)
152 {
153 NativeRdb::ValuesBucket bucket = GetBucket(traceFlowRecord);
154 int64_t seq = 0;
155 if (dbStore_->Insert(seq, TABLE_NAME, bucket) != NativeRdb::E_OK) {
156 HIVIEW_LOGW("failed to insert table");
157 }
158 }
159
Query(TraceFlowRecord & traceFlowRecord)160 void TraceStorage::Query(TraceFlowRecord& traceFlowRecord)
161 {
162 if (dbStore_ == nullptr) {
163 HIVIEW_LOGE("db store is null, path=%{public}s", dbStorePath_.c_str());
164 return;
165 }
166 QueryTable(traceFlowRecord);
167 }
168
QueryTable(TraceFlowRecord & traceFlowRecord)169 void TraceStorage::QueryTable(TraceFlowRecord& traceFlowRecord)
170 {
171 NativeRdb::AbsRdbPredicates predicates(TABLE_NAME);
172 predicates.EqualTo(COLUMN_CALLER_NAME, traceFlowRecord.callerName);
173 auto resultSet = dbStore_->Query(predicates, {COLUMN_SYSTEM_TIME, COLUMN_USED_SIZE});
174 if (resultSet == nullptr) {
175 HIVIEW_LOGE("failed to query from table %{public}s, db is null", TABLE_NAME.c_str());
176 return;
177 }
178
179 if (resultSet->GoToNextRow() == NativeRdb::E_OK) {
180 resultSet->GetString(0, traceFlowRecord.systemTime); // 0 means system_time field
181 resultSet->GetLong(1, traceFlowRecord.usedSize); // 1 means used_size field
182 }
183 resultSet->Close();
184 }
185
QueryAppEventTask(int32_t uid,int32_t date,AppEventTask & appEventTask)186 bool TraceStorage::QueryAppEventTask(int32_t uid, int32_t date, AppEventTask& appEventTask)
187 {
188 if (appTaskStore_ == nullptr) {
189 return false;
190 }
191 appTaskStore_->GetAppEventTask(uid, date, appEventTask);
192 return true;
193 }
194
StoreAppEventTask(AppEventTask & appEventTask)195 bool TraceStorage::StoreAppEventTask(AppEventTask& appEventTask)
196 {
197 if (appTaskStore_ == nullptr) {
198 return false;
199 }
200
201 return appTaskStore_->InsertAppEventTask(appEventTask);
202 }
203
RemoveOldAppEventTask(int32_t eventDate)204 void TraceStorage::RemoveOldAppEventTask(int32_t eventDate)
205 {
206 if (appTaskStore_ == nullptr) {
207 return;
208 }
209 appTaskStore_->RemoveAppEventTask(eventDate);
210 }
211 } // namespace HiviewDFX
212 } // namespace OHOS
213