1 /*
2 * Copyright (C) 2021-2023 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 "network_selection_manager.h"
18 #include "wifi_settings.h"
19 #include "wifi_logger.h"
20 #include "network_selection_utils.h"
21 #include "wifi_common_util.h"
22 #include "wifi_hisysevent.h"
23 #include "wifi_sensor_scene.h"
24 #include "wifi_channel_helper.h"
25 #include "wifi_service_manager.h"
26 #include "wifi_config_center.h"
27
28 namespace OHOS::Wifi {
29 DEFINE_WIFILOG_LABEL("networkSelectionManager")
30
31 const int OUTDOOR_NETWORK_SELECT_THRES = 3;
32
NetworkSelectionManager()33 NetworkSelectionManager::NetworkSelectionManager()
34 {
35 pNetworkSelectorFactory = std::make_unique<NetworkSelectorFactory>();
36 }
37
SelectNetworkWithSsid(WifiDeviceConfig & deviceConfig,std::string & autoSelectBssid)38 void NetworkSelectionManager::SelectNetworkWithSsid(WifiDeviceConfig& deviceConfig, std::string& autoSelectBssid)
39 {
40 WIFI_LOGI("Enter SelectNetworkWithSsid.");
41 std::vector<WifiScanInfo> wifiScanInfoList;
42 WifiConfigCenter::GetInstance().GetWifiScanConfig()->GetScanInfoList(wifiScanInfoList);
43 std::vector<InterScanInfo> interScanInfoList;
44 for (auto &wifiScanInfo : wifiScanInfoList) {
45 std::string deviceKeyMgmt;
46 wifiScanInfo.GetDeviceMgmt(deviceKeyMgmt);
47 if (wifiScanInfo.ssid == deviceConfig.ssid &&
48 WifiSettings::GetInstance().InKeyMgmtBitset(deviceConfig, deviceKeyMgmt)) {
49 InterScanInfo interScanInfo;
50 ConvertScanInfo(wifiScanInfo, interScanInfo);
51 interScanInfoList.push_back(interScanInfo);
52 }
53 }
54 WIFI_LOGI("select scanInfo size: %{public}zu", interScanInfoList.size());
55 NetworkSelectionResult networkSelectionResult;
56 SelectNetwork(networkSelectionResult, NetworkSelectType::USER_CONNECT, interScanInfoList);
57 autoSelectBssid = networkSelectionResult.interScanInfo.bssid;
58 }
59
ConvertScanInfo(WifiScanInfo & wifiScanInfo,InterScanInfo & interScanInfo)60 void NetworkSelectionManager::ConvertScanInfo(WifiScanInfo &wifiScanInfo, InterScanInfo &interScanInfo)
61 {
62 interScanInfo.bssid = wifiScanInfo.bssid;
63 interScanInfo.ssid = wifiScanInfo.ssid;
64 interScanInfo.oriSsid = wifiScanInfo.oriSsid;
65 interScanInfo.capabilities = wifiScanInfo.capabilities;
66 interScanInfo.frequency = wifiScanInfo.frequency;
67 interScanInfo.channelWidth = wifiScanInfo.channelWidth;
68 interScanInfo.centerFrequency0 = wifiScanInfo.centerFrequency0;
69 interScanInfo.centerFrequency1 = wifiScanInfo.centerFrequency1;
70 interScanInfo.rssi = wifiScanInfo.rssi;
71 interScanInfo.securityType = wifiScanInfo.securityType;
72 interScanInfo.infoElems = wifiScanInfo.infoElems;
73 interScanInfo.features = wifiScanInfo.features;
74 interScanInfo.timestamp = wifiScanInfo.timestamp;
75 interScanInfo.band = wifiScanInfo.band;
76 interScanInfo.isHiLinkNetwork = wifiScanInfo.isHiLinkNetwork;
77 interScanInfo.supportedWifiCategory = wifiScanInfo.supportedWifiCategory;
78 }
79
SelectNetwork(NetworkSelectionResult & networkSelectionResult,NetworkSelectType type,const std::vector<InterScanInfo> & scanInfos)80 bool NetworkSelectionManager::SelectNetwork(NetworkSelectionResult &networkSelectionResult,
81 NetworkSelectType type,
82 const std::vector<InterScanInfo> &scanInfos)
83 {
84 if (scanInfos.empty()) {
85 WIFI_LOGI("scanInfos is empty, ignore this selection");
86 return false;
87 }
88
89 /* networkCandidates must be declared before networkSelector,
90 * so it can be accessed in the destruct of networkSelector and wifiFilter */
91 std::vector<NetworkSelection::NetworkCandidate> networkCandidates;
92 auto networkSelectorOptional = pNetworkSelectorFactory->GetNetworkSelector(type);
93 if (!(networkSelectorOptional.has_value())) {
94 WIFI_LOGE("Get NetworkSelector failed for type %{public}d", static_cast<int>(type));
95 return false;
96 }
97 auto &networkSelector = networkSelectorOptional.value();
98 WIFI_LOGI("NetworkSelector: %{public}s", networkSelector->GetNetworkSelectorMsg().c_str());
99
100 /* Get the device config for each scanInfo, then create networkCandidate and put it into networkCandidates */
101 GetAllDeviceConfigs(networkCandidates, scanInfos);
102 bool isSavedNetEmpty = false;
103 std::string savedResult = GetSavedNetInfoForChr(networkCandidates, isSavedNetEmpty);
104
105 /* Traverse networkCandidates and reserve qualified networkCandidate */
106 TryNominate(networkCandidates, networkSelector);
107
108 std::string filteredReason = GetFilteredReasonForChr(networkCandidates);
109
110 /* Get best networkCandidate from the reserved networkCandidates */
111 std::vector<NetworkSelection::NetworkCandidate *> bestNetworkCandidates;
112 networkSelector->GetBestCandidates(bestNetworkCandidates);
113
114 std::string selectedInfo;
115 if (bestNetworkCandidates.empty()) {
116 if (!isSavedNetEmpty) {
117 WriteAutoSelectHiSysEvent(static_cast<int>(type), selectedInfo, filteredReason, savedResult);
118 }
119 return false;
120 } else {
121 selectedInfo = GetSelectedInfoForChr(bestNetworkCandidates.at(0));
122 WriteAutoSelectHiSysEvent(static_cast<int>(type), selectedInfo, filteredReason, savedResult);
123 }
124
125 /* Determine whether to select bestNetworkCandidates in outdoor scene */
126 IodStatisticInfo iodStatisticInfo;
127 iodStatisticInfo.outdoorAutoSelectCnt++;
128 if (IsOutdoorFilter(bestNetworkCandidates.at(0))) {
129 WIFI_LOGI("bestNetworkCandidates do not satisfy outdoor select condition");
130 iodStatisticInfo.outdoorFilterCnt++;
131 WriteIodHiSysEvent(iodStatisticInfo);
132 return false;
133 }
134 WriteIodHiSysEvent(iodStatisticInfo);
135
136 /* if bestNetworkCandidates is not empty, assign the value of first bestNetworkCandidate
137 * to the network selection result, and return true which means the network selection is successful */
138 networkSelectionResult.wifiDeviceConfig = bestNetworkCandidates.at(0)->wifiDeviceConfig;
139 networkSelectionResult.interScanInfo = bestNetworkCandidates.at(0)->interScanInfo;
140 return true;
141 }
142
GetAllDeviceConfigs(std::vector<NetworkSelection::NetworkCandidate> & networkCandidates,const std::vector<InterScanInfo> & scanInfos)143 void NetworkSelectionManager::GetAllDeviceConfigs(std::vector<NetworkSelection::NetworkCandidate> &networkCandidates,
144 const std::vector<InterScanInfo> &scanInfos)
145 {
146 std::map<int, std::size_t> wifiDeviceConfigs;
147 std::map<int, std::size_t> wifiCandidateConfigs;
148 for (auto &scanInfo : scanInfos) {
149 auto& networkCandidate = networkCandidates.emplace_back(scanInfo);
150 std::string deviceKeyMgmt;
151 scanInfo.GetDeviceMgmt(deviceKeyMgmt);
152 WifiSettings::GetInstance().GetDeviceConfig(scanInfo.ssid, deviceKeyMgmt, networkCandidate.wifiDeviceConfig);
153
154 // save the indexes of saved network candidate in networkCandidates;
155 if (networkCandidates.back().wifiDeviceConfig.networkId != INVALID_NETWORK_ID) {
156 wifiDeviceConfigs.insert({networkCandidate.wifiDeviceConfig.networkId, networkCandidates.size() - 1});
157 WifiSettings::GetInstance().SetNetworkCandidateScanResult(networkCandidate.wifiDeviceConfig.networkId);
158 continue;
159 }
160
161 // add suggesion network
162 WifiSettings::GetInstance().GetCandidateConfigWithoutUid(scanInfo.ssid, deviceKeyMgmt,
163 networkCandidate.wifiDeviceConfig);
164 if (networkCandidates.back().wifiDeviceConfig.networkId != INVALID_NETWORK_ID &&
165 networkCandidates.back().wifiDeviceConfig.uid != WIFI_INVALID_UID &&
166 networkCandidates.back().wifiDeviceConfig.isShared == false) {
167 wifiCandidateConfigs.insert({networkCandidate.wifiDeviceConfig.networkId, networkCandidates.size() - 1});
168 }
169 }
170
171 std::stringstream wifiDevicesInfo;
172 for (auto &pair: wifiDeviceConfigs) {
173 if (wifiDevicesInfo.rdbuf() ->in_avail() != 0) {
174 wifiDevicesInfo << ",";
175 }
176 wifiDevicesInfo << "\"" << pair.first << "_" <<
177 SsidAnonymize(networkCandidates.at(pair.second).wifiDeviceConfig.ssid) << "_" <<
178 networkCandidates.at(pair.second).wifiDeviceConfig.keyMgmt << "\"";
179 }
180
181 std::stringstream wifiCandidateInfos;
182 for (auto &pair: wifiCandidateConfigs) {
183 if (wifiCandidateInfos.rdbuf() ->in_avail() != 0) {
184 wifiCandidateInfos << ",";
185 }
186 wifiCandidateInfos << "\"" << pair.first << "_" <<
187 SsidAnonymize(networkCandidates.at(pair.second).wifiDeviceConfig.ssid) << "\"";
188 }
189 WIFI_LOGI("Find savedNetworks in scanInfos: [%{public}s]\n"
190 "Find suggestion networks in scanInfos: [%{public}s]",
191 wifiDevicesInfo.str().c_str(), wifiCandidateInfos.str().c_str());
192 }
193
TryNominate(std::vector<NetworkSelection::NetworkCandidate> & networkCandidates,const std::unique_ptr<NetworkSelection::INetworkSelector> & networkSelector)194 void NetworkSelectionManager::TryNominate(std::vector<NetworkSelection::NetworkCandidate> &networkCandidates,
195 const std::unique_ptr<NetworkSelection::INetworkSelector> &networkSelector)
196 {
197 std::for_each(networkCandidates.begin(), networkCandidates.end(), [&networkSelector](auto &networkCandidate) {
198 networkSelector->TryNominate(networkCandidate);
199 });
200 }
201
GetSavedNetInfoForChr(std::vector<NetworkSelection::NetworkCandidate> & networkCandidates,bool & isSavedNetEmpty)202 std::string NetworkSelectionManager::GetSavedNetInfoForChr(
203 std::vector<NetworkSelection::NetworkCandidate> &networkCandidates, bool &isSavedNetEmpty)
204 {
205 std::map<int, NetworkSelection::NetworkCandidate> savedCandidates;
206 for (size_t i = 0; i < networkCandidates.size(); i++) {
207 if (networkCandidates.at(i).wifiDeviceConfig.networkId == INVALID_NETWORK_ID) {
208 continue;
209 }
210 savedCandidates.insert({networkCandidates.at(i).wifiDeviceConfig.networkId,
211 networkCandidates.at(i)});
212 }
213 if (savedCandidates.empty()) {
214 isSavedNetEmpty = true;
215 }
216 std::string savedResult;
217 savedResult += "[";
218 for (auto pair : savedCandidates) {
219 savedResult += "[";
220 savedResult += std::to_string(pair.first);
221 savedResult += "_";
222 savedResult += SsidAnonymize(pair.second.wifiDeviceConfig.ssid);
223 savedResult += "_";
224 savedResult += pair.second.wifiDeviceConfig.keyMgmt;
225 savedResult += "]";
226 }
227 savedResult += "]";
228 return savedResult;
229 }
230
GetFilteredReasonForChr(std::vector<NetworkSelection::NetworkCandidate> & networkCandidates)231 std::string NetworkSelectionManager::GetFilteredReasonForChr(
232 std::vector<NetworkSelection::NetworkCandidate> &networkCandidates)
233 {
234 std::string filteredReasons;
235 filteredReasons += "[";
236 for (size_t i = 0; i < networkCandidates.size(); i++) {
237 if (networkCandidates.at(i).wifiDeviceConfig.networkId == INVALID_NETWORK_ID) {
238 continue;
239 }
240 std::map<std::string, std::set<NetworkSelection::FiltedReason,
241 NetworkSelection::FiltedReasonComparator, std::allocator<NetworkSelection::FiltedReason>>> filtedReason;
242 filtedReason = networkCandidates.at(i).filtedReason;
243 if (filtedReason.size() == 0) {
244 continue;
245 }
246 filteredReasons += "[";
247 for (const auto& pair : filtedReason) {
248 std::string filterName = pair.first;
249 filteredReasons += filterName;
250 filteredReasons += "_";
251 filteredReasons += networkCandidates.at(i).ToString(filterName);
252 }
253 filteredReasons += "]";
254 if (i < networkCandidates.size() - 1) {
255 filteredReasons += ", ";
256 }
257 }
258 filteredReasons += "]";
259 return filteredReasons;
260 }
261
GetSelectedInfoForChr(NetworkSelection::NetworkCandidate * networkCandidate)262 std::string NetworkSelectionManager::GetSelectedInfoForChr(NetworkSelection::NetworkCandidate *networkCandidate)
263 {
264 std::string selectedInfo;
265 WifiDeviceConfig selectedConfig;
266 selectedConfig = networkCandidate->wifiDeviceConfig;
267 selectedInfo += std::to_string(selectedConfig.networkId);
268 selectedInfo += "_";
269 selectedInfo += SsidAnonymize(selectedConfig.ssid);
270 selectedInfo += "_";
271 selectedInfo += MacAnonymize(selectedConfig.bssid);
272 selectedInfo += "_";
273 selectedInfo += selectedConfig.keyMgmt;
274 selectedInfo += "_";
275 selectedInfo += std::to_string(networkCandidate->interScanInfo.frequency);
276 selectedInfo += "_";
277 selectedInfo += std::to_string(networkCandidate->interScanInfo.rssi);
278 return selectedInfo;
279 }
280
IsOutdoorFilter(NetworkSelection::NetworkCandidate * networkCandidate)281 bool NetworkSelectionManager::IsOutdoorFilter(NetworkSelection::NetworkCandidate *networkCandidate)
282 {
283 std::lock_guard<std::mutex> lock(rssiCntMutex_);
284 if (!WifiSensorScene::GetInstance().IsOutdoorScene()) {
285 WIFI_LOGI("IsOutdoorFilter indoor scene do not filter");
286 rssiCntMap_.clear();
287 return false;
288 }
289 if ((WifiChannelHelper::GetInstance().IsValid5GHz(networkCandidate->interScanInfo.frequency) &&
290 networkCandidate->interScanInfo.rssi >= RSSI_LEVEL_4_5G) ||
291 (WifiChannelHelper::GetInstance().IsValid24GHz(networkCandidate->interScanInfo.frequency) &&
292 networkCandidate->interScanInfo.rssi >= RSSI_LEVEL_4_2G)) {
293 WIFI_LOGI("IsOutdoorFilter outdoor strong signal do not filter");
294 rssiCntMap_.clear();
295 return false;
296 }
297 if ((WifiChannelHelper::GetInstance().IsValid5GHz(networkCandidate->interScanInfo.frequency) &&
298 networkCandidate->interScanInfo.rssi < RSSI_LEVEL_3_5G) ||
299 (WifiChannelHelper::GetInstance().IsValid24GHz(networkCandidate->interScanInfo.frequency) &&
300 networkCandidate->interScanInfo.rssi < RSSI_LEVEL_3_2G)) {
301 rssiCntMap_.clear();
302 return true;
303 }
304 if (rssiCntMap_[networkCandidate->interScanInfo.bssid] < OUTDOOR_NETWORK_SELECT_THRES) {
305 rssiCntMap_[networkCandidate->interScanInfo.bssid]++;
306 int instId = 0;
307 IScanService *pScanService = WifiServiceManager::GetInstance().GetScanServiceInst(instId);
308 if (pScanService == nullptr || pScanService->ResetScanInterval() != WIFI_OPT_SUCCESS) {
309 WIFI_LOGE("IsOutdoorFilter ResetScanInterval failed");
310 rssiCntMap_.clear();
311 return false;
312 }
313 return true;
314 }
315 WIFI_LOGI("IsOutdoorFilter signal satisfy outdoor select condition");
316 rssiCntMap_.clear();
317 return false;
318 }
319 }