1 /*
2  * Copyright (C) 2024-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 "wifi_net_stats_manager.h"
17 #include "wifi_common_util.h"
18 #include <algorithm>
19 #include "net_stats_client.h"
20 #include "wifi_system_timer.h"
21 #include "wifi_logger.h"
22 
23 namespace OHOS {
24 namespace Wifi {
25 DEFINE_WIFILOG_LABEL("WifiNetStats");
26 
27 const char* WLAN_0 = "wlan0";
28 const char* UNKNOWN_PACKAGE_NAME = "unknown_package";
29 const char* SEP_STR = "/";
30 const char* END_STR = ",";
31 const int32_t UID_ALL = -1;
32 const int32_t MAX_LOG_TRAFFIC = 10;
33 const int64_t NET_STATS_POLL_INTERVAL = 10 * 1000;
34 const int64_t NET_STATS_DELAY_TIME = 2 * 1000;
35 
StartNetStats()36 void WifiNetStatsManager::StartNetStats()
37 {
38     WIFI_LOGI("%{public}s, enter", __FUNCTION__);
39     if (m_netStatsTimerId != 0) {
40         WIFI_LOGI("%{public}s, m_netStatsTimerId is not zero", __FUNCTION__);
41         return;
42     }
43     std::shared_ptr<WifiSysTimer> netStatsTimer =
44         std::make_shared<WifiSysTimer>(true, NET_STATS_POLL_INTERVAL, true, false);
45     std::function<void()> callback = std::bind(&WifiNetStatsManager::PerformPollAndLog, this);
46     netStatsTimer->SetCallbackInfo(callback);
47     m_netStatsTimerId = MiscServices::TimeServiceClient::GetInstance()->CreateTimer(netStatsTimer);
48     int64_t currentTime = MiscServices::TimeServiceClient::GetInstance()->GetBootTimeMs();
49     MiscServices::TimeServiceClient::GetInstance()->StartTimer(m_netStatsTimerId, currentTime + NET_STATS_DELAY_TIME);
50     WIFI_LOGI("%{public}s, succuss", __FUNCTION__);
51 }
52 
StopNetStats()53 void WifiNetStatsManager::StopNetStats()
54 {
55     WIFI_LOGI("%{public}s, enter", __FUNCTION__);
56     if (m_netStatsTimerId == 0) {
57         WIFI_LOGE("%{public}s, m_netStatsTimerId is zero", __FUNCTION__);
58     } else {
59         MiscServices::TimeServiceClient::GetInstance()->StopTimer(m_netStatsTimerId);
60         MiscServices::TimeServiceClient::GetInstance()->DestroyTimer(m_netStatsTimerId);
61         m_netStatsTimerId = 0;
62     }
63     std::lock_guard<std::mutex> lock(lastStatsMapMutex_);
64     m_lastStatsMap.clear();
65     m_hasLastStats = false;
66     WIFI_LOGI("%{public}s, succuss", __FUNCTION__);
67 }
68 
PerformPollAndLog()69 void WifiNetStatsManager::PerformPollAndLog()
70 {
71     NetStats curNetStats;
72     if (GetWifiNetStatsDetail(curNetStats) != WIFI_OPT_SUCCESS) {
73         WIFI_LOGE("%{public}s, get network stats failed", __FUNCTION__);
74         return;
75     }
76     std::lock_guard<std::mutex> lock(lastStatsMapMutex_);
77     if (!m_hasLastStats) {
78         WIFI_LOGE("%{public}s, get base network stats", __FUNCTION__);
79         m_hasLastStats = true;
80         m_lastStatsMap = ConvertNetStatsToMap(curNetStats);
81         return;
82     }
83     NetStats incrementalNetStats = GetIncrementalNetStats(curNetStats);
84     m_lastStatsMap = ConvertNetStatsToMap(curNetStats);
85     LogNetStatsTraffic(incrementalNetStats);
86 }
87 
GetWifiNetStatsDetail(NetStats & netStats)88 ErrCode WifiNetStatsManager::GetWifiNetStatsDetail(NetStats &netStats)
89 {
90     NetStats data;
91     int32_t ret = DelayedSingleton<NetManagerStandard::NetStatsClient>::GetInstance()->GetAllStatsInfo(data);
92     if (ret != ERR_OK) {
93         WIFI_LOGE("%{public}s, get network stats failed, ret: %{public}d", __FUNCTION__, ret);
94         return WIFI_OPT_FAILED;
95     }
96     std::copy_if(data.begin(), data.end(), std::back_insert_iterator(netStats), [](NetStatsInfo info) {
97         return info.iface_ == WLAN_0 && !info.HasNoData();
98     });
99     return WIFI_OPT_SUCCESS;
100 }
101 
GetIncrementalNetStats(NetStats curNetStats)102 NetStats WifiNetStatsManager::GetIncrementalNetStats(NetStats curNetStats)
103 {
104     NetStats incrementNetStats;
105     for (auto &curInfo : curNetStats) {
106         NetStatsInfo deltaInfo;
107         auto indexIter = m_lastStatsMap.find(curInfo.uid_);
108         if (indexIter == m_lastStatsMap.end()) {
109             deltaInfo = curInfo;
110         } else {
111             deltaInfo = curInfo - indexIter->second;
112         }
113         if (deltaInfo.HasNoData()) {
114             continue;
115         }
116         incrementNetStats.push_back(deltaInfo);
117     }
118     return incrementNetStats;
119 }
120 
GetTotalNetStatsInfo(NetStats netStats)121 NetStatsInfo WifiNetStatsManager::GetTotalNetStatsInfo(NetStats netStats)
122 {
123     NetStatsInfo totalNetStatsInfo;
124     for (const auto &info : netStats) {
125         totalNetStatsInfo += info;
126     }
127     totalNetStatsInfo.uid_ = UID_ALL;
128     return totalNetStatsInfo;
129 }
130 
ConvertNetStatsToMap(NetStats netStats)131 std::map<int32_t, NetStatsInfo> WifiNetStatsManager::ConvertNetStatsToMap(NetStats netStats)
132 {
133     std::map<int32_t, NetStatsInfo> netStatsMap;
134     for (const auto &item : netStats) {
135         netStatsMap.emplace(item.uid_, item);
136     }
137     return netStatsMap;
138 }
139 
GetTrafficLog(std::string bundleName,NetStatsInfo info,bool needEndStr)140 std::string WifiNetStatsManager::GetTrafficLog(std::string bundleName, NetStatsInfo info, bool needEndStr)
141 {
142     std::string trafficLog;
143     trafficLog += bundleName;
144     trafficLog += SEP_STR;
145     trafficLog += std::to_string(info.rxBytes_);
146     trafficLog += SEP_STR;
147     trafficLog += std::to_string(info.txBytes_);
148     trafficLog += SEP_STR;
149     trafficLog += std::to_string(info.rxPackets_);
150     trafficLog += SEP_STR;
151     trafficLog += std::to_string(info.txPackets_);
152     if (needEndStr) {
153         trafficLog += END_STR;
154     }
155     return trafficLog;
156 }
157 
GetBundleName(int32_t uid)158 std::string WifiNetStatsManager::GetBundleName(int32_t uid)
159 {
160     if (uid == UID_ALL) {
161         return "total";
162     }
163     std::string bundleName;
164     if (OHOS::Wifi::GetBundleNameByUid(uid, bundleName) != WIFI_OPT_SUCCESS) {
165         return "unknown:" + std::to_string(uid);
166     }
167     return bundleName;
168 }
169 
LogNetStatsTraffic(NetStats netStats)170 void WifiNetStatsManager::LogNetStatsTraffic(NetStats netStats)
171 {
172     std::sort(netStats.begin(), netStats.end(), [] (NetStatsInfo v1, NetStatsInfo v2) {
173         return v1.GetStats() > v2.GetStats();
174     });
175     int maxCount = netStats.size() >= MAX_LOG_TRAFFIC ? MAX_LOG_TRAFFIC : static_cast<int>(netStats.size());
176     NetStatsInfo totalNetStats = GetTotalNetStatsInfo(netStats);
177     if (totalNetStats.HasNoData()) {
178         return;
179     }
180     std::string allTrafficLog;
181     allTrafficLog += GetTrafficLog(GetBundleName(totalNetStats.uid_), totalNetStats);
182     for (int i = 0; i < maxCount; i++) {
183         if (i != maxCount - 1) {
184             allTrafficLog += GetTrafficLog(GetBundleName(netStats[i].uid_), netStats[i]);
185         } else {
186             allTrafficLog += GetTrafficLog(GetBundleName(netStats[i].uid_), netStats[i], false);
187         }
188     }
189     WIFI_LOGI("%{public}s", allTrafficLog.c_str());
190 }
191 } // namespace Wifi
192 } // namespace OHOS