• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }