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 "wifi_comparator_impl.h"
18 #include "network_selection_utils.h"
19 #include "wifi_logger.h"
20 
21 namespace OHOS::Wifi::NetworkSelection {
22 DEFINE_WIFILOG_LABEL("WifiComparatorImpl")
23 
WifiScorerComparator(const std::string & comparatorName)24 WifiScorerComparator::WifiScorerComparator(const std::string &comparatorName)
25     : comparatorName(comparatorName) {}
26 
AddScorer(const std::shared_ptr<IWifiScorer> & scorer)27 void WifiScorerComparator::AddScorer(const std::shared_ptr<IWifiScorer> &scorer)
28 {
29     if (scorer) {
30         scorers.emplace_back(scorer);
31     }
32 }
33 
GetBestCandidates(const std::vector<NetworkCandidate * > & candidates,std::vector<NetworkCandidate * > & selectedCandidates)34 void WifiScorerComparator::GetBestCandidates(const std::vector<NetworkCandidate *> &candidates,
35                                              std::vector<NetworkCandidate *> &selectedCandidates)
36 {
37     /* if candidates is empty, it is unnecessary to score the candidate */
38     if (candidates.empty()) {
39         return;
40     }
41     std::vector<NetworkCandidate *> bestNetworkCandidates; //bestNetworkCandidates have founded.
42     std::vector<ScoreResult> bestNetworkScoreResults; //score records of bestNetworkCandidates.
43     bestNetworkCandidates.emplace_back(candidates.at(0)); //at first,we assume the first one is the best.
44     for (std::size_t i = 1; i < candidates.size(); ++i) {
45         bool isWorseNetworkCandidate = false;
46         auto networkCandidate = candidates.at(i);
47         for (std::size_t j = 0; j < scorers.size(); j++) {
48             auto scorer = scorers.at(j);
49             ScoreResult scoreResult;
50             if (bestNetworkScoreResults.size() <= j) {
51                 /*
52                  * if current scorer does not score best networkCandidate, we should score the bestCandidate
53                  * by current scorer at first.
54                  */
55                 bestNetworkScoreResults.emplace_back(scoreResult);
56                 scorer->DoScore(*bestNetworkCandidates.front(), bestNetworkScoreResults.at(j));
57             }
58             scorer->DoScore(*networkCandidate, scoreResult); // score current networkCandidate.
59             if (scoreResult.score > bestNetworkScoreResults.at(j).score) {
60                 /*
61                  * if the score of current networkCandidate is better than the best networkCandidate, it means we found
62                  * a better networkCandidate, then log the best networkCandidates which should be abandon. clear the
63                  * vector for best networkCandidates and score records, then continue for the next network candidate .
64                  */
65                 LogWorseSelectedCandidates(bestNetworkCandidates, *networkCandidate, bestNetworkScoreResults);
66                 bestNetworkScoreResults.erase(bestNetworkScoreResults.begin() + j, bestNetworkScoreResults.end());
67                 bestNetworkScoreResults.emplace_back(scoreResult);
68                 bestNetworkCandidates.clear();
69                 break;
70             } else if (scoreResult.score < bestNetworkScoreResults.at(j).score) {
71                 /*
72                  * if the score of current networkCandidate is worse than the best networkCandidate, log the msg of
73                  * current network candidate, and continue the next networkCandidate.
74                  */
75                 LogWorseCandidate(*networkCandidate, *bestNetworkCandidates.front(), scoreResult);
76                 isWorseNetworkCandidate = true;
77                 break;
78             }
79         }
80         if (!isWorseNetworkCandidate) {
81             /* if the current networkCandidate is not worse than the best, add it to bestNetworkCandidates. */
82             bestNetworkCandidates.emplace_back(networkCandidate);
83         }
84     }
85     LogSelectedCandidates(bestNetworkCandidates, bestNetworkScoreResults);
86     selectedCandidates.insert(selectedCandidates.end(), bestNetworkCandidates.begin(), bestNetworkCandidates.end());
87 }
88 
LogSelectedCandidates(std::vector<NetworkCandidate * > & selectedCandidates,std::vector<ScoreResult> & scoreResults)89 void WifiScorerComparator::LogSelectedCandidates(std::vector<NetworkCandidate *> &selectedCandidates,
90                                                  std::vector<ScoreResult> &scoreResults)
91 {
92     WIFI_LOGI("%{public}s get best candidates %{public}s which get scores %{public}s",
93               comparatorName.c_str(),
94               NetworkSelectionUtils::GetNetworkCandidatesInfo(selectedCandidates).c_str(),
95               NetworkSelectionUtils::GetScoreResultsInfo(scoreResults).c_str());
96 }
97 
LogWorseSelectedCandidates(std::vector<NetworkCandidate * > & worseNetworkCandidates,NetworkCandidate & betterNetworkCandidate,std::vector<ScoreResult> & scoreResults)98 void WifiScorerComparator::LogWorseSelectedCandidates(std::vector<NetworkCandidate *> &worseNetworkCandidates,
99                                                       NetworkCandidate &betterNetworkCandidate,
100                                                       std::vector<ScoreResult> &scoreResults)
101 {
102     WIFI_LOGD("%{public}s find a better candidate %{public}s, "
103               "abandon candidates %{public}s which get scores %{public}s",
104               comparatorName.c_str(),
105               betterNetworkCandidate.ToString().c_str(),
106               NetworkSelectionUtils::GetNetworkCandidatesInfo(worseNetworkCandidates).c_str(),
107               NetworkSelectionUtils::GetScoreResultsInfo(scoreResults).c_str());
108 }
109 
LogWorseCandidate(NetworkCandidate & worseNetworkCandidates,NetworkCandidate & selectedNetworkCandidate,ScoreResult & scoreResult)110 void WifiScorerComparator::LogWorseCandidate(NetworkCandidate &worseNetworkCandidates,
111                                              NetworkCandidate &selectedNetworkCandidate,
112                                              ScoreResult &scoreResult)
113 {
114     WIFI_LOGD("%{public}s find a worse candidate %{public}s which getScore %{public}s"
115               ",and current best candidate is %{public}s",
116               comparatorName.c_str(),
117               worseNetworkCandidates.ToString().c_str(),
118               scoreResult.ToString().c_str(),
119               selectedNetworkCandidate.ToString().c_str());
120 }
121 }
122 // namespace OHOS::Wifi
123