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 <iostream>
17 #include "wifi_scorer_impl.h"
18 #include "wifi_config_center.h"
19 #include "network_status_history_manager.h"
20 #include "external_wifi_common_builder_manager.h"
21 #include "wifi_logger.h"
22 
23 namespace OHOS::Wifi::NetworkSelection {
24 DEFINE_WIFILOG_LABEL("WifiScorerImpl")
25 namespace {
26 constexpr int SUFFICIENT_RSSI_5G = -70;
27 constexpr int SUFFICIENT_RSSI_2G = -73;
28 constexpr int RSSI_SCORE_OFFSET = 85;
29 constexpr int RSSI_SCORE_SLOPE_IS_4 = 4;
30 constexpr int TOP_TIME_BASE_SCORE = 1000000;
31 constexpr int MAX_RECENT_SELECTION_SECONDS = 8 * 60 * 60;
32 constexpr int MIN_5G_FREQUENCY = 5160;
33 constexpr int MAX_5G_FREQUENCY = 5865;
34 constexpr int WIFI_5G_BAND_SCORE = 50;
35 constexpr int WIFI_2G_BAND_SCORE = 20;
36 constexpr int SECURITY_BONUS_SCORE = 5;
37 constexpr int RSSI_LEVEL_FOUR_SCORE = 80;
38 constexpr int RSSI_LEVEL_THREE_SCORE = 60;
39 constexpr int RSSI_LEVEL_TWO_SCORE = 20;
40 constexpr int WIFI_DEFAULT_SCORE = -1;
41 constexpr int RSSI_LEVEL_TWO_SCORE_5G = 40;
42 constexpr int RSSI_LEVEL_TWO_SCORE_2G = 20;
43 constexpr int SIGNAL_LEVEL_TWO = 2;
44 constexpr int SIGNAL_LEVEL_THREE = 3;
45 constexpr int SIGNAL_LEVEL_FOUR = 4;
46 constexpr int MIN_RSSI = -128;
47 constexpr int INTERNET_ACCESS_AWARD = 2;
48 constexpr int EMPTY_NETWORK_STATUS_HISTORY_AWARD = 1;
49 constexpr int MAX_HISTORY_NETWORK_STATUS_NUM = 10;
50 constexpr int HISTORY_NETWORK_STATUS_WEIGHTED_SCORE[MAX_HISTORY_NETWORK_STATUS_NUM] = {
51     81920, 40960, 20480, 10240, 5120, 2560, 1280, 640, 320, 160};
52 }
53 
RssiScorer()54 RssiScorer::RssiScorer() : SimpleWifiScorer("rssiScorer") {}
55 
Score(NetworkCandidate & networkCandidate)56 double RssiScorer::Score(NetworkCandidate &networkCandidate)
57 {
58     if (networkCandidate.interScanInfo.rssi < MIN_RSSI) {
59         return MIN_RSSI;
60     } else if (networkCandidate.interScanInfo.rssi > 0) {
61         return 0;
62     }
63     return networkCandidate.interScanInfo.rssi;
64 }
65 
LastHaveInternetTimeScorer()66 LastHaveInternetTimeScorer::LastHaveInternetTimeScorer() : SimpleWifiScorer("lastHaveInternetTimeScorer") {}
67 
Score(NetworkCandidate & networkCandidate)68 double LastHaveInternetTimeScorer::Score(NetworkCandidate &networkCandidate)
69 {
70     if (networkCandidate.wifiDeviceConfig.lastHasInternetTime > 0) {
71         return static_cast<double>(networkCandidate.wifiDeviceConfig.lastHasInternetTime);
72     }
73     return 0;
74 }
75 
NetworkStatusHistoryScorer()76 NetworkStatusHistoryScorer::NetworkStatusHistoryScorer() : SimpleWifiScorer("networkStatusHistoryScorer") {}
77 
Score(NetworkCandidate & networkCandidate)78 double NetworkStatusHistoryScorer::Score(NetworkCandidate &networkCandidate)
79 {
80     auto networkStatusHistory = networkCandidate.wifiDeviceConfig.networkStatusHistory;
81     if (NetworkStatusHistoryManager::IsInternetAccessByHistory(networkStatusHistory)) {
82         return INTERNET_ACCESS_AWARD;
83     } else if (NetworkStatusHistoryManager::IsEmptyNetworkStatusHistory(networkStatusHistory)) {
84         return EMPTY_NETWORK_STATUS_HISTORY_AWARD;
85     }
86     return 0;
87 }
88 
GetRssiBaseScore(NetworkCandidate & networkCandidate)89 double ThroughputScorer::GetRssiBaseScore(NetworkCandidate &networkCandidate)
90 {
91     int rssi = networkCandidate.interScanInfo.rssi;
92     if (networkCandidate.interScanInfo.band == static_cast<int>(BandType::BAND_2GHZ)) {
93         rssi = rssi > SUFFICIENT_RSSI_2G ? SUFFICIENT_RSSI_2G : rssi;
94     } else {
95         rssi = rssi > SUFFICIENT_RSSI_5G ? SUFFICIENT_RSSI_5G : rssi;
96     }
97     return (rssi + RSSI_SCORE_OFFSET) * RSSI_SCORE_SLOPE_IS_4;
98 }
99 
GetSavedNetworkAward(NetworkCandidate & networkCandidate)100 double ThroughputScorer::GetSavedNetworkAward(NetworkCandidate &networkCandidate)
101 {
102     return networkCandidate.wifiDeviceConfig.isEphemeral ? 0 : SAVED_NETWORK_AWARD_SCORE;
103 }
104 
IsRecentUserSelected(NetworkCandidate & networkCandidate) const105 bool ThroughputScorer::IsRecentUserSelected(NetworkCandidate &networkCandidate) const
106 {
107     auto userLastSelectedNetworkId = WifiConfigCenter::GetInstance().GetUserLastSelectedNetworkId();
108     if (userLastSelectedNetworkId != INVALID_NETWORK_ID
109         && userLastSelectedNetworkId == networkCandidate.wifiDeviceConfig.networkId) {
110         time_t userLastSelectedNetworkTimeVal = WifiConfigCenter::GetInstance().GetUserLastSelectedNetworkTimeVal();
111         auto now = time(nullptr);
112         if (now < 0) {
113             WIFI_LOGW("time return invalid!\n.");
114             return false;
115         }
116         return (now - userLastSelectedNetworkTimeVal) < MAX_RECENT_SELECTION_SECONDS;
117     }
118     return false;
119 }
120 
IsSecurityNetwork(NetworkCandidate & networkCandidate) const121 bool ThroughputScorer::IsSecurityNetwork(NetworkCandidate &networkCandidate) const
122 {
123     return networkCandidate.wifiDeviceConfig.keyMgmt == KEY_MGMT_WEP
124         || networkCandidate.wifiDeviceConfig.keyMgmt == KEY_MGMT_WPA_PSK
125         || networkCandidate.wifiDeviceConfig.keyMgmt == KEY_MGMT_SAE
126         || networkCandidate.wifiDeviceConfig.keyMgmt == KEY_MGMT_EAP;
127 }
128 
DoScore(NetworkCandidate & networkCandidate,ScoreResult & scoreResult)129 void ThroughputScorer::DoScore(NetworkCandidate &networkCandidate, ScoreResult &scoreResult)
130 {
131     double rssiBaseScore = GetRssiBaseScore(networkCandidate);
132     double savedNetworkAward = GetSavedNetworkAward(networkCandidate);
133     scoreResult.scorerName = "ThroughputScorer";
134     if (IsRecentUserSelected(networkCandidate)) {
135         scoreResult.score = TOP_TIME_BASE_SCORE + rssiBaseScore + savedNetworkAward;
136         return;
137     }
138     scoreResult.score = rssiBaseScore + savedNetworkAward;
139     if (IsSecurityNetwork(networkCandidate)) {
140         scoreResult.score += SECURITY_AWARD_SCORE;
141     }
142 }
143 
SecurityBonusScorer()144 SecurityBonusScorer::SecurityBonusScorer() : SimpleWifiScorer("securityScore") {}
145 
IsHigherSecurityTypeFromScanResult(const InterScanInfo & interScanInfo)146 bool SecurityBonusScorer::IsHigherSecurityTypeFromScanResult(const InterScanInfo &interScanInfo)
147 {
148     return IsEncryptionSae(interScanInfo) || IsEncryptionPskSaeTransition(interScanInfo)
149         || IsEncryptionOwe(interScanInfo) || IsEncryptionOweTransition(interScanInfo)
150         || IsWpa3EnterpriseOnlyNetwork(interScanInfo) || IsWpa3EnterpriseTransitionNetwork(interScanInfo);
151 }
152 
IsEncryptionSae(const InterScanInfo & interScanInfo)153 bool SecurityBonusScorer::IsEncryptionSae(const InterScanInfo &interScanInfo)
154 {
155     return ExistSecurityType(interScanInfo, "SAE");
156 }
157 
IsEncryptionPskSaeTransition(const InterScanInfo & interScanInfo)158 bool SecurityBonusScorer::IsEncryptionPskSaeTransition(const InterScanInfo &interScanInfo)
159 {
160     return ExistSecurityType(interScanInfo, "PSK") && ExistSecurityType(interScanInfo, "SAE");
161 }
162 
IsEncryptionOwe(const InterScanInfo & interScanInfo)163 bool SecurityBonusScorer::IsEncryptionOwe(const InterScanInfo &interScanInfo)
164 {
165     return ExistSecurityType(interScanInfo, "OWE");
166 }
167 
IsEncryptionOweTransition(const InterScanInfo & interScanInfo)168 bool SecurityBonusScorer::IsEncryptionOweTransition(const InterScanInfo &interScanInfo)
169 {
170     return ExistSecurityType(interScanInfo, "OWE_TRANSITION");
171 }
172 
IsWpa3EnterpriseOnlyNetwork(const InterScanInfo & interScanInfo)173 bool SecurityBonusScorer::IsWpa3EnterpriseOnlyNetwork(const InterScanInfo &interScanInfo)
174 {
175     return ExistSecurityType(interScanInfo, "EAP/SHA256") && !ExistSecurityType(interScanInfo, "EAP/SHA1")
176         && ExistSecurityType(interScanInfo, "RSN") && !ExistSecurityType(interScanInfo, "WEP")
177         && !ExistSecurityType(interScanInfo, "TKIP")
178         && (ExistSecurityType(interScanInfo, "[MFPR]") || ExistSecurityType(interScanInfo, "[PMFR]"))
179         && (ExistSecurityType(interScanInfo, "[MFPC]") || ExistSecurityType(interScanInfo, "[PMFC]"));
180 }
181 
IsWpa3EnterpriseTransitionNetwork(const InterScanInfo & interScanInfo)182 bool SecurityBonusScorer::IsWpa3EnterpriseTransitionNetwork(const InterScanInfo &interScanInfo)
183 {
184     return ExistSecurityType(interScanInfo, "EAP/SHA1") && ExistSecurityType(interScanInfo, "EAP/SHA256")
185         && ExistSecurityType(interScanInfo, "RSN") && !ExistSecurityType(interScanInfo, "WEP")
186         && !ExistSecurityType(interScanInfo, "TKIP")
187         && !(ExistSecurityType(interScanInfo, "[MFPR]") || ExistSecurityType(interScanInfo, "[PMFR]"))
188         && (ExistSecurityType(interScanInfo, "[MFPC]") || ExistSecurityType(interScanInfo, "[PMFC]"));
189 }
190 
ExistSecurityType(const InterScanInfo & interScanInfo,const std::string & securityType)191 bool SecurityBonusScorer::ExistSecurityType(const InterScanInfo &interScanInfo, const std::string &securityType)
192 {
193     return interScanInfo.capabilities.find(securityType) != std::string::npos;
194 }
195 
Score(NetworkCandidate & networkCandidate)196 double SecurityBonusScorer::Score(NetworkCandidate &networkCandidate)
197 {
198     return IsHigherSecurityTypeFromScanResult(networkCandidate.interScanInfo) ? SECURITY_BONUS_SCORE : 0;
199 }
200 
RssiLevelBonusScorer()201 RssiLevelBonusScorer::RssiLevelBonusScorer() : SimpleWifiScorer("rssiLevelScore") {}
202 
Score(NetworkCandidate & networkCandidate)203 double RssiLevelBonusScorer::Score(NetworkCandidate &networkCandidate)
204 {
205     auto &scanInfo = networkCandidate.interScanInfo;
206     int frequency = networkCandidate.interScanInfo.frequency;
207     int currentSignalLevel = WifiSettings::GetInstance().GetSignalLevel(scanInfo.rssi, scanInfo.band);
208     if (currentSignalLevel == SIGNAL_LEVEL_FOUR) {
209         return RSSI_LEVEL_FOUR_SCORE;
210     }
211     if (currentSignalLevel == SIGNAL_LEVEL_THREE) {
212         return RSSI_LEVEL_THREE_SCORE;
213     }
214     if (currentSignalLevel == SIGNAL_LEVEL_TWO) {
215         if (frequency >= MIN_5G_FREQUENCY && frequency <= MAX_5G_FREQUENCY) {
216             return RSSI_LEVEL_TWO_SCORE_5G;
217         } else {
218             return RSSI_LEVEL_TWO_SCORE_2G;
219         }
220     }
221     return 0;
222 }
223 
SignalLevelScorer()224 SignalLevelScorer::SignalLevelScorer() : SimpleWifiScorer("SignalLevelScorer") {}
225 
Score(NetworkCandidate & networkCandidate)226 double SignalLevelScorer::Score(NetworkCandidate &networkCandidate)
227 {
228     auto &scanInfo = networkCandidate.interScanInfo;
229     int signalLevel = WifiSettings::GetInstance().GetSignalLevel(scanInfo.rssi, scanInfo.band);
230     int32_t levelScore = 0;
231     switch (signalLevel) {
232         case SIGNAL_LEVEL_FOUR:
233             levelScore = RSSI_LEVEL_FOUR_SCORE;
234             break;
235         case SIGNAL_LEVEL_THREE:
236             levelScore = RSSI_LEVEL_THREE_SCORE;
237             break;
238         case SIGNAL_LEVEL_TWO:
239             levelScore = RSSI_LEVEL_TWO_SCORE;
240             break;
241         default:
242             levelScore = WIFI_DEFAULT_SCORE;
243             break;
244     }
245 
246     return levelScore;
247 }
248 
Network5gBonusScorer()249 Network5gBonusScorer::Network5gBonusScorer() : SimpleWifiScorer("5gBonusScore") {}
250 
Score(NetworkCandidate & networkCandidate)251 double Network5gBonusScorer::Score(NetworkCandidate &networkCandidate)
252 {
253     int frequency = networkCandidate.interScanInfo.frequency;
254     return frequency >= MIN_5G_FREQUENCY && frequency <= MAX_5G_FREQUENCY ? WIFI_5G_BAND_SCORE : WIFI_2G_BAND_SCORE;
255 }
256 
SavedNetworkScorer(const std::string & scorerName)257 SavedNetworkScorer::SavedNetworkScorer(const std::string &scorerName) : CompositeWifiScorer(scorerName)
258 {
259     AddScorer(std::make_shared<RssiLevelBonusScorer>());
260     AddScorer(std::make_shared<SecurityBonusScorer>());
261     AddScorer(std::make_shared<Network5gBonusScorer>());
262     ExternalWifiCommonBuildManager::GetInstance().BuildScore(
263         TagType::HAS_INTERNET_NETWORK_SELECTOR_SCORE_WIFI_CATEGORY_TAG, *this);
264 }
265 
NoInternetNetworkStatusHistoryScorer()266 NoInternetNetworkStatusHistoryScorer::NoInternetNetworkStatusHistoryScorer()
267     : SimpleWifiScorer("NoInternetNetworkStatusHistoryScorer") {}
268 
Score(NetworkCandidate & networkCandidate)269 double NoInternetNetworkStatusHistoryScorer::Score(NetworkCandidate &networkCandidate)
270 {
271     double score = 0;
272     std::vector<int> vNetworkStatusHistory{};
273     vNetworkStatusHistory = NetworkStatusHistoryManager::GetCurrentNetworkStatusHistory2Array(
274         networkCandidate.wifiDeviceConfig.networkStatusHistory);
275 
276     int nSize = (int)vNetworkStatusHistory.size();
277     for (int i = 0; i < nSize; i++) {
278         if (i >= MAX_HISTORY_NETWORK_STATUS_NUM) {
279             break;
280         }
281         score += HISTORY_NETWORK_STATUS_WEIGHTED_SCORE[i] * vNetworkStatusHistory[i];
282     }
283     return score;
284 }
285 
ApQualityScorer(const std::string & scorerName)286 ApQualityScorer::ApQualityScorer(const std::string &scorerName) : CompositeWifiScorer(scorerName)
287 {
288     AddScorer(std::make_shared<SignalLevelScorer>());
289     AddScorer(std::make_shared<Network5gBonusScorer>());
290     ExternalWifiCommonBuildManager::GetInstance().BuildScore(
291         TagType::HAS_INTERNET_NETWORK_SELECTOR_SCORE_WIFI_CATEGORY_TAG, *this);
292     AddScorer(std::make_shared<SecurityBonusScorer>());
293 }
294 }
295