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 <chrono>
17 #include <cinttypes>
18 #include <ctime>
19 #include <sys/stat.h>
20 #include <unordered_map>
21 #include <vector>
22
23 #include "app_caller_event.h"
24 #include "app_event_task_storage.h"
25 #include "file_util.h"
26 #include "hiview_logger.h"
27 #include "parameter_ex.h"
28 #include "string_util.h"
29 #include "time_util.h"
30 #include "trace_flow_controller.h"
31 #include "trace_utils.h"
32
33 using namespace OHOS::HiviewDFX;
34
35 namespace OHOS {
36 namespace HiviewDFX {
37 namespace {
38 DEFINE_LOG_TAG("UCollectUtil-TraceCollector");
39 const std::string UNIFIED_SHARE_PATH = "/data/log/hiview/unified_collection/trace/share/";
40 const std::string UNIFIED_SPECIAL_PATH = "/data/log/hiview/unified_collection/trace/special/";
41 const std::string DB_PATH = "/data/log/hiview/unified_collection/trace/";
42 const int64_t XPERF_SIZE = 1750 * 1024 * 1024;
43 const int64_t XPOWER_SIZE = 700 * 1024 * 1024;
44 const int64_t RELIABILITY_SIZE = 750 * 1024 * 1024;
45 const int64_t HIVIEW_SIZE = 350 * 1024 * 1024;
46 const int64_t FOUNDATION_SIZE = 150 * 1024 * 1024;
47 const float TEN_PERCENT_LIMIT = 0.1;
48
GetActualReliabilitySize()49 int64_t GetActualReliabilitySize()
50 {
51 return Parameter::IsLaboratoryMode() ? RELIABILITY_SIZE * 5 : RELIABILITY_SIZE; // 5 : laboratory largen 5 times
52 }
53
54 const std::unordered_map<UCollect::TraceCaller, std::pair<std::string, int64_t>> TRACE_QUOTA = {
55 {UCollect::TraceCaller::XPERF, {"xperf", XPERF_SIZE}},
56 {UCollect::TraceCaller::XPOWER, {"xpower", XPOWER_SIZE}},
57 {UCollect::TraceCaller::RELIABILITY, {"reliability", GetActualReliabilitySize()}},
58 {UCollect::TraceCaller::HIVIEW, {"hiview", HIVIEW_SIZE}},
59 {UCollect::TraceCaller::FOUNDATION, {"foundation", FOUNDATION_SIZE}},
60 };
61 }
62
CreateTracePath(const std::string & filePath)63 void CreateTracePath(const std::string &filePath)
64 {
65 if (FileUtil::FileExists(filePath)) {
66 return;
67 }
68 if (!CreateMultiDirectory(filePath)) {
69 HIVIEW_LOGE("failed to create multidirectory %{public}s.", filePath.c_str());
70 return;
71 }
72 }
73
InitTraceDb()74 void TraceFlowController::InitTraceDb()
75 {
76 traceFlowRecord_ = QueryDb();
77 HIVIEW_LOGI("systemTime:%{public}s, callerName:%{public}s, usedSize:%{public}" PRId64,
78 traceFlowRecord_.systemTime.c_str(), traceFlowRecord_.callerName.c_str(),
79 traceFlowRecord_.usedSize);
80 }
81
InitTraceStorage()82 void TraceFlowController::InitTraceStorage()
83 {
84 CreateTracePath(UNIFIED_SHARE_PATH);
85 CreateTracePath(UNIFIED_SPECIAL_PATH);
86
87 traceStorage_ = std::make_shared<TraceStorage>(DB_PATH);
88 }
89
TraceFlowController(UCollect::TraceCaller caller)90 TraceFlowController::TraceFlowController(UCollect::TraceCaller caller) : caller_(caller)
91 {
92 InitTraceStorage();
93 InitTraceDb();
94 }
95
NeedDump()96 bool TraceFlowController::NeedDump()
97 {
98 std::string nowDays = GetDate();
99 HIVIEW_LOGI("start to dump, nowDays = %{public}s, systemTime = %{public}s.",
100 nowDays.c_str(), traceFlowRecord_.systemTime.c_str());
101 if (nowDays != traceFlowRecord_.systemTime) {
102 // date changes
103 traceFlowRecord_.systemTime = nowDays;
104 traceFlowRecord_.usedSize = 0;
105 return true;
106 }
107 return TRACE_QUOTA.find(caller_) != TRACE_QUOTA.end() ?
108 traceFlowRecord_.usedSize < TRACE_QUOTA.at(caller_).second : true;
109 }
110
NeedUpload(TraceRetInfo ret)111 bool TraceFlowController::NeedUpload(TraceRetInfo ret)
112 {
113 int64_t traceSize = GetTraceSize(ret);
114 HIVIEW_LOGI("start to upload , traceSize = %{public}" PRId64 ".", traceSize);
115 if (TRACE_QUOTA.find(caller_) == TRACE_QUOTA.end()) {
116 return true;
117 }
118 if (IsLowerLimit(traceFlowRecord_.usedSize, traceSize, TRACE_QUOTA.at(caller_).second)) {
119 traceFlowRecord_.usedSize += traceSize;
120 return true;
121 }
122 return false;
123 }
124
IsLowerLimit(int64_t nowSize,int64_t traceSize,int64_t limitSize)125 bool TraceFlowController::IsLowerLimit(int64_t nowSize, int64_t traceSize, int64_t limitSize)
126 {
127 if (limitSize == 0) {
128 HIVIEW_LOGE("error, limit size is zero.");
129 return false;
130 }
131
132 int64_t totalSize = nowSize + traceSize;
133 if (totalSize < limitSize) {
134 return true;
135 }
136
137 float limit = static_cast<float>(totalSize - limitSize) / limitSize;
138 if (limit > TEN_PERCENT_LIMIT) {
139 return false;
140 }
141 return true;
142 }
143
StoreDb()144 void TraceFlowController::StoreDb()
145 {
146 if (TRACE_QUOTA.find(caller_) == TRACE_QUOTA.end()) {
147 HIVIEW_LOGI("caller %{public}d not need store", caller_);
148 return;
149 }
150 HIVIEW_LOGI("systemTime:%{public}s, callerName:%{public}s, usedSize:%{public}" PRId64,
151 traceFlowRecord_.systemTime.c_str(), traceFlowRecord_.callerName.c_str(),
152 traceFlowRecord_.usedSize);
153 traceStorage_->Store(traceFlowRecord_);
154 }
155
GetTraceSize(TraceRetInfo ret)156 int64_t TraceFlowController::GetTraceSize(TraceRetInfo ret)
157 {
158 struct stat fileInfo;
159 int64_t traceSize = 0;
160 for (const auto &tracePath : ret.outputFiles) {
161 int ret = stat(tracePath.c_str(), &fileInfo);
162 if (ret != 0) {
163 HIVIEW_LOGE("%{public}s is not exists, ret = %{public}d.", tracePath.c_str(), ret);
164 continue;
165 }
166 traceSize += fileInfo.st_size;
167 }
168 return traceSize;
169 }
170
GetDate()171 std::string TraceFlowController::GetDate()
172 {
173 std::string dateStr = TimeUtil::TimestampFormatToDate(std::time(nullptr), "%Y-%m-%d");
174 return dateStr;
175 }
176
QueryDb()177 TraceFlowRecord TraceFlowController::QueryDb()
178 {
179 struct TraceFlowRecord tmpTraceFlowRecord;
180 if (TRACE_QUOTA.find(caller_) == TRACE_QUOTA.end()) {
181 return tmpTraceFlowRecord;
182 }
183 tmpTraceFlowRecord.callerName = TRACE_QUOTA.at(caller_).first;
184 traceStorage_->Query(tmpTraceFlowRecord);
185 return tmpTraceFlowRecord;
186 }
187
HasCallOnceToday(int32_t uid,uint64_t happenTime)188 bool TraceFlowController::HasCallOnceToday(int32_t uid, uint64_t happenTime)
189 {
190 uint64_t happenTimeInSecond = happenTime / TimeUtil::SEC_TO_MILLISEC;
191 std::string date = TimeUtil::TimestampFormatToDate(happenTimeInSecond, "%Y%m%d");
192
193 AppEventTask appEventTask;
194 appEventTask.id_ = 0;
195 int32_t dateNum = 0;
196 auto result = std::from_chars(date.c_str(), date.c_str() + date.size(), dateNum);
197 if (result.ec != std::errc()) {
198 HIVIEW_LOGW("convert error, dateStr: %{public}s", date.c_str());
199 return false;
200 }
201 traceStorage_->QueryAppEventTask(uid, dateNum, appEventTask);
202 return appEventTask.id_ > 0;
203 }
204
RecordCaller(std::shared_ptr<AppCallerEvent> appEvent)205 bool TraceFlowController::RecordCaller(std::shared_ptr<AppCallerEvent> appEvent)
206 {
207 uint64_t happenTimeInSecond = appEvent->happenTime_ / TimeUtil::SEC_TO_MILLISEC;
208 std::string date = TimeUtil::TimestampFormatToDate(happenTimeInSecond, "%Y%m%d");
209 int64_t dateNum = 0;
210 auto result = std::from_chars(date.c_str(), date.c_str() + date.size(), dateNum);
211 if (result.ec != std::errc()) {
212 HIVIEW_LOGW("convert error, dateStr: %{public}s", date.c_str());
213 return false;
214 }
215 AppEventTask appEventTask;
216 appEventTask.taskDate_ = dateNum;
217 appEventTask.taskType_ = APP_EVENT_TASK_TYPE_JANK_EVENT;
218 appEventTask.uid_ = appEvent->uid_;
219 appEventTask.pid_ = appEvent->pid_;
220 appEventTask.bundleName_ = appEvent->bundleName_;
221 appEventTask.bundleVersion_ = appEvent->bundleVersion_;
222 appEventTask.startTime_ = appEvent->taskBeginTime_;
223 appEventTask.finishTime_ = appEvent->taskEndTime_;
224 appEventTask.resourePath_ = appEvent->externalLog_;
225 appEventTask.resourceSize_ = static_cast<int32_t>(FileUtil::GetFileSize(appEventTask.resourePath_));
226 appEventTask.state_ = APP_EVENT_TASK_STATE_FINISH;
227 return traceStorage_->StoreAppEventTask(appEventTask);
228 }
229
CleanOldAppTrace()230 void TraceFlowController::CleanOldAppTrace()
231 {
232 UCollect::TraceCaller caller = UCollect::TraceCaller::APP;
233 FileRemove(caller);
234
235 uint64_t timeNow = TimeUtil::GetMilliseconds() / TimeUtil::SEC_TO_MILLISEC;
236 uint32_t secondsOfThreeDays = 3 * TimeUtil::SECONDS_PER_DAY; // 3 : clean data three days ago
237 if (timeNow < secondsOfThreeDays) {
238 HIVIEW_LOGW("time is invalid");
239 return;
240 }
241 uint64_t timeThreeDaysAgo = timeNow - secondsOfThreeDays;
242 std::string dateThreeDaysAgo = TimeUtil::TimestampFormatToDate(timeThreeDaysAgo, "%Y%m%d");
243 int32_t dateNum = 0;
244 auto result = std::from_chars(dateThreeDaysAgo.c_str(),
245 dateThreeDaysAgo.c_str() + dateThreeDaysAgo.size(), dateNum);
246 if (result.ec != std::errc()) {
247 HIVIEW_LOGW("convert error, dateStr: %{public}s", dateThreeDaysAgo.c_str());
248 return;
249 }
250 traceStorage_->RemoveOldAppEventTask(dateNum);
251 }
252 } // HiViewDFX
253 } // OHOS
254