1 /*
2 * Copyright (c) 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
16 #include <sstream>
17 #include <chrono>
18 #include <unistd.h>
19
20 #include "hisysevent.h"
21 #include "netstack_log.h"
22 #include "netstack_hisysevent.h"
23 #include "netstack_common_utils.h"
24
25 namespace OHOS::NetStack {
26
27 namespace {
28 using HiSysEvent = OHOS::HiviewDFX::HiSysEvent;
29 const uint32_t REPORT_INTERVAL = 3 * 60;
30 const uint32_t REPORT_NET_STACK_INTERVAL = 10 * 1000;
31 // event_name
32 constexpr const char *HTTP_PERF_ENAME = "HTTP_PERF";
33 constexpr const char *HTTP_RESPONSE_ERROR = "NET_STACK_HTTP_RESPONSE_ERROR";
34 // event params
35 constexpr const char *PACKAGE_NAME_EPARA = "PACKAGE_NAME";
36 constexpr const char *TOTAL_TIME_EPARA = "TOTAL_TIME";
37 constexpr const char *TOTAL_RATE_EPARA = "TOTAL_RATE";
38 constexpr const char *SUCCESS_COUNT_EPARA = "SUCCESS_COUNT";
39 constexpr const char *TOTAL_COUNT_EPARA = "TOTAL_COUNT";
40 constexpr const char *VERSION_EPARA = "VERSION";
41 constexpr const char *TOTAL_DNS_TIME_EPARA = "TOTAL_DNS_TIME";
42 constexpr const char *TOTAL_TLS_TIME_EPARA = "TOTAL_TLS_TIME";
43 constexpr const char *TOTAL_TCP_TIME_EPARA = "TOTAL_TCP_TIME";
44 constexpr const char *TOTAL_FIRST_RECVIVE_TIME_EPARA = "TOTAL_FIRST_RECEIVE_TIME";
45 constexpr const char *IP_TYPE_EPARA = "IP_TYPE";
46 constexpr const char *OS_ERR_EPARA = "OS_ERR";
47 constexpr const char *ERROR_CODE_EPARA = "ERROR_CODE";
48 const int64_t VALIAD_RESP_CODE_START = 200;
49 const int64_t VALIAD_RESP_CODE_END = 399;
50 const int64_t ERROR_HTTP_CODE_START = 400;
51 const int64_t ERROR_HTTP_CODE_END = 600;
52 const int64_t HTTP_SUCCEED_CODE = 0;
53 const int64_t HTTP_APP_UID_THRESHOLD = 200000 * 100;
54 const int64_t HTTP_SEND_CHR_THRESHOLD = 5;
55 const unsigned int ERROR_COUNT_THRESHOLD = 10;
56 const uint32_t REPORT_HIVIEW_INTERVAL = 10 * 60 * 1000;
57 }
58
IsSuccess() const59 bool HttpPerfInfo::IsSuccess() const
60 {
61 return responseCode >= VALIAD_RESP_CODE_START && responseCode <= VALIAD_RESP_CODE_END;
62 }
63
IsError() const64 bool HttpPerfInfo::IsError() const
65 {
66 return (responseCode >= ERROR_HTTP_CODE_START && responseCode < ERROR_HTTP_CODE_END)
67 || errCode != HTTP_SUCCEED_CODE;
68 }
69
EventReport()70 EventReport::EventReport()
71 {
72 InitPackageName();
73 }
74
InitPackageName()75 void EventReport::InitPackageName()
76 {
77 if (CommonUtils::GetBundleName().has_value()) {
78 packageName_ = CommonUtils::GetBundleName().value();
79 } else {
80 validFlag = false;
81 }
82 // init eventInfo
83 ResetCounters();
84 }
85
IsValid()86 bool EventReport::IsValid()
87 {
88 return validFlag;
89 }
90
GetInstance()91 EventReport &EventReport::GetInstance()
92 {
93 static EventReport instance;
94 return instance;
95 }
96
ProcessHttpPerfHiSysevent(const HttpPerfInfo & httpPerfInfo)97 void EventReport::ProcessHttpPerfHiSysevent(const HttpPerfInfo &httpPerfInfo)
98 {
99 std::lock_guard<std::recursive_mutex> lock(mutex);
100
101 HandleHttpResponseErrorEvents(httpPerfInfo);
102 HandleHttpPerfEvents(httpPerfInfo);
103 }
104
HandleHttpPerfEvents(const HttpPerfInfo & httpPerfInfo)105 void EventReport::HandleHttpPerfEvents(const HttpPerfInfo &httpPerfInfo)
106 {
107 time_t currentTime = time(0);
108
109 if (reportTime == 0) {
110 reportTime = currentTime;
111 }
112 eventInfo.totalCount += 1;
113 if (httpPerfInfo.IsSuccess() && httpPerfInfo.totalTime != 0) {
114 eventInfo.successCount += 1;
115 eventInfo.totalTime += httpPerfInfo.totalTime;
116 eventInfo.totalRate += httpPerfInfo.size / httpPerfInfo.totalTime;
117 eventInfo.totalDnsTime += httpPerfInfo.dnsTime;
118 eventInfo.totalTlsTime += httpPerfInfo.tlsTime;
119 eventInfo.totalFirstRecvTime += httpPerfInfo.firstRecvTime;
120 eventInfo.totalTcpTime += httpPerfInfo.tcpTime;
121 auto result = versionMap.emplace(httpPerfInfo.version, 1);
122 if (!result.second) {
123 ++(result.first->second);
124 }
125 }
126
127 if (currentTime - reportTime >= REPORT_INTERVAL) {
128 eventInfo.packageName = packageName_;
129 eventInfo.version = MapToJsonString(versionMap);
130 NETSTACK_LOGD("Sending HTTP_PERF event");
131 SendHttpPerfEvent(eventInfo);
132 ResetCounters();
133 reportTime = currentTime;
134 }
135 }
136
HandleHttpResponseErrorEvents(const HttpPerfInfo & httpPerfInfo)137 void EventReport::HandleHttpResponseErrorEvents(const HttpPerfInfo &httpPerfInfo)
138 {
139 if (getuid() <= HTTP_APP_UID_THRESHOLD) {
140 return;
141 }
142 if (!httpPerfInfo.IsError()) {
143 totalErrorCount_ = 0;
144 httpPerfInfoQueue_.clear();
145 httpReponseRecordTime_ = std::chrono::steady_clock::time_point::min();
146 return;
147 }
148 totalErrorCount_ += 1;
149 httpPerfInfoQueue_.push_back(httpPerfInfo);
150
151 auto now = std::chrono::steady_clock::now();
152 uint32_t httpReportInterval_ = 0;
153 if (httpReponseRecordTime_ != std::chrono::steady_clock::time_point::min()) {
154 httpReportInterval_ = static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::milliseconds>
155 (now - httpReponseRecordTime_).count());
156 }
157 httpReponseRecordTime_ = now;
158
159 if (totalErrorCount_ >= ERROR_COUNT_THRESHOLD || httpReportInterval_ >= REPORT_NET_STACK_INTERVAL) {
160 SendHttpResponseErrorEvent(httpPerfInfoQueue_, now);
161 totalErrorCount_ = 0;
162 httpPerfInfoQueue_.clear();
163 httpReponseRecordTime_ = std::chrono::steady_clock::time_point::min();
164 }
165 }
166
ResetCounters()167 void EventReport::ResetCounters()
168 {
169 eventInfo.totalCount = 0;
170 eventInfo.successCount = 0;
171 eventInfo.totalTime = 0.0;
172 eventInfo.totalRate = 0.0;
173 eventInfo.totalDnsTime = 0.0;
174 eventInfo.totalTlsTime = 0.0;
175 eventInfo.totalTcpTime = 0.0;
176 eventInfo.totalFirstRecvTime = 0.0;
177 versionMap.clear();
178 }
179
MapToJsonString(const std::map<std::string,uint32_t> mapPara)180 std::string EventReport::MapToJsonString(const std::map<std::string, uint32_t> mapPara)
181 {
182 if (mapPara.empty()) {
183 return "{}";
184 }
185 std::stringstream sStream;
186 size_t count = 0;
187 for (const auto &pair : mapPara) {
188 sStream << "\"" << pair.first << "\":" << pair.second;
189 count++;
190 if (count < mapPara.size()) {
191 sStream << ",";
192 }
193 }
194 return "{" + sStream.str() + "}";
195 }
196
SendHttpPerfEvent(const EventInfo & eventInfo)197 void EventReport::SendHttpPerfEvent(const EventInfo &eventInfo)
198 {
199 int ret = HiSysEventWrite(
200 HiSysEvent::Domain::NETMANAGER_STANDARD, HTTP_PERF_ENAME, HiSysEvent::EventType::STATISTIC, PACKAGE_NAME_EPARA,
201 eventInfo.packageName, TOTAL_TIME_EPARA, eventInfo.totalTime, TOTAL_RATE_EPARA, eventInfo.totalRate,
202 SUCCESS_COUNT_EPARA, eventInfo.successCount, TOTAL_COUNT_EPARA, eventInfo.totalCount, VERSION_EPARA,
203 eventInfo.version, TOTAL_DNS_TIME_EPARA, eventInfo.totalDnsTime, TOTAL_TLS_TIME_EPARA, eventInfo.totalTlsTime,
204 TOTAL_TCP_TIME_EPARA, eventInfo.totalTcpTime, TOTAL_FIRST_RECVIVE_TIME_EPARA, eventInfo.totalFirstRecvTime);
205 if (ret != 0) {
206 NETSTACK_LOGE("Send HTTP_PERF event fail");
207 }
208 }
209
ReportHiSysEventWrite(const std::deque<HttpPerfInfo> & httpPerfInfoQueue_)210 void EventReport::ReportHiSysEventWrite(const std::deque<HttpPerfInfo> &httpPerfInfoQueue_)
211 {
212 if (httpPerfInfoQueue_.empty()) {
213 return;
214 }
215 std::vector<double> dnsTimeArr;
216 std::vector<double> tcpTimeArr;
217 std::vector<double> tlsTimeArr;
218 std::vector<int32_t> errCodeArr;
219 std::vector<int64_t> osErrArr;
220 std::vector<int> ipTypeArr;
221
222 for (const auto& info : httpPerfInfoQueue_) {
223 dnsTimeArr.push_back(info.dnsTime);
224 tcpTimeArr.push_back(info.tcpTime);
225 tlsTimeArr.push_back(info.tlsTime);
226 osErrArr.push_back(info.osErr);
227 ipTypeArr.push_back(info.ipType);
228 errCodeArr.push_back(info.errCode != 0 ? info.errCode : info.responseCode);
229 }
230
231 int ret = HiSysEventWrite(HiSysEvent::Domain::NETMANAGER_STANDARD, HTTP_RESPONSE_ERROR,
232 HiSysEvent::EventType::FAULT, PACKAGE_NAME_EPARA, packageName_,
233 TOTAL_DNS_TIME_EPARA, dnsTimeArr, TOTAL_TCP_TIME_EPARA, tcpTimeArr,
234 TOTAL_TLS_TIME_EPARA, tlsTimeArr, ERROR_CODE_EPARA, errCodeArr,
235 OS_ERR_EPARA, osErrArr, IP_TYPE_EPARA, ipTypeArr);
236 if (ret != 0) {
237 NETSTACK_LOGE("Send EventReport::ReportHiSysEventWrite event failed");
238 }
239 }
240
SendHttpResponseErrorEvent(const std::deque<HttpPerfInfo> & httpPerfInfoQueue_,const std::chrono::steady_clock::time_point now)241 void EventReport::SendHttpResponseErrorEvent(const std::deque<HttpPerfInfo> &httpPerfInfoQueue_,
242 const std::chrono::steady_clock::time_point now)
243 {
244 if (httpPerfInfoQueue_.empty()) {
245 return;
246 }
247 if (hiviewReportFirstTime_ == std::chrono::steady_clock::time_point::min()) {
248 hiviewReportFirstTime_ = now;
249 }
250 uint32_t hiviewReportInterval_ = static_cast<uint32_t>(
251 std::chrono::duration_cast<std::chrono::milliseconds>(now - hiviewReportFirstTime_).count());
252 if (hiviewReportInterval_ >= REPORT_HIVIEW_INTERVAL) {
253 sendHttpNetStackEventCount_ = 0;
254 hiviewReportFirstTime_ = std::chrono::steady_clock::time_point::min();
255 NETSTACK_LOGI("SendHttpResponseErrorEvent NET_STACK_HTTP_RESPONSE_ERROR event threshold reopen.");
256 } else if (sendHttpNetStackEventCount_ >= HTTP_SEND_CHR_THRESHOLD) {
257 NETSTACK_LOGI("SendHttpResponseErrorEvent NET_STACK_HTTP_RESPONSE_ERROR event threshold already reached.");
258 return;
259 }
260
261 ReportHiSysEventWrite(httpPerfInfoQueue_);
262 sendHttpNetStackEventCount_++;
263 }
264 }