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 #include "trans_network_statistics.h"
16
17 #include <securec.h>
18 #include "cJSON.h"
19
20 #include "comm_log.h"
21 #include "softbus_adapter_mem.h"
22 #include "softbus_errcode.h"
23 #include "softbus_json_utils.h"
24 #include "softbus_utils.h"
25 #include "trans_event.h"
26
27 typedef struct {
28 ListNode node;
29 int32_t channelId;
30 int32_t channelType;
31 } ChannelDfxInfo;
32
33 typedef struct {
34 ListNode node;
35 int32_t channelId;
36 char *channelInfo;
37 uint32_t len;
38 } ChannelStatisticsInfo;
39
40 typedef struct {
41 ListNode node;
42 NetworkResource resource;
43 int64_t startTime;
44 int64_t endTime;
45 ListNode channels;
46 } NetworkStatisticsInfo;
47
48 static SoftBusList *g_networkResourceList = NULL;
49
50 static SoftBusList *g_channelDfxInfoList = NULL;
51
AddChannelStatisticsInfo(int32_t channelId,int32_t channelType)52 void AddChannelStatisticsInfo(int32_t channelId, int32_t channelType)
53 {
54 if (channelId < 0) {
55 COMM_LOGE(COMM_DFX, "invalid param");
56 return;
57 }
58 if (g_channelDfxInfoList == NULL) {
59 COMM_LOGE(COMM_DFX, "channel info list init failed, channelId=%{public}d", channelId);
60 return;
61 }
62 if (SoftBusMutexLock(&g_channelDfxInfoList->lock) != SOFTBUS_OK) {
63 COMM_LOGE(COMM_DFX, "channel info list lock failed, channelId=%{public}d", channelId);
64 return;
65 }
66 if ((int32_t)g_channelDfxInfoList->cnt >= MAX_CHANNEL_INFO_NUM) {
67 COMM_LOGE(COMM_DFX, "channel info list out of max num, channelId=%{public}d", channelId);
68 (void)SoftBusMutexUnlock(&g_channelDfxInfoList->lock);
69 return;
70 }
71
72 ChannelDfxInfo *temp = NULL;
73 LIST_FOR_EACH_ENTRY(temp, &g_channelDfxInfoList->list, ChannelDfxInfo, node) {
74 if (temp->channelId == channelId && temp->channelType == channelType) {
75 COMM_LOGE(COMM_DFX, "channel info already in channel info list, channelId=%{public}d", channelId);
76 (void)SoftBusMutexUnlock(&g_channelDfxInfoList->lock);
77 return;
78 }
79 }
80 ChannelDfxInfo *channelInfo = (ChannelDfxInfo *)SoftBusCalloc(sizeof(ChannelDfxInfo));
81 if (channelInfo == NULL) {
82 COMM_LOGE(COMM_DFX, "channel info calloc failed, channelId=%{public}d", channelId);
83 (void)SoftBusMutexUnlock(&g_channelDfxInfoList->lock);
84 return;
85 }
86 channelInfo->channelId = channelId;
87 channelInfo->channelType = channelType;
88 ListAdd(&g_channelDfxInfoList->list, &channelInfo->node);
89 g_channelDfxInfoList->cnt++;
90 (void)SoftBusMutexUnlock(&g_channelDfxInfoList->lock);
91 }
92
AddNetworkResource(NetworkResource * networkResource)93 void AddNetworkResource(NetworkResource *networkResource)
94 {
95 if (networkResource == NULL) {
96 COMM_LOGE(COMM_DFX, "invalid param");
97 return;
98 }
99 if (g_networkResourceList == NULL) {
100 COMM_LOGE(COMM_DFX, "g_networkResourceList init fail");
101 return;
102 }
103 if (SoftBusMutexLock(&g_networkResourceList->lock) != SOFTBUS_OK) {
104 COMM_LOGE(COMM_DFX, "lock failed");
105 return;
106 }
107 if ((int32_t)g_networkResourceList->cnt >= MAX_NETWORK_RESOURCE_NUM) {
108 COMM_LOGE(COMM_DFX, "network Resource out of max num");
109 (void)SoftBusMutexUnlock(&g_networkResourceList->lock);
110 return;
111 }
112
113 NetworkStatisticsInfo *temp = NULL;
114 LIST_FOR_EACH_ENTRY(temp, &g_networkResourceList->list, NetworkStatisticsInfo, node) {
115 if (temp->resource.laneId == networkResource->laneId) {
116 COMM_LOGE(COMM_DFX, "laneId already in g_networkResourceList");
117 (void)SoftBusMutexUnlock(&g_networkResourceList->lock);
118 return;
119 }
120 }
121 NetworkStatisticsInfo *info = (NetworkStatisticsInfo *)SoftBusCalloc(sizeof(NetworkStatisticsInfo));
122 if (info == NULL) {
123 COMM_LOGE(COMM_DFX, "network resource info SoftBusCalloc fail");
124 (void)SoftBusMutexUnlock(&g_networkResourceList->lock);
125 return;
126 }
127 if (memcpy_s(&info->resource, sizeof(NetworkResource), networkResource, sizeof(NetworkResource)) != EOK) {
128 COMM_LOGE(COMM_DFX, "network resource memcpy fail");
129 (void)SoftBusMutexUnlock(&g_networkResourceList->lock);
130 SoftBusFree(info);
131 return;
132 }
133 ListInit(&info->node);
134 ListInit(&info->channels);
135 info->startTime = SoftBusGetSysTimeMs();
136 ListAdd(&g_networkResourceList->list, &info->node);
137 g_networkResourceList->cnt++;
138 (void)SoftBusMutexUnlock(&g_networkResourceList->lock);
139 }
140
IsChannelDfxInfoValid(int32_t channelId,int32_t channelType)141 static bool IsChannelDfxInfoValid(int32_t channelId, int32_t channelType)
142 {
143 if (channelId < 0) {
144 COMM_LOGE(COMM_DFX, "invalid param");
145 return false;
146 }
147 if (g_channelDfxInfoList == NULL) {
148 COMM_LOGE(COMM_DFX, "channel info list init failed, channelId=%{public}d", channelId);
149 return false;
150 }
151 if (SoftBusMutexLock(&g_channelDfxInfoList->lock) != SOFTBUS_OK) {
152 COMM_LOGE(COMM_DFX, "channel info list lock failed, channelId=%{public}d", channelId);
153 return false;
154 }
155
156 bool ret = false;
157 ChannelDfxInfo *temp = NULL;
158 LIST_FOR_EACH_ENTRY(temp, &g_channelDfxInfoList->list, ChannelDfxInfo, node) {
159 if (temp->channelId == channelId && temp->channelType == channelType) {
160 ret = true;
161 break;
162 }
163 }
164 (void)SoftBusMutexUnlock(&g_channelDfxInfoList->lock);
165 return ret;
166 }
167
RemoveChannelDfxInfo(int32_t channelId,int32_t channelType)168 static void RemoveChannelDfxInfo(int32_t channelId, int32_t channelType)
169 {
170 if (channelId < 0) {
171 COMM_LOGE(COMM_DFX, "invalid param");
172 return;
173 }
174 if (g_channelDfxInfoList == NULL) {
175 COMM_LOGE(COMM_DFX, "channel info list init failed, channelId=%{public}d", channelId);
176 return;
177 }
178 if (SoftBusMutexLock(&g_channelDfxInfoList->lock) != SOFTBUS_OK) {
179 COMM_LOGE(COMM_DFX, "channel info list lock failed, channelId=%{public}d", channelId);
180 return;
181 }
182
183 ChannelDfxInfo *temp = NULL;
184 ChannelDfxInfo *next = NULL;
185 LIST_FOR_EACH_ENTRY_SAFE(temp, next, &(g_channelDfxInfoList->list), ChannelDfxInfo, node) {
186 if (temp->channelId == channelId && temp->channelType == channelType) {
187 ListDelete(&temp->node);
188 g_channelDfxInfoList->cnt--;
189 SoftBusFree(temp);
190 }
191 }
192 (void)SoftBusMutexUnlock(&g_channelDfxInfoList->lock);
193 }
194
SetChannelStatisticsInfo(ChannelStatisticsInfo * info,int32_t channelId,const void * dataInfo,uint32_t len)195 static int32_t SetChannelStatisticsInfo(ChannelStatisticsInfo *info, int32_t channelId, const void *dataInfo,
196 uint32_t len)
197 {
198 if (info == NULL || dataInfo == NULL || len > MAX_SOCKET_RESOURCE_LEN) {
199 COMM_LOGE(COMM_DFX, "invalid param, channelId=%{public}d", channelId);
200 return SOFTBUS_INVALID_PARAM;
201 }
202
203 info->channelInfo = (char *)SoftBusMalloc(len);
204 if (info->channelInfo == NULL) {
205 COMM_LOGE(COMM_DFX, "channel info mallloc fail, channelId=%{public}d", channelId);
206 return SOFTBUS_MALLOC_ERR;
207 }
208 if (memcpy_s(info->channelInfo, len, (char *)dataInfo, len) != EOK) {
209 COMM_LOGE(COMM_DFX, "channel info memcpy fail, channelId=%{public}d", channelId);
210 SoftBusFree(info->channelInfo);
211 return SOFTBUS_MEM_ERR;
212 }
213 info->channelId = channelId;
214 info->len = len;
215 return SOFTBUS_OK;
216 }
217
UpdateNetworkResourceByLaneId(int32_t channelId,int32_t channelType,uint64_t laneId,const void * dataInfo,uint32_t len)218 void UpdateNetworkResourceByLaneId(int32_t channelId, int32_t channelType, uint64_t laneId,
219 const void *dataInfo, uint32_t len)
220 {
221 if (dataInfo == NULL || len > MAX_SOCKET_RESOURCE_LEN || !IsChannelDfxInfoValid(channelId, channelType)) {
222 COMM_LOGE(COMM_DFX, "invalid param, channelId=%{public}d", channelId);
223 return;
224 }
225 RemoveChannelDfxInfo(channelId, channelType);
226 if (g_networkResourceList == NULL) {
227 COMM_LOGE(COMM_DFX, "network resource list init fail, channelId=%{public}d", channelId);
228 return;
229 }
230 if (SoftBusMutexLock(&g_networkResourceList->lock) != SOFTBUS_OK) {
231 COMM_LOGE(COMM_DFX, "lock failed, channelId=%{public}d", channelId);
232 return;
233 }
234
235 NetworkStatisticsInfo *temp = NULL;
236 LIST_FOR_EACH_ENTRY(temp, &g_networkResourceList->list, NetworkStatisticsInfo, node) {
237 if (temp->resource.laneId != laneId) {
238 continue;
239 }
240 ChannelStatisticsInfo *item = NULL;
241 LIST_FOR_EACH_ENTRY(item, &temp->channels, ChannelStatisticsInfo, node) {
242 if (item->channelId == channelId) {
243 COMM_LOGE(COMM_DFX, "channelId already in channels, channelId=%{public}d", channelId);
244 (void)SoftBusMutexUnlock(&g_networkResourceList->lock);
245 return;
246 }
247 }
248 ChannelStatisticsInfo *info = (ChannelStatisticsInfo *)SoftBusCalloc(sizeof(ChannelStatisticsInfo));
249 if (info == NULL) {
250 COMM_LOGE(COMM_DFX, "channel statistics info SoftBusCalloc fail, channelId=%{public}d", channelId);
251 (void)SoftBusMutexUnlock(&g_networkResourceList->lock);
252 return;
253 }
254 if (SetChannelStatisticsInfo(info, channelId, dataInfo, len) != SOFTBUS_OK) {
255 COMM_LOGE(COMM_DFX, "channel statistics info set fail, channelId=%{public}d", channelId);
256 (void)SoftBusMutexUnlock(&g_networkResourceList->lock);
257 SoftBusFree(info);
258 return;
259 }
260 ListInit(&info->node);
261 ListAdd(&temp->channels, &info->node);
262 (void)SoftBusMutexUnlock(&g_networkResourceList->lock);
263 return;
264 }
265 (void)SoftBusMutexUnlock(&g_networkResourceList->lock);
266 }
267
PackNetworkStatistics(cJSON * json,NetworkStatisticsInfo * info)268 static int32_t PackNetworkStatistics(cJSON *json, NetworkStatisticsInfo *info)
269 {
270 if (json == NULL || info == NULL) {
271 COMM_LOGE(COMM_DFX, "invalid param");
272 return SOFTBUS_INVALID_PARAM;
273 }
274
275 char laneId[MAX_LANE_ID_LEN] = { 0 };
276 if (sprintf_s(laneId, sizeof(laneId), "%"PRIu64"", info->resource.laneId) < 0) {
277 COMM_LOGE(COMM_DFX, "sprintf lane id fail");
278 return SOFTBUS_MEM_ERR;
279 }
280 if (!AddStringToJsonObject(json, "laneId", laneId) ||
281 !AddStringToJsonObject(json, "localUdid", info->resource.localUdid) ||
282 !AddStringToJsonObject(json, "peerUdid", info->resource.peerUdid)) {
283 return SOFTBUS_PARSE_JSON_ERR;
284 }
285 if (!AddNumberToJsonObject(json, "lineLinkType", info->resource.laneLinkType) ||
286 !AddNumber64ToJsonObject(json, "startTime", info->startTime) ||
287 !AddNumber64ToJsonObject(json, "endTime", info->endTime)) {
288 return SOFTBUS_PARSE_JSON_ERR;
289 }
290
291 cJSON *channelStatsObj = cJSON_AddArrayToObject(json, "channelStats");
292 if (channelStatsObj == NULL) {
293 return SOFTBUS_PARSE_JSON_ERR;
294 }
295 ChannelStatisticsInfo *temp = NULL;
296 LIST_FOR_EACH_ENTRY(temp, &info->channels, ChannelStatisticsInfo, node) {
297 if (temp->channelInfo != NULL) {
298 cJSON_AddItemToArray(channelStatsObj, cJSON_Parse(temp->channelInfo));
299 }
300 }
301 return SOFTBUS_OK;
302 }
303
DfxRecordTransChannelStatistics(NetworkStatisticsInfo * networkStatisticsInfo)304 static void DfxRecordTransChannelStatistics(NetworkStatisticsInfo *networkStatisticsInfo)
305 {
306 if (networkStatisticsInfo == NULL) {
307 COMM_LOGE(COMM_DFX, "invalid param");
308 return;
309 }
310 if (IsListEmpty(&networkStatisticsInfo->channels)) {
311 return;
312 }
313 cJSON *json = cJSON_CreateObject();
314 COMM_CHECK_AND_RETURN_LOGW(json != NULL, COMM_DFX, "cJSON_CreateObject fail");
315
316 if (PackNetworkStatistics(json, networkStatisticsInfo) != SOFTBUS_OK) {
317 cJSON_Delete(json);
318 return;
319 }
320 char *trafficStats = cJSON_PrintUnformatted(json);
321 cJSON_Delete(json);
322 COMM_CHECK_AND_RETURN_LOGW(trafficStats != NULL, COMM_DFX, "cJSON_PrintUnformatted fail");
323 TransEventExtra extra = {
324 .result = EVENT_STAGE_RESULT_OK,
325 .trafficStats = trafficStats
326 };
327 TRANS_EVENT(EVENT_SCENE_TRANS_CHANNEL_STATISTICS, EVENT_STAGE_TRANS_COMMON_ONE, extra);
328 cJSON_free(trafficStats);
329 }
330
DeleteNetworkResourceByLaneId(uint64_t laneId)331 void DeleteNetworkResourceByLaneId(uint64_t laneId)
332 {
333 if (g_networkResourceList == NULL) {
334 COMM_LOGE(COMM_DFX, "network resource list init fail");
335 return;
336 }
337 if (SoftBusMutexLock(&g_networkResourceList->lock) != SOFTBUS_OK) {
338 COMM_LOGE(COMM_DFX, "lock failed");
339 return;
340 }
341
342 NetworkStatisticsInfo *item = NULL;
343 NetworkStatisticsInfo *next = NULL;
344 LIST_FOR_EACH_ENTRY_SAFE(item, next, &(g_networkResourceList->list), NetworkStatisticsInfo, node) {
345 if (item->resource.laneId == laneId) {
346 item->endTime = SoftBusGetSysTimeMs();
347 DfxRecordTransChannelStatistics(item);
348 ChannelStatisticsInfo *channelItem = NULL;
349 ChannelStatisticsInfo *channelNext = NULL;
350 LIST_FOR_EACH_ENTRY_SAFE(channelItem, channelNext, &item->channels, ChannelStatisticsInfo, node) {
351 ListDelete(&channelItem->node);
352 SoftBusFree(channelItem->channelInfo);
353 SoftBusFree(channelItem);
354 }
355 ListDelete(&item->node);
356 g_networkResourceList->cnt--;
357 SoftBusFree(item);
358 }
359 }
360 (void)SoftBusMutexUnlock(&g_networkResourceList->lock);
361 }
362
TransNetworkStatisticsInit(void)363 int32_t TransNetworkStatisticsInit(void)
364 {
365 if (g_networkResourceList != NULL) {
366 COMM_LOGE(COMM_DFX, "network statistics has init");
367 return SOFTBUS_OK;
368 }
369 g_networkResourceList = CreateSoftBusList();
370 if (g_networkResourceList == NULL) {
371 COMM_LOGE(COMM_DFX, "network statistics init fail");
372 return SOFTBUS_MALLOC_ERR;
373 }
374
375 if (g_channelDfxInfoList != NULL) {
376 COMM_LOGE(COMM_DFX, "channel statistics has init");
377 return SOFTBUS_OK;
378 }
379 g_channelDfxInfoList = CreateSoftBusList();
380 if (g_channelDfxInfoList == NULL) {
381 COMM_LOGE(COMM_DFX, "channel statistics init fail");
382 return SOFTBUS_MALLOC_ERR;
383 }
384 return SOFTBUS_OK;
385 }
386
TransNetworkResourceDeinit(void)387 static void TransNetworkResourceDeinit(void)
388 {
389 if (g_networkResourceList == NULL) {
390 COMM_LOGE(COMM_DFX, "network statistics has deinit");
391 return;
392 }
393
394 if (SoftBusMutexLock(&g_networkResourceList->lock) != SOFTBUS_OK) {
395 COMM_LOGE(COMM_DFX, "lock failed");
396 return;
397 }
398 NetworkStatisticsInfo *item = NULL;
399 NetworkStatisticsInfo *next = NULL;
400 LIST_FOR_EACH_ENTRY_SAFE(item, next, &(g_networkResourceList->list), NetworkStatisticsInfo, node) {
401 if (!IsListEmpty(&item->channels)) {
402 ChannelStatisticsInfo *channelItem = NULL;
403 ChannelStatisticsInfo *channelNext = NULL;
404 LIST_FOR_EACH_ENTRY_SAFE(channelItem, channelNext, &item->channels, ChannelStatisticsInfo, node) {
405 ListDelete(&channelItem->node);
406 SoftBusFree(channelItem->channelInfo);
407 SoftBusFree(channelItem);
408 }
409 }
410 ListDelete(&item->node);
411 SoftBusFree(item);
412 }
413 g_networkResourceList->cnt = 0;
414 (void)SoftBusMutexUnlock(&g_networkResourceList->lock);
415 DestroySoftBusList(g_networkResourceList);
416 g_networkResourceList = NULL;
417 }
418
TransChannelStatisticsDeinit(void)419 static void TransChannelStatisticsDeinit(void)
420 {
421 if (g_channelDfxInfoList == NULL) {
422 COMM_LOGE(COMM_DFX, "channel statistics has deinit");
423 return;
424 }
425
426 if (SoftBusMutexLock(&g_channelDfxInfoList->lock) != SOFTBUS_OK) {
427 COMM_LOGE(COMM_DFX, "channel statistics lock failed");
428 return;
429 }
430 ChannelDfxInfo *item = NULL;
431 ChannelDfxInfo *next = NULL;
432 LIST_FOR_EACH_ENTRY_SAFE(item, next, &(g_channelDfxInfoList->list), ChannelDfxInfo, node) {
433 ListDelete(&item->node);
434 SoftBusFree(item);
435 }
436 g_channelDfxInfoList->cnt = 0;
437 (void)SoftBusMutexUnlock(&g_channelDfxInfoList->lock);
438 DestroySoftBusList(g_channelDfxInfoList);
439 g_channelDfxInfoList = NULL;
440 }
441
TransNetworkStatisticsDeinit(void)442 void TransNetworkStatisticsDeinit(void)
443 {
444 TransNetworkResourceDeinit();
445 TransChannelStatisticsDeinit();
446 }