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 <charconv>
16 #include <sys/stat.h>
17 #include <set>
18
19 #include "app_caller_event.h"
20 #include "app_event_task_storage.h"
21 #include "file_util.h"
22 #include "hiview_logger.h"
23 #include "time_util.h"
24 #include "trace_common.h"
25 #include "trace_flow_controller.h"
26 #include "trace_db_callback.h"
27
28 using namespace OHOS::HiviewDFX;
29
30 namespace OHOS {
31 namespace HiviewDFX {
32 namespace {
33 DEFINE_LOG_TAG("TraceFlowController");
34 constexpr int32_t DB_VERSION = 4;
35 const std::string UNIFIED_SHARE_PATH = "/data/log/hiview/unified_collection/trace/share/";
36 const std::string UNIFIED_SPECIAL_PATH = "/data/log/hiview/unified_collection/trace/special/";
37 const std::string DB_NAME = "trace_flow_control.db";
38 constexpr int32_t HITRACE_CACHE_DURATION_LIMIT_DAILY_TOTAL = 10 * 60; // 10 minutes
39 const std::set<std::string> DB_CALLER {
40 CallerName::XPERF, CallerName::XPOWER, CallerName::RELIABILITY, CallerName::HIVIEW
41 };
42 }
43
InitTraceDb(const std::string & dbPath)44 void TraceFlowController::InitTraceDb(const std::string& dbPath)
45 {
46 NativeRdb::RdbStoreConfig config(dbPath + DB_NAME);
47 config.SetSecurityLevel(NativeRdb::SecurityLevel::S1);
48 TraceDbStoreCallback callback;
49 auto ret = NativeRdb::E_OK;
50 dbStore_ = NativeRdb::RdbHelper::GetRdbStore(config, DB_VERSION, callback, ret);
51 if (ret != NativeRdb::E_OK) {
52 HIVIEW_LOGE("failed to init db store, db store path=%{public}s", dbPath.c_str());
53 dbStore_ = nullptr;
54 return;
55 }
56 }
57
InitTraceStorage(const std::string & caller)58 void TraceFlowController::InitTraceStorage(const std::string& caller)
59 {
60 if (dbStore_ == nullptr) {
61 HIVIEW_LOGE("dbStore fail init");
62 return;
63 }
64 if (DB_CALLER.find(caller) != DB_CALLER.end()) {
65 HIVIEW_LOGD("is db caller, init TraceStorage");
66 traceStorage_ = std::make_shared<TraceStorage>(dbStore_, caller);
67 }
68 if (caller == ClientName::APP) {
69 appTaskStore_ = std::make_shared<AppEventTaskStorage>(dbStore_);
70 }
71 if (caller == BusinessName::BEHAVIOR) {
72 behaviorTaskStore_ = std::make_shared<TraceBehaviorStorage>(dbStore_);
73 }
74 if (caller == BusinessName::TELEMETRY) {
75 teleMetryStorage_ = std::make_shared<TeleMetryStorage>(dbStore_);
76 }
77 }
78
TraceFlowController(const std::string & caller,const std::string & dbPath)79 TraceFlowController::TraceFlowController(const std::string& caller, const std::string& dbPath)
80 {
81 InitTraceDb(dbPath);
82 InitTraceStorage(caller);
83 }
84
NeedDump()85 bool TraceFlowController::NeedDump()
86 {
87 if (traceStorage_ == nullptr) {
88 return false;
89 }
90 return traceStorage_->NeedDump();
91 }
92
NeedUpload(int64_t traceSize)93 bool TraceFlowController::NeedUpload(int64_t traceSize)
94 {
95 if (traceStorage_ == nullptr) {
96 return false;
97 }
98 return traceStorage_->NeedUpload(traceSize);
99 }
100
StoreDb()101 void TraceFlowController::StoreDb()
102 {
103 if (traceStorage_ == nullptr) {
104 return;
105 }
106 traceStorage_->StoreDb();
107 }
108
HasCallOnceToday(int32_t uid,uint64_t happenTime)109 bool TraceFlowController::HasCallOnceToday(int32_t uid, uint64_t happenTime)
110 {
111 if (appTaskStore_ == nullptr) {
112 return true;
113 }
114 uint64_t happenTimeInSecond = happenTime / TimeUtil::SEC_TO_MILLISEC;
115 std::string date = TimeUtil::TimestampFormatToDate(happenTimeInSecond, "%Y%m%d");
116
117 AppEventTask appEventTask;
118 appEventTask.id_ = 0;
119 int32_t dateNum = 0;
120 auto result = std::from_chars(date.c_str(), date.c_str() + date.size(), dateNum);
121 if (result.ec != std::errc()) {
122 HIVIEW_LOGW("convert error, dateStr: %{public}s", date.c_str());
123 return true;
124 }
125 HIVIEW_LOGD("Query appEventTask where uid:%{public}d, dateNum:%{public}d", uid, dateNum);
126 appTaskStore_->GetAppEventTask(uid, dateNum, appEventTask);
127 return appEventTask.id_ > 0;
128 }
129
RecordCaller(std::shared_ptr<AppCallerEvent> appEvent)130 bool TraceFlowController::RecordCaller(std::shared_ptr<AppCallerEvent> appEvent)
131 {
132 if (appTaskStore_ == nullptr) {
133 return false;
134 }
135 uint64_t happenTimeInSecond = appEvent->happenTime_ / TimeUtil::SEC_TO_MILLISEC;
136 std::string date = TimeUtil::TimestampFormatToDate(happenTimeInSecond, "%Y%m%d");
137 int64_t dateNum = 0;
138 auto result = std::from_chars(date.c_str(), date.c_str() + date.size(), dateNum);
139 if (result.ec != std::errc()) {
140 HIVIEW_LOGW("convert error, dateStr: %{public}s", date.c_str());
141 return false;
142 }
143 AppEventTask appEventTask;
144 appEventTask.taskDate_ = dateNum;
145 appEventTask.taskType_ = APP_EVENT_TASK_TYPE_JANK_EVENT;
146 appEventTask.uid_ = appEvent->uid_;
147 appEventTask.pid_ = appEvent->pid_;
148 appEventTask.bundleName_ = appEvent->bundleName_;
149 appEventTask.bundleVersion_ = appEvent->bundleVersion_;
150 appEventTask.startTime_ = appEvent->taskBeginTime_;
151 appEventTask.finishTime_ = appEvent->taskEndTime_;
152 appEventTask.resourePath_ = appEvent->externalLog_;
153 appEventTask.resourceSize_ = static_cast<int32_t>(FileUtil::GetFileSize(appEventTask.resourePath_));
154 appEventTask.state_ = APP_EVENT_TASK_STATE_FINISH;
155 return appTaskStore_->InsertAppEventTask(appEventTask);
156 }
157
CleanOldAppTrace(int32_t dateNum)158 void TraceFlowController::CleanOldAppTrace(int32_t dateNum)
159 {
160 if (appTaskStore_ == nullptr) {
161 return;
162 }
163 appTaskStore_->RemoveAppEventTask(dateNum);
164 }
165
UseCacheTimeQuota(int32_t interval)166 CacheFlow TraceFlowController::UseCacheTimeQuota(int32_t interval)
167 {
168 if (behaviorTaskStore_ == nullptr) {
169 return CacheFlow::EXIT;
170 }
171 BehaviorRecord record;
172 record.behaviorId = CACHE_LOW_MEM;
173 record.dateNum = TimeUtil::TimestampFormatToDate(TimeUtil::GetSeconds(), "%Y%m%d");
174 if (!behaviorTaskStore_->GetRecord(record) && !behaviorTaskStore_->InsertRecord(record)) {
175 HIVIEW_LOGE("failed to get and insert record, close task");
176 return CacheFlow::EXIT;
177 }
178 HIVIEW_LOGD("get used quota:%{public}d", record.usedQuota);
179 if (record.usedQuota >= HITRACE_CACHE_DURATION_LIMIT_DAILY_TOTAL) {
180 HIVIEW_LOGW("usedQuota exceeds daily limit. usedQuota:%{public}d", record.usedQuota);
181 return CacheFlow::OVER_FLOW;
182 }
183 record.usedQuota += interval;
184 behaviorTaskStore_->UpdateRecord(record);
185 return CacheFlow::SUCCESS;
186 }
187
InitTelemetryData(const std::string & telemetryId,int64_t & beginTime,const std::map<std::string,int64_t> & flowControlQuotas)188 TelemetryRet TraceFlowController::InitTelemetryData(const std::string &telemetryId, int64_t &beginTime,
189 const std::map<std::string, int64_t>& flowControlQuotas)
190 {
191 if (teleMetryStorage_ == nullptr) {
192 HIVIEW_LOGE("failed to init teleMetryStorage");
193 return TelemetryRet::EXIT;
194 }
195 return teleMetryStorage_->InitTelemetryControl(telemetryId, beginTime, flowControlQuotas);
196 }
197
NeedTelemetryDump(const std::string & module,int64_t traceSize)198 TelemetryRet TraceFlowController::NeedTelemetryDump(const std::string &module, int64_t traceSize)
199 {
200 if (teleMetryStorage_ == nullptr) {
201 HIVIEW_LOGE("failed to init teleMetryStorage, close task");
202 return TelemetryRet::EXIT;
203 }
204 return teleMetryStorage_->NeedTelemetryDump(module, traceSize);
205 }
206
ClearTelemetryData()207 void TraceFlowController::ClearTelemetryData()
208 {
209 if (teleMetryStorage_ == nullptr) {
210 HIVIEW_LOGE("failed to init teleMetryStorage, return");
211 return;
212 }
213 return teleMetryStorage_->ClearTelemetryData();
214 }
215 } // HiViewDFX
216 } // OHOS
217