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 }