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