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