WifiAutoJoinController.java revision 2451dbcc4f9641df188326215b204b798eb70c46
1f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle/*
262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle * Copyright (C) 2014 The Android Open Source Project
3f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
4f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * Licensed under the Apache License, Version 2.0 (the "License");
5f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * you may not use this file except in compliance with the License.
6f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * You may obtain a copy of the License at
7f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
8f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *      http://www.apache.org/licenses/LICENSE-2.0
9f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
10f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * Unless required by applicable law or agreed to in writing, software
11f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * distributed under the License is distributed on an "AS IS" BASIS,
12f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * See the License for the specific language governing permissions and
14f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * limitations under the License.
15f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle */
16f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
17f22d23092ab37286a5ef9d257d5bb32c421d2669vandwallepackage com.android.server.wifi;
18f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
19f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.content.Context;
20f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
21f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.NetworkKey;
22f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.NetworkScoreManager;
230c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalleimport android.net.WifiKey;
24f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.wifi.WifiConfiguration;
25f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.wifi.ScanResult;
26f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.wifi.WifiManager;
27f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
28f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.os.SystemClock;
29b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalleimport android.os.Process;
30f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.util.Log;
31f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
320c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalleimport java.util.ArrayList;
33f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.Iterator;
34f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.HashMap;
35f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.List;
36f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
37f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle/**
38f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * AutoJoin controller is responsible for WiFi Connect decision
39f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
40f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * It runs in the thread context of WifiStateMachine
41f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
42f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle */
43f22d23092ab37286a5ef9d257d5bb32c421d2669vandwallepublic class WifiAutoJoinController {
44f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
45f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private Context mContext;
46f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiStateMachine mWifiStateMachine;
47f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiConfigStore mWifiConfigStore;
48f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNative mWifiNative;
49f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
50f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private NetworkScoreManager scoreManager;
51f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNetworkScoreCache mNetworkScoreCache;
52f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
53f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final String TAG = "WifiAutoJoinController ";
54ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    private static boolean DBG = false;
55ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    private static boolean VDBG = false;
56f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final boolean mStaStaSupported = false;
57f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final int SCAN_RESULT_CACHE_SIZE = 80;
58f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
59453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle    private String mCurrentConfigurationKey = null; //used by autojoin
60f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
61f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private HashMap<String, ScanResult> scanResultCache =
62f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            new HashMap<String, ScanResult>();
63f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
64931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Lose the non-auth failure blacklisting after 8 hours
654dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    private final static long loseBlackListHardMilli = 1000 * 60 * 60 * 8;
66931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Lose some temporary blacklisting after 30 minutes
674dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    private final static long loseBlackListSoftMilli = 1000 * 60 * 30;
6827355a942653264388e909a4276196ee63e57811vandwalle
69b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_IDLE = 0;
70b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_ROAMING = 1;
71b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_EXTENDED_ROAMING = 2;
72b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_OUT_OF_NETWORK_ROAMING = 3;
73b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
74f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    WifiAutoJoinController(Context c, WifiStateMachine w, WifiConfigStore s,
75f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                           WifiTrafficPoller t, WifiNative n) {
76f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mContext = c;
77f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiStateMachine = w;
78f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore = s;
79f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiNative = n;
80f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mNetworkScoreCache = null;
8121bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle        scoreManager =
8221bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                (NetworkScoreManager) mContext.getSystemService(Context.NETWORK_SCORE_SERVICE);
83f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager == null)
84f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("Registered scoreManager NULL " + " service " + Context.NETWORK_SCORE_SERVICE);
85f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
86f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager != null) {
87f13817203179f41620514718c8668ae7e418f8afJeff Davidson            mNetworkScoreCache = new WifiNetworkScoreCache(mContext);
88f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            scoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
89f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        } else {
90f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("No network score service: Couldnt register as a WiFi score Manager, type="
91f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.toString(NetworkKey.TYPE_WIFI)
92f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + " service " + Context.NETWORK_SCORE_SERVICE);
93f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            mNetworkScoreCache = null;
94f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
95f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
96f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
97ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    void enableVerboseLogging(int verbose) {
98ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        if (verbose > 0 ) {
99abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = true;
100ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = true;
101ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        } else {
102abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = false;
103ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = false;
104ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
105ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    }
106ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle
10721bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle    int mScanResultMaximumAge = 30000; /* milliseconds unit */
108f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
109931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
110931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * Flush out scan results older than mScanResultMaximumAge
111ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     *
112931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
113f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private void ageScanResultsOut(int delay) {
114f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (delay <= 0) {
115931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            delay = mScanResultMaximumAge; // Something sane
116f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
117b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        long milli = System.currentTimeMillis();
118f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG) {
119f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("ageScanResultsOut delay " + Integer.valueOf(delay) + " size "
120f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.valueOf(scanResultCache.size()) + " now " + Long.valueOf(milli));
121f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
122f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
123f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        Iterator<HashMap.Entry<String,ScanResult>> iter = scanResultCache.entrySet().iterator();
124f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        while (iter.hasNext()) {
125f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            HashMap.Entry<String,ScanResult> entry = iter.next();
126f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            ScanResult result = entry.getValue();
127f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
128f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if ((result.seen + delay) < milli) {
129f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                iter.remove();
130f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
131f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
132f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
133f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
134f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void addToScanCache(List<ScanResult> scanList) {
135f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration associatedConfig;
136f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1370c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        ArrayList<NetworkKey> unknownScanResults = new ArrayList<NetworkKey>();
1380c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
139f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for(ScanResult result: scanList) {
1401fcf3c6d2b9ed65573e1e7c55fc5a30ebd364c4fYuhao Zheng            if (result.SSID == null) continue;
141f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            result.seen = System.currentTimeMillis();
142f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
143f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            ScanResult sr = scanResultCache.get(result.BSSID);
144f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (sr != null) {
145931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // If there was a previous cache result for this BSSID, average the RSSI values
146f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
147f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                int previous_rssi = sr.level;
148f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                long previously_seen_milli = sr.seen;
149f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
150931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Average RSSI with previously seen instances of this scan result
151f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                int avg_rssi = result.level;
152f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
153f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if ((previously_seen_milli > 0)
154f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        && (previously_seen_milli < mScanResultMaximumAge/2)) {
155f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    /*
156f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    *
157f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    * previously_seen_milli = 0 => RSSI = 0.5 * previous_seen_rssi + 0.5 * new_rssi
158f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    *
159f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    * If previously_seen_milli is 15+ seconds old:
160f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    *      previously_seen_milli = 15000 => RSSI = new_rssi
161f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    *
162f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    */
163f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
164f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    double alpha = 0.5 - (double)previously_seen_milli
165f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            / (double)mScanResultMaximumAge;
166f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
167f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    avg_rssi = (int)((double)avg_rssi * (1-alpha) + (double)previous_rssi * alpha);
168f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
169f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                result.level = avg_rssi;
170f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
171931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Remove the previous Scan Result
172f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                scanResultCache.remove(result.BSSID);
1730c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            } else {
1740c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                if (!mNetworkScoreCache.isScoredNetwork(result)) {
17521bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    WifiKey wkey;
176931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // Quoted SSIDs are the only one valid at this stage
17721bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    try {
17821bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        wkey = new WifiKey("\"" + result.SSID + "\"", result.BSSID);
17921bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    } catch (IllegalArgumentException e) {
18021bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        logDbg("AutoJoinController: received badly encoded SSID=[" + result.SSID +
18121bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                                "] ->skipping this network");
18221bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        wkey = null;
18321bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    }
18421bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    if (wkey != null) {
18521bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        NetworkKey nkey = new NetworkKey(wkey);
1862451dbcc4f9641df188326215b204b798eb70c46vandwalle                        //if we don't know this scan result then request a score from the scorer
18721bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                        unknownScanResults.add(nkey);
18821bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    }
1890c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                }
190f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
191f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
192f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            scanResultCache.put(result.BSSID, new ScanResult(result));
193f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
194931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Add this BSSID to the scanResultCache of the relevant WifiConfiguration
195f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            associatedConfig = mWifiConfigStore.updateSavedNetworkHistory(result);
196f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
197931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Try to associate this BSSID to an existing Saved WifiConfiguration
198f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (associatedConfig == null) {
199f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                associatedConfig = mWifiConfigStore.associateWithConfiguration(result);
2001fcf3c6d2b9ed65573e1e7c55fc5a30ebd364c4fYuhao Zheng                if (associatedConfig != null && associatedConfig.SSID != null) {
201f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (VDBG) {
202f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        logDbg("addToScanCache save associated config "
203f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                + associatedConfig.SSID + " with " + associatedConfig.SSID);
204f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
205f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    mWifiStateMachine.sendMessage(WifiManager.SAVE_NETWORK, associatedConfig);
206f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
207f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
208f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
2090c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
2100c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        if (unknownScanResults.size() != 0) {
2110c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            NetworkKey[] newKeys =
2120c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                    unknownScanResults.toArray(new NetworkKey[unknownScanResults.size()]);
213931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Kick the score manager, we will get updated scores asynchronously
2140c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            scoreManager.requestScores(newKeys);
2150c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        }
216f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
217f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
218f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void logDbg(String message) {
2190888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle        logDbg(message, false);
220ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    }
221ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
222ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    void logDbg(String message, boolean stackTrace) {
223f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        long now = SystemClock.elapsedRealtimeNanos();
2240888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle        String ts = String.format("[%,d us] ", now / 1000);
225ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (stackTrace) {
226ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            Log.e(TAG, ts + message + " stack:"
227ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[2].getMethodName() + " - "
228ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[3].getMethodName() + " - "
229ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[4].getMethodName() + " - "
230ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[5].getMethodName());
231ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        } else {
232ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            Log.e(TAG, ts + message);
233ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        }
234f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
235f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
236931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Called directly from WifiStateMachine
237f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void newSupplicantResults() {
238f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        List<ScanResult> scanList = mWifiStateMachine.syncGetScanResultsList();
239f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        addToScanCache(scanList);
240f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(mScanResultMaximumAge);
241f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (DBG)
242f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle           logDbg("newSupplicantResults size=" + Integer.valueOf(scanResultCache.size()) );
243f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
244f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
245f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore.writeKnownNetworkHistory();
246f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
247f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
248f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
249f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
250931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
251931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * Not used at the moment
252f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * should be a call back from WifiScanner HAL ??
253f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * this function is not hooked and working yet, it will receive scan results from WifiScanners
254f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * with the list of IEs,then populate the capabilities by parsing the IEs and inject the scan
255f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * results as normal.
256f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     */
257f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void newHalScanResults() {
258f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        List<ScanResult> scanList = null;//mWifiScanner.syncGetScanResultsList();
259f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String akm = WifiParser.parse_akm(null, null);
260f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        logDbg(akm);
261f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        addToScanCache(scanList);
262f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(0);
263f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
264f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore.writeKnownNetworkHistory();
265f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
266f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
267931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
268931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     *  network link quality changed, called directly from WifiTrafficPoller,
269931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * or by listening to Link Quality intent
270931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
271f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void linkQualitySignificantChange() {
272f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
273f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
274f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
275931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
276f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * compare a WifiConfiguration against the current network, return a delta score
277f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * If not associated, and the candidate will always be better
278f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * For instance if the candidate is a home network versus an unknown public wifi,
279f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * the delta will be infinite, else compare Kepler scores etc…
280b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle     * Negatve return values from this functions are meaningless per se, just trying to
281b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle     * keep them distinct for debug purpose (i.e. -1, -2 etc...)
282931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
283f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private int compareNetwork(WifiConfiguration candidate) {
284b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (candidate == null)
285b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            return -3;
286b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
287f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration currentNetwork = mWifiStateMachine.getCurrentWifiConfiguration();
288b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (currentNetwork == null) {
289b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle           return 1000;
290b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        }
291f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
292f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (candidate.configKey(true).equals(currentNetwork.configKey(true))) {
293b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            return -2;
294f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
295f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
296f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = compareWifiConfigurations(currentNetwork, candidate);
297f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
298f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (order > 0) {
299f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            //ascending: currentNetwork < candidate
300f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return 10; //will try switch over to the candidate
301f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
302f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
303f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return 0;
304f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
305f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
306ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    /**
307ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * update the network history fields fo that configuration
308ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if userTriggered, we mark the configuration as "non selfAdded" since the user has seen it
309ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * and took over management
310ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if it is a "connect", remember which network were there at the point of the connect, so
311ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * as those networks get a relative lower score than the selected configuration
31262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle     *
313ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param netId
314ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param userTriggered : if the update come from WiFiManager
315ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param connect : if the update includes a connect
316931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
31762f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle    public void updateConfigurationHistory(int netId, boolean userTriggered, boolean connect) {
318f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration selected = mWifiConfigStore.getWifiConfiguration(netId);
319f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (selected == null) {
320f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return;
321f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
322f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
323e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        if (selected.SSID == null) {
324e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            return;
325e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        }
326e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
32762f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        if (userTriggered) {
328931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Reenable autojoin for this network,
32962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            // since the user want to connect to this configuration
33027355a942653264388e909a4276196ee63e57811vandwalle            selected.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
33162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            selected.selfAdded = false;
33262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        }
333f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
334992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (DBG && userTriggered) {
335f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (selected.connectChoices != null) {
336ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
337f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        + Integer.toString(netId) + " now: "
338992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(selected.connectChoices.size())
339992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
340f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
341ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
342992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(netId)
343992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
344f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
345f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
346f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
347ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (connect && userTriggered) {
348ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            boolean found = false;
3492451dbcc4f9641df188326215b204b798eb70c46vandwalle            int choice = 0;
35062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            List<WifiConfiguration> networks =
35162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    mWifiConfigStore.getRecentConfiguredNetworks(12000, false);
35262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            if (networks != null) {
35362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                for (WifiConfiguration config : networks) {
354992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    if (DBG) {
355992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        logDbg("updateConfigurationHistory got " + config.SSID + " nid="
356992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                                + Integer.toString(config.networkId));
357992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    }
358f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
35962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (selected.configKey(true).equals(config.configKey(true))) {
360ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        found = true;
36162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        continue;
36262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
363f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
3642451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // Compare RSSI values so as to evaluate the strength of the user preference
3652451dbcc4f9641df188326215b204b798eb70c46vandwalle                    int order = compareWifiConfigurationsRSSI(config, selected, null);
3662451dbcc4f9641df188326215b204b798eb70c46vandwalle
3672451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (order < -30) {
3682451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Selected configuration is worse than the visible configuration
3692451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // hence register a strong choice so as autojoin cannot override this
3702451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // for instance, the user has select a network
3712451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // with 1 bar over a network with 3 bars...
3722451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 60;
3732451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else if (order < -20) {
3742451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 50;
3752451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else if (order < -10) {
3762451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 40;
3772451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else if (order < 10) {
3782451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Selected configuration is about same or has a slightly better RSSI
3792451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // hence register a weaker choice, here a difference of at least +/-30 in
3802451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // RSSI comparison triggered by autoJoin will override the choice
3812451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 30;
3822451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else if (order <= 30) {
3832451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Selected configuration is better than the visible configuration
3842451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // hence we do not know if the user prefers this configuration strongly
3852451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 20;
3862451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else {
3872451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 10;
38862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
389f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
390931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // The selected configuration was preferred over a recently seen config
391931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // hence remember the user's choice:
392931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // add the recently seen config to the selected's connectChoices array
393ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
394ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    if (selected.connectChoices == null) {
395ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        selected.connectChoices = new HashMap<String, Integer>();
396ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    }
397ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
398ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    logDbg("updateConfigurationHistory add a choice " + selected.configKey(true)
3990888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                            + " over " + config.configKey(true)
4002451dbcc4f9641df188326215b204b798eb70c46vandwalle                            + " choice " + Integer.toString(choice));
401cf5b8eb8a08c45bd4a82f1f4bb789c8a1b08744fvandwalle
4022451dbcc4f9641df188326215b204b798eb70c46vandwalle                    Integer currentChoice = selected.connectChoices.get(config.configKey(true));
4032451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (currentChoice == null || currentChoice.intValue() < choice) {
4042451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Add the visible config to the selected's connect choice list
4052451dbcc4f9641df188326215b204b798eb70c46vandwalle                        selected.connectChoices.put(config.configKey(true), choice);
4062451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
407f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
40862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (config.connectChoices != null) {
409ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        if (VDBG) {
410ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                            logDbg("updateConfigurationHistory will remove "
41162f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                    + selected.configKey(true) + " from " + config.configKey(true));
412ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        }
413931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Remove the selected from the recently seen config's connectChoice list
41462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        config.connectChoices.remove(selected.configKey(true));
4150888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle
4160888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        if (selected.linkedConfigurations != null) {
417931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                           // Remove the selected's linked configuration from the
418931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                           // recently seen config's connectChoice list
4190888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           for (String key : selected.linkedConfigurations.keySet()) {
4200888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                               config.connectChoices.remove(key);
4210888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           }
4220888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        }
42362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
424ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                }
425ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                if (found == false) {
4262451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // We haven't found the configuration that the user just selected in our
4272451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // scan cache.
4282451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // In that case we will need a new scan before attempting to connect to this
4292451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // configuration anyhow and thus we can process the scan results then.
430ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                     logDbg("updateConfigurationHistory try to connect to an old network!! : "
431ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                             + selected.configKey());
43262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
433f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
43462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                if (selected.connectChoices != null) {
43562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (VDBG)
436ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        logDbg("updateConfigurationHistory " + Integer.toString(netId)
43762f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                + " now: " + Integer.toString(selected.connectChoices.size()));
43862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
439f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
440f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
441992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle
442931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // TODO: write only if something changed
443992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (userTriggered || connect) {
444992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle            mWifiConfigStore.writeKnownNetworkHistory();
445992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        }
446f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
447f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
4482451dbcc4f9641df188326215b204b798eb70c46vandwalle    int getConnectChoice(WifiConfiguration source, WifiConfiguration target) {
4492451dbcc4f9641df188326215b204b798eb70c46vandwalle        Integer choice = null;
4502451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (source == null || target == null) {
4512451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
452f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
453f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
4542451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (source.connectChoices != null
4552451dbcc4f9641df188326215b204b798eb70c46vandwalle                && source.connectChoices.containsKey(target.configKey(true))) {
4562451dbcc4f9641df188326215b204b798eb70c46vandwalle            choice = source.connectChoices.get(target.configKey(true));
4572451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else if (source.linkedConfigurations != null) {
458f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            for (String key : source.linkedConfigurations.keySet()) {
459f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(key);
460f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (config != null) {
461f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (config.connectChoices != null) {
4622451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = config.connectChoices.get(target.configKey(true));
463f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
464f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
465f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
4662451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
4672451dbcc4f9641df188326215b204b798eb70c46vandwalle
4682451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (choice == null) {
4692451dbcc4f9641df188326215b204b798eb70c46vandwalle            //We didn't find the connect choice
4702451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
4712451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else {
4722451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice.intValue() < 0) {
4732451dbcc4f9641df188326215b204b798eb70c46vandwalle                choice = 20; // Compatibility with older files
4742451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
4752451dbcc4f9641df188326215b204b798eb70c46vandwalle            return choice.intValue();
4762451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
4772451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
4782451dbcc4f9641df188326215b204b798eb70c46vandwalle
4792451dbcc4f9641df188326215b204b798eb70c46vandwalle
4802451dbcc4f9641df188326215b204b798eb70c46vandwalle    int getScoreFromVisibility(WifiConfiguration.Visibility visibility, int rssiBoost) {
4812451dbcc4f9641df188326215b204b798eb70c46vandwalle        int rssiBoost5 = 0;
4822451dbcc4f9641df188326215b204b798eb70c46vandwalle        int score = 0;
4834dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
4842451dbcc4f9641df188326215b204b798eb70c46vandwalle        /**
4852451dbcc4f9641df188326215b204b798eb70c46vandwalle         * Boost RSSI value of 5GHz bands iff the base value is better than threshold
4862451dbcc4f9641df188326215b204b798eb70c46vandwalle         * This implements band preference where we prefer 5GHz if RSSI5 is good enough, whereas
4872451dbcc4f9641df188326215b204b798eb70c46vandwalle         * we prefer 2.4GHz otherwise.
4882451dbcc4f9641df188326215b204b798eb70c46vandwalle         * Note that 2.4GHz doesn't need a boost since at equal power the RSSI is typically
4892451dbcc4f9641df188326215b204b798eb70c46vandwalle         * 6-10 dB higher
4902451dbcc4f9641df188326215b204b798eb70c46vandwalle         */
4912451dbcc4f9641df188326215b204b798eb70c46vandwalle        if ((visibility.rssi5 + rssiBoost) > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD) {
4922451dbcc4f9641df188326215b204b798eb70c46vandwalle            rssiBoost5 = 25;
4932451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else if ((visibility.rssi5 + rssiBoost)
4942451dbcc4f9641df188326215b204b798eb70c46vandwalle                > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD_LOW) {
4952451dbcc4f9641df188326215b204b798eb70c46vandwalle            rssiBoost5 = 15;
4962451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
4972451dbcc4f9641df188326215b204b798eb70c46vandwalle
4982451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Select which band to use so as to score a
4992451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (visibility.rssi5 + rssiBoost5 > visibility.rssi24) {
5002451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Prefer a's 5GHz
5012451dbcc4f9641df188326215b204b798eb70c46vandwalle            score = visibility.rssi5 + rssiBoost5 + rssiBoost;
5022451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else {
5032451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Prefer a's 2.4GHz
5042451dbcc4f9641df188326215b204b798eb70c46vandwalle            score = visibility.rssi24 + rssiBoost;
505f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
5062451dbcc4f9641df188326215b204b798eb70c46vandwalle
5072451dbcc4f9641df188326215b204b798eb70c46vandwalle        return score;
508f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
509f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
5102451dbcc4f9641df188326215b204b798eb70c46vandwalle    // Compare WifiConfiguration by RSSI, and return a comparison value in the range [-50, +50]
5112451dbcc4f9641df188326215b204b798eb70c46vandwalle    // The result represents "approximately" an RSSI difference measured in dBM
5122451dbcc4f9641df188326215b204b798eb70c46vandwalle    // Adjusted with various parameters:
5132451dbcc4f9641df188326215b204b798eb70c46vandwalle    // +) current network gets a +15 boost
5142451dbcc4f9641df188326215b204b798eb70c46vandwalle    // +) 5GHz signal, if they are strong enough, get a +15 or +25 boost, representing the
5152451dbcc4f9641df188326215b204b798eb70c46vandwalle    // fact that at short range we prefer 5GHz band as it is cleaner of interference and
5162451dbcc4f9641df188326215b204b798eb70c46vandwalle    // provides for wider channels
5172451dbcc4f9641df188326215b204b798eb70c46vandwalle    int compareWifiConfigurationsRSSI(WifiConfiguration a, WifiConfiguration b,
5182451dbcc4f9641df188326215b204b798eb70c46vandwalle                                      String currentConfiguration) {
519f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
5202451dbcc4f9641df188326215b204b798eb70c46vandwalle
5212451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Boost used so as to favor current config
5222451dbcc4f9641df188326215b204b798eb70c46vandwalle        int aRssiBoost = 0;
5232451dbcc4f9641df188326215b204b798eb70c46vandwalle        int bRssiBoost = 0;
5242451dbcc4f9641df188326215b204b798eb70c46vandwalle
5252451dbcc4f9641df188326215b204b798eb70c46vandwalle        int scoreA;
5262451dbcc4f9641df188326215b204b798eb70c46vandwalle        int scoreB;
5272451dbcc4f9641df188326215b204b798eb70c46vandwalle
5282451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Retrieve the visibility
529f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility astatus = a.visibility;
530f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility bstatus = b.visibility;
531f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (astatus == null || bstatus == null) {
5322451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Error visibility wasn't set
533f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("compareWifiConfigurations NULL band status!");
534f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return 0;
535f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
5362451dbcc4f9641df188326215b204b798eb70c46vandwalle
5372451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply Hysteresis, boost RSSI of current configuration
5382451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (null != currentConfiguration) {
5392451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (a.configKey().equals(currentConfiguration)) {
5402451dbcc4f9641df188326215b204b798eb70c46vandwalle                aRssiBoost += 15;
5412451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (b.configKey().equals(currentConfiguration)) {
5422451dbcc4f9641df188326215b204b798eb70c46vandwalle                bRssiBoost += 15;
5432451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
5442451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
5452451dbcc4f9641df188326215b204b798eb70c46vandwalle
5462451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG)  {
5472451dbcc4f9641df188326215b204b798eb70c46vandwalle            logDbg("compareWifiConfigurationsRSSI: " + a.configKey()
5482451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " " + Integer.toString(astatus.rssi5)
5492451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + Integer.toString(astatus.rssi24) + "   "
5502451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " boost=" + Integer.toString(aRssiBoost)
5512451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + b.configKey() + " "
5522451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + Integer.toString(bstatus.rssi5) + ","
5532451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + Integer.toString(bstatus.rssi24)
5542451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " boost=" + Integer.toString(bRssiBoost)
5552451dbcc4f9641df188326215b204b798eb70c46vandwalle            );
556f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
5572451dbcc4f9641df188326215b204b798eb70c46vandwalle
5582451dbcc4f9641df188326215b204b798eb70c46vandwalle        scoreA = getScoreFromVisibility(astatus, aRssiBoost);
5592451dbcc4f9641df188326215b204b798eb70c46vandwalle        scoreB = getScoreFromVisibility(bstatus, bRssiBoost);
5602451dbcc4f9641df188326215b204b798eb70c46vandwalle
5612451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Compare a and b
5622451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If a score is higher then a > b and the order is descending (negative)
5632451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If b score is higher then a < b and the order is ascending (positive)
5642451dbcc4f9641df188326215b204b798eb70c46vandwalle        order = scoreB - scoreA;
5652451dbcc4f9641df188326215b204b798eb70c46vandwalle
5662451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Normalize the order to [-50, +50]
5672451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (order > 50) order = 50;
5682451dbcc4f9641df188326215b204b798eb70c46vandwalle        else if (order < -50) order = -50;
5692451dbcc4f9641df188326215b204b798eb70c46vandwalle
5702451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
5712451dbcc4f9641df188326215b204b798eb70c46vandwalle            String prefer = " = ";
5722451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (order > 0) {
5732451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " < "; // Ascending
5742451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (order < 0) {
5752451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " > "; // Descending
5762451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
5772451dbcc4f9641df188326215b204b798eb70c46vandwalle            logDbg("compareWifiConfigurationsRSSI " + a.configKey()
5782451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + a.visibility.rssi24
5792451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.rssi5
5802451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + a.visibility.num24
5812451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.num5 + ")"
5822451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + prefer + b.configKey()
5832451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + b.visibility.rssi24
5842451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.rssi5
5852451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + b.visibility.num24
5862451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.num5 + ")"
5872451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " -> " + order);
5882451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
5892451dbcc4f9641df188326215b204b798eb70c46vandwalle
590f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
591f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
592f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
5934dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
5942451dbcc4f9641df188326215b204b798eb70c46vandwalle    int compareWifiConfigurationsWithScorer(WifiConfiguration a, WifiConfiguration b) {
5952451dbcc4f9641df188326215b204b798eb70c46vandwalle
5962451dbcc4f9641df188326215b204b798eb70c46vandwalle        int aRssiBoost = 0;
5972451dbcc4f9641df188326215b204b798eb70c46vandwalle        int bRssiBoost = 0;
5982451dbcc4f9641df188326215b204b798eb70c46vandwalle
5992451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply Hysteresis : boost RSSI of current configuration before
6002451dbcc4f9641df188326215b204b798eb70c46vandwalle        // looking up the score
6012451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (null != mCurrentConfigurationKey) {
6022451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (a.configKey().equals(mCurrentConfigurationKey)) {
6032451dbcc4f9641df188326215b204b798eb70c46vandwalle                aRssiBoost += 15;
6042451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (b.configKey().equals(mCurrentConfigurationKey)) {
6052451dbcc4f9641df188326215b204b798eb70c46vandwalle                bRssiBoost += 15;
6062451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
6072451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
6082451dbcc4f9641df188326215b204b798eb70c46vandwalle        int scoreA = getConfigNetworkScore(a, 3000, aRssiBoost);
6092451dbcc4f9641df188326215b204b798eb70c46vandwalle        int scoreB = getConfigNetworkScore(a, 3000, bRssiBoost);
6102451dbcc4f9641df188326215b204b798eb70c46vandwalle
6112451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Both configurations need to have a score for the scorer to be used
6122451dbcc4f9641df188326215b204b798eb70c46vandwalle        // ...and the scores need to be different:-)
6132451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (scoreA == WifiNetworkScoreCache.INVALID_NETWORK_SCORE
6142451dbcc4f9641df188326215b204b798eb70c46vandwalle                || scoreB == WifiNetworkScoreCache.INVALID_NETWORK_SCORE) {
6152451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
6162451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
6172451dbcc4f9641df188326215b204b798eb70c46vandwalle
6182451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
6192451dbcc4f9641df188326215b204b798eb70c46vandwalle            String prefer = " = ";
6202451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (scoreA < scoreB) {
6212451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " < ";
6222451dbcc4f9641df188326215b204b798eb70c46vandwalle            } if (scoreA > scoreB) {
6232451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " > ";
6242451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
6252451dbcc4f9641df188326215b204b798eb70c46vandwalle            logDbg("compareWifiConfigurationsWithScorer " + a.configKey()
6262451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + a.visibility.rssi24
6272451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.rssi5
6282451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + a.visibility.num24
6292451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.num5 + ")"
6302451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + prefer + b.configKey()
6312451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + b.visibility.rssi24
6322451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.rssi5
6332451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + b.visibility.num24
6342451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.num5 + ")"
6352451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " -> " + Integer.toString(scoreB - scoreA));
6362451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
6372451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If scoreA > scoreB, the comparison is descending hence the return value is negative
6382451dbcc4f9641df188326215b204b798eb70c46vandwalle        return scoreB - scoreA;
6392451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
6402451dbcc4f9641df188326215b204b798eb70c46vandwalle
641f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    int compareWifiConfigurations(WifiConfiguration a, WifiConfiguration b) {
642f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
643117be607246604e875de62aa8cdd99700b77a2b4vandwalle        String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration();
644f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        boolean linked = false;
645f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
646453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if ((a.linkedConfigurations != null) && (b.linkedConfigurations != null)
647453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (a.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)
648453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (b.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)) {
6492451dbcc4f9641df188326215b204b798eb70c46vandwalle            if ((a.linkedConfigurations.get(b.configKey(true)) != null)
6502451dbcc4f9641df188326215b204b798eb70c46vandwalle                    && (b.linkedConfigurations.get(a.configKey(true)) != null)) {
651f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                linked = true;
652f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
653f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
654f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
655f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (a.ephemeral && b.ephemeral == false) {
656f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
657453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("compareWifiConfigurations ephemeral and prefers " + b.configKey()
658453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + a.configKey());
659f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
660931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            return 1; // b is of higher priority - ascending
661f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
662f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (b.ephemeral && a.ephemeral == false) {
663f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
6642451dbcc4f9641df188326215b204b798eb70c46vandwalle                logDbg("compareWifiConfigurations ephemeral and prefers " + a.configKey()
665453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + b.configKey());
666f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
667931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            return -1; // a is of higher priority - descending
668f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
669f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
6702451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply RSSI, in the range [-5, +5]
6712451dbcc4f9641df188326215b204b798eb70c46vandwalle        // after band adjustment, +n difference roughly corresponds to +10xn dBm
6722451dbcc4f9641df188326215b204b798eb70c46vandwalle        order = order + compareWifiConfigurationsRSSI(a, b, mCurrentConfigurationKey);
673f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
6742451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If the configurations are not linked, compare by user's choice, only a
6752451dbcc4f9641df188326215b204b798eb70c46vandwalle        // very high RSSI difference can then override the choice
6762451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (!linked) {
6772451dbcc4f9641df188326215b204b798eb70c46vandwalle            int choice;
678f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
6792451dbcc4f9641df188326215b204b798eb70c46vandwalle            choice = getConnectChoice(a, b);
6802451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice > 0) {
681931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of higher priority - descending
6822451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = order - choice;
683f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG) {
6842451dbcc4f9641df188326215b204b798eb70c46vandwalle                    logDbg("compareWifiConfigurations prefers " + a.configKey()
685453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + " over " + b.configKey()
6862451dbcc4f9641df188326215b204b798eb70c46vandwalle                            + " due to user choice order -> " + Integer.toString(order));
687f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
6882451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
6892451dbcc4f9641df188326215b204b798eb70c46vandwalle
6902451dbcc4f9641df188326215b204b798eb70c46vandwalle            choice = getConnectChoice(b, a);
6912451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice > 0) {
692931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of lower priority - ascending
6932451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = order + choice;
6944dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                if (VDBG) {
6952451dbcc4f9641df188326215b204b798eb70c46vandwalle                    logDbg("compareWifiConfigurations prefers " + b.configKey() + " over "
6962451dbcc4f9641df188326215b204b798eb70c46vandwalle                            + a.configKey() + " due to user choice order ->"
6972451dbcc4f9641df188326215b204b798eb70c46vandwalle                            + Integer.toString(order));
698f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
699f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
700f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
701ede1310be531a84faa08f02c3fd243448dd936ddvandwalle
702f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (order == 0) {
703931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // We don't know anything - pick the last seen i.e. K behavior
704931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // we should do this only for recently picked configurations
705f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (a.priority > b.priority) {
706931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of higher priority - descending
7072451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (VDBG) {
708453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("compareWifiConfigurations prefers -1 " + a.configKey() + " over "
709453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + b.configKey() + " due to priority");
710f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
711f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
712f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                order = -1;
713f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else if (a.priority < b.priority) {
714931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of lower priority - ascending
7152451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (VDBG) {
716453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("compareWifiConfigurations prefers +1 " + b.configKey() + " over "
717453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + a.configKey() + " due to priority");
718f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
7192451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = 1;
720f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
721f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
722f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
723f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String sorder = " == ";
724931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        if (order > 0) {
725f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " < ";
726931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        } else if (order < 0) {
727f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " > ";
728931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        }
729f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
7302451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
731453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            logDbg("compareWifiConfigurations Done: " + a.configKey() + sorder
732453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    + b.configKey() + " order " + Integer.toString(order));
733f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
734f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
735f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
736f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
737f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
738931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
739931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * attemptRoam function implements the core of the same SSID switching algorithm
740931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
741b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    ScanResult attemptRoam(WifiConfiguration current, int age) {
7424dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        ScanResult a = null;
743b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current == null) {
744b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
745b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam not associated");
746b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
7474dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            return null;
7484dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
749b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current.scanResultCache == null) {
750b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
751b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam no scan cache");
752b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
7534dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            return null;
7544dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
755b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle        if (current.scanResultCache.size() > 6) {
756b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
757c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                logDbg("attemptRoam scan cache size "
758c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + current.scanResultCache.size() + " --> bail");
759b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
760931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Implement same SSID roaming only for configurations
761c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            // that have less than 4 BSSIDs
7624dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            return null;
7634dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
764b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        String currentBSSID = mWifiStateMachine.getCurrentBSSID();
765b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (currentBSSID == null) {
766b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (DBG)   {
767b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam currentBSSID unknown");
768b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
769b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            return null;
770b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
771b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
772b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current.bssidOwnerUid!= 0 && current.bssidOwnerUid != Process.WIFI_UID) {
773b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (DBG)   {
774c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                logDbg("attemptRoam BSSID owner is "
775c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + Long.toString(current.bssidOwnerUid) + " -> bail");
776b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
7774dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            return null;
7784dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
7794dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
780931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Determine which BSSID we want to associate to, taking account
781c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle        // relative strength of 5 and 2.4 GHz BSSIDs
7822451dbcc4f9641df188326215b204b798eb70c46vandwalle        long nowMs = System.currentTimeMillis();
7834dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        int bRssiBoost5 = 0;
7844dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        int aRssiBoost5 = 0;
7854dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        int bRssiBoost = 0;
7864dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        int aRssiBoost = 0;
787b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        for (ScanResult b : current.scanResultCache.values()) {
7884dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
789931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            if ((b.seen == 0) || (b.BSSID == null)
7902451dbcc4f9641df188326215b204b798eb70c46vandwalle                    || (nowMs - b.seen) > age ) {
7912451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // TODO: do not apply blacklisting right now so as to leave this
7922451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // bug as apparent
7932451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // https://b2.corp.google.com/#/issues/16504012
7942451dbcc4f9641df188326215b204b798eb70c46vandwalle                    //                    || b.status != ScanResult.ENABLED) {
7954dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                continue;
7963a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
7974dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
798931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Pick first one
7994dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (a == null) {
8004dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                a = b;
8014dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                continue;
8024dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
8034dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
8042451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Apply hysteresis: we favor the currentBSSID by giving it a boost
805b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (currentBSSID.equals(b.BSSID)) {
806931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Reduce the benefit of hysteresis if RSSI <= -75
807c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                if (b.level <= WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD) {
808c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    bRssiBoost = +6;
809c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                } else {
810c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    bRssiBoost = +10;
811c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
8124dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
813b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (currentBSSID.equals(a.BSSID)) {
814c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                if (a.level <= WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD) {
815931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // Reduce the benefit of hysteresis if RSSI <= -75
816c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    aRssiBoost = +6;
817c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                } else {
818c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    aRssiBoost = +10;
819c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
8204dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
8212451dbcc4f9641df188326215b204b798eb70c46vandwalle
8222451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Favor 5GHz: give a boost to 5GHz BSSIDs
8232451dbcc4f9641df188326215b204b798eb70c46vandwalle            //   Boost the BSSID if it is on 5GHz, above a threshold
8242451dbcc4f9641df188326215b204b798eb70c46vandwalle            //   But penalize it if it is on 5GHz and below threshold
825c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            if (b.is5GHz() && (b.level+bRssiBoost)
826c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD) {
8274dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                bRssiBoost5 = 25;
828c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            } else if (b.is5GHz() && (b.level+bRssiBoost)
829c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    < WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD) {
830c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                bRssiBoost5 = -10;
8314dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
832c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            if (a.is5GHz() && (a.level+aRssiBoost)
833c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD) {
8344dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                aRssiBoost5 = 25;
835c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            } else if (a.is5GHz() && (a.level+aRssiBoost)
836c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    < WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD) {
837c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                aRssiBoost5 = -10;
8384dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
8394dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
8404dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (VDBG)  {
841c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                String comp = " < ";
842c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                if (b.level + bRssiBoost + bRssiBoost5 > a.level +aRssiBoost + aRssiBoost5) {
843c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    comp = " > ";
844c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
8454dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                logDbg("attemptRoam: "
846c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + b.BSSID + " rssi=" + b.level + " boost=" + Integer.toString(bRssiBoost)
847c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + "/" + Integer.toString(bRssiBoost5) + " freq=" + b.frequency + comp
848c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + a.BSSID + " rssi=" + a.level + " boost=" + Integer.toString(aRssiBoost)
849c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + "/" + Integer.toString(aRssiBoost5) + " freq=" + a.frequency);
850c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            }
851c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle
8522451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Compare the RSSIs after applying the hysteresis boost and the 5GHz
8532451dbcc4f9641df188326215b204b798eb70c46vandwalle            // boost if applicable
854c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            if (b.level + bRssiBoost + bRssiBoost5 > a.level +aRssiBoost + aRssiBoost5) {
855931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // b is the better BSSID
856c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                a = b;
8574dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
8584dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
8593a2a3d226881cce8a4e511302231d843b0def303vandwalle        if (a != null) {
8603a2a3d226881cce8a4e511302231d843b0def303vandwalle            if (VDBG)  {
8613a2a3d226881cce8a4e511302231d843b0def303vandwalle                logDbg("attemptRoam: Found "
8623a2a3d226881cce8a4e511302231d843b0def303vandwalle                        + a.BSSID + " rssi=" + a.level + " freq=" + a.frequency
8633a2a3d226881cce8a4e511302231d843b0def303vandwalle                        + " Current: " + currentBSSID);
8643a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
8653a2a3d226881cce8a4e511302231d843b0def303vandwalle            if (currentBSSID.equals(a.BSSID)) {
8663a2a3d226881cce8a4e511302231d843b0def303vandwalle                return null;
8673a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
8684dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
8693a2a3d226881cce8a4e511302231d843b0def303vandwalle        return a;
8704dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    }
8714dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
872931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
8732451dbcc4f9641df188326215b204b798eb70c46vandwalle     * getNetworkScore()
8742451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
8752451dbcc4f9641df188326215b204b798eb70c46vandwalle     * if scorer is present, get the network score of a WifiConfiguration
8762451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
8772451dbcc4f9641df188326215b204b798eb70c46vandwalle     * Note: this should be merge with setVisibility
8782451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
8792451dbcc4f9641df188326215b204b798eb70c46vandwalle     * @param config
8802451dbcc4f9641df188326215b204b798eb70c46vandwalle     * @return score
8812451dbcc4f9641df188326215b204b798eb70c46vandwalle     */
8822451dbcc4f9641df188326215b204b798eb70c46vandwalle    int getConfigNetworkScore(WifiConfiguration config, int age, int rssiBoost) {
8832451dbcc4f9641df188326215b204b798eb70c46vandwalle
8842451dbcc4f9641df188326215b204b798eb70c46vandwalle        int score = WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
8852451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (mNetworkScoreCache == null) {
8862451dbcc4f9641df188326215b204b798eb70c46vandwalle            return score;
8872451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
8882451dbcc4f9641df188326215b204b798eb70c46vandwalle
8892451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Get current date
8902451dbcc4f9641df188326215b204b798eb70c46vandwalle        long nowMs = System.currentTimeMillis();
8912451dbcc4f9641df188326215b204b798eb70c46vandwalle
8922451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Run thru all cached scan results
8932451dbcc4f9641df188326215b204b798eb70c46vandwalle        for (ScanResult result : scanResultCache.values()) {
8942451dbcc4f9641df188326215b204b798eb70c46vandwalle            if ((nowMs - result.seen) < age) {
8952451dbcc4f9641df188326215b204b798eb70c46vandwalle                int sc = mNetworkScoreCache.getNetworkScore(result, rssiBoost);
8962451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (sc > score) {
8972451dbcc4f9641df188326215b204b798eb70c46vandwalle                    score = sc;
8982451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
8992451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
9002451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
9012451dbcc4f9641df188326215b204b798eb70c46vandwalle        return score;
9022451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
9032451dbcc4f9641df188326215b204b798eb70c46vandwalle
9042451dbcc4f9641df188326215b204b798eb70c46vandwalle    /**
905931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * attemptAutoJoin() function implements the core of the a network switching algorithm
906931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
907f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void attemptAutoJoin() {
9082451dbcc4f9641df188326215b204b798eb70c46vandwalle        boolean didOverride = false;
909b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        int networkSwitchType = AUTO_JOIN_IDLE;
9104dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
9118c9088d11880553458f09377cc60d6eb7e66747bvandwalle        String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration();
9128c9088d11880553458f09377cc60d6eb7e66747bvandwalle
913931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Reset the currentConfiguration Key, and set it only if WifiStateMachine and
914453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        // supplicant agree
915453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        mCurrentConfigurationKey = null;
916453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        WifiConfiguration currentConfiguration = mWifiStateMachine.getCurrentWifiConfiguration();
917453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
918f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration candidate = null;
919f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
920931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Obtain the subset of recently seen networks
92127355a942653264388e909a4276196ee63e57811vandwalle        List<WifiConfiguration> list = mWifiConfigStore.getRecentConfiguredNetworks(3000, false);
922f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (list == null) {
923f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG)  logDbg("attemptAutoJoin nothing");
924f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return;
925f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
926f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
927931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Find the currently connected network: ask the supplicant directly
928f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String val = mWifiNative.status();
929f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String status[] = val.split("\\r?\\n");
930f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG) {
931f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("attemptAutoJoin() status=" + val + " split="
932f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.toString(status.length));
933f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
934f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
935b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        int supplicantNetId = -1;
936f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for (String key : status) {
937f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (key.regionMatches(0, "id=", 0, 3)) {
938f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                int idx = 3;
939b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                supplicantNetId = 0;
940f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                while (idx < key.length()) {
941f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    char c = key.charAt(idx);
942f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
943f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if ((c >= 0x30) && (c <= 0x39)) {
944b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                        supplicantNetId *= 10;
945b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                        supplicantNetId += c - 0x30;
946f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        idx++;
947f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    } else {
948f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        break;
949f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
950f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
951f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
952f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
953ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        if (DBG) {
954ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            logDbg("attemptAutoJoin() num recent config " + Integer.toString(list.size())
955b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                    + " ---> suppId=" + Integer.toString(supplicantNetId));
956ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
957f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
958453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if (currentConfiguration != null) {
9592451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (supplicantNetId != currentConfiguration.networkId
9602451dbcc4f9641df188326215b204b798eb70c46vandwalle                    //https://b.corp.google.com/issue?id=16484607
9612451dbcc4f9641df188326215b204b798eb70c46vandwalle                    //mark this confition as an error only if the mismatched networkId are valid
9622451dbcc4f9641df188326215b204b798eb70c46vandwalle                    && supplicantNetId != WifiConfiguration.INVALID_NETWORK_ID
9632451dbcc4f9641df188326215b204b798eb70c46vandwalle                    && currentConfiguration.networkId != WifiConfiguration.INVALID_NETWORK_ID) {
964453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("attemptAutoJoin() ERROR wpa_supplicant out of sync nid="
965b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                        + Integer.toString(supplicantNetId) + " WifiStateMachine="
966453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + Integer.toString(currentConfiguration.networkId));
967b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                mWifiStateMachine.disconnectCommand();
968b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                return;
969453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            } else {
970453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                mCurrentConfigurationKey = currentConfiguration.configKey();
971453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            }
972453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        }
973453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
974b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        int currentNetId = -1;
975b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (currentConfiguration != null) {
976931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // If we are associated to a configuration, it will
977b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            // be compared thru the compareNetwork function
978b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            currentNetId = currentConfiguration.networkId;
979b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        }
980b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle
981931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
982931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * Run thru all visible configurations without looking at the one we
983c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle         * are currently associated to
9844dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle         * select Best Network candidate from known WifiConfigurations
985931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
986f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for (WifiConfiguration config : list) {
987f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if ((config.status == WifiConfiguration.Status.DISABLED)
988f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    && (config.disableReason == WifiConfiguration.DISABLED_AUTH_FAILURE)) {
989ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
990b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("attemptAutoJoin skip candidate due to auth failure: "
991ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + config.configKey(true));
992ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
993f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
994f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
995453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
996e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            if (config.SSID == null) {
997b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                continue;
998e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            }
999e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
100027355a942653264388e909a4276196ee63e57811vandwalle            if (config.autoJoinStatus >=
100127355a942653264388e909a4276196ee63e57811vandwalle                    WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
1002931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Avoid networks disabled because of AUTH failure altogether
1003ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
1004ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                    logDbg("attemptAutoJoin skip candidate due to auto join status "
1005ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + Integer.toString(config.autoJoinStatus) + " key "
1006ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + config.configKey(true));
1007ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
1008f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
1009f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1010f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1011931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Try to un-blacklist based on elapsed time
101227355a942653264388e909a4276196ee63e57811vandwalle            if (config.blackListTimestamp > 0) {
101327355a942653264388e909a4276196ee63e57811vandwalle                long now = System.currentTimeMillis();
101427355a942653264388e909a4276196ee63e57811vandwalle                if (now < config.blackListTimestamp) {
1015931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    /**
1016931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * looks like there was a change in the system clock since we black listed, and
1017931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * timestamp is not meaningful anymore, hence lose it.
1018931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * this event should be rare enough so that we still want to lose the black list
10192451dbcc4f9641df188326215b204b798eb70c46vandwalle                     */
102027355a942653264388e909a4276196ee63e57811vandwalle                    config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
102127355a942653264388e909a4276196ee63e57811vandwalle                } else {
10224dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    if ((now - config.blackListTimestamp) > loseBlackListHardMilli) {
1023931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Reenable it after 18 hours, i.e. next day
102427355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
10254dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    } else if ((now - config.blackListTimestamp) > loseBlackListSoftMilli) {
1026931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Lose blacklisting due to bad link
102727355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(config.autoJoinStatus - 8);
102827355a942653264388e909a4276196ee63e57811vandwalle                    }
102927355a942653264388e909a4276196ee63e57811vandwalle                }
103027355a942653264388e909a4276196ee63e57811vandwalle            }
103127355a942653264388e909a4276196ee63e57811vandwalle
1032931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Try to unblacklist based on good visibility
103327355a942653264388e909a4276196ee63e57811vandwalle            if (config.visibility.rssi5 < WifiConfiguration.UNBLACKLIST_THRESHOLD_5_SOFT
103427355a942653264388e909a4276196ee63e57811vandwalle                    && config.visibility.rssi24 < WifiConfiguration.UNBLACKLIST_THRESHOLD_24_SOFT) {
103527355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
103627355a942653264388e909a4276196ee63e57811vandwalle                    logDbg("attemptAutoJoin skip candidate due to auto join status "
10374dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.autoJoinStatus
10384dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " key " + config.configKey(true)
10394dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " rssi=(" + config.visibility.rssi24
10404dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.rssi5
10414dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
10424dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
104327355a942653264388e909a4276196ee63e57811vandwalle                }
104427355a942653264388e909a4276196ee63e57811vandwalle            } else if (config.visibility.rssi5 < WifiConfiguration.UNBLACKLIST_THRESHOLD_5_HARD
104527355a942653264388e909a4276196ee63e57811vandwalle                    && config.visibility.rssi24 < WifiConfiguration.UNBLACKLIST_THRESHOLD_24_HARD) {
1046931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // If the network is simply temporary disabled, don't allow reconnect until
1047931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // RSSI becomes good enough
104827355a942653264388e909a4276196ee63e57811vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 1);
104927355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
105027355a942653264388e909a4276196ee63e57811vandwalle                    logDbg("attemptAutoJoin good candidate seen, bumped soft -> status="
105127355a942653264388e909a4276196ee63e57811vandwalle                            + config.autoJoinStatus
10524dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " key " + config.configKey(true) + " rssi=("
10534dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.visibility.rssi24 + "," + config.visibility.rssi5
10544dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
10554dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
105627355a942653264388e909a4276196ee63e57811vandwalle                }
105727355a942653264388e909a4276196ee63e57811vandwalle            } else {
1058c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 3);
105927355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
106027355a942653264388e909a4276196ee63e57811vandwalle                    logDbg("attemptAutoJoin good candidate seen, bumped hard -> status="
106127355a942653264388e909a4276196ee63e57811vandwalle                            + config.autoJoinStatus
10624dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " key " + config.configKey(true) + " rssi=("
10634dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.visibility.rssi24 + "," + config.visibility.rssi5
10644dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
10654dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
106627355a942653264388e909a4276196ee63e57811vandwalle                }
106727355a942653264388e909a4276196ee63e57811vandwalle            }
106827355a942653264388e909a4276196ee63e57811vandwalle
106927355a942653264388e909a4276196ee63e57811vandwalle            if (config.autoJoinStatus >=
107027355a942653264388e909a4276196ee63e57811vandwalle                    WifiConfiguration.AUTO_JOIN_TEMPORARY_DISABLED) {
1071931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Network is blacklisted, skip
10724dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                if (DBG) {
10734dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    logDbg("attemptAutoJoin skip blacklisted -> status="
10744dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.autoJoinStatus
10754dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " key " + config.configKey(true) + " rssi=("
10764dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.visibility.rssi24 + "," + config.visibility.rssi5
10774dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
10784dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
10794dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                }
108027355a942653264388e909a4276196ee63e57811vandwalle                continue;
108127355a942653264388e909a4276196ee63e57811vandwalle            }
1082f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (config.networkId == currentNetId) {
1083ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
108421bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    logDbg("attemptAutoJoin skip current candidate  "
108521bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                            + Integer.toString(currentNetId)
1086ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + " key " + config.configKey(true));
1087ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
1088f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
1089f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1090f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
109121bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle            if (lastSelectedConfiguration == null ||
109221bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    !config.configKey().equals(lastSelectedConfiguration)) {
1093931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Don't try to autojoin a network that is too far
10948c9088d11880553458f09377cc60d6eb7e66747bvandwalle                if (config.visibility == null) {
10958c9088d11880553458f09377cc60d6eb7e66747bvandwalle                    continue;
10968c9088d11880553458f09377cc60d6eb7e66747bvandwalle                }
109727355a942653264388e909a4276196ee63e57811vandwalle                if (config.visibility.rssi5 < WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_5
1098c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        && config.visibility.rssi24
1099c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        < WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_24) {
11004dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    if (DBG) {
11014dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                        logDbg("attemptAutoJoin gskip due to low visibility -> status="
11024dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                                + config.autoJoinStatus
11034dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                                + " key " + config.configKey(true) + " rssi="
11044dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                                + config.visibility.rssi24 + ", " + config.visibility.rssi5
11054dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                                + " num=" + config.visibility.num24
11064dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                                + ", " + config.visibility.num5);
11074dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    }
11088c9088d11880553458f09377cc60d6eb7e66747bvandwalle                    continue;
11098c9088d11880553458f09377cc60d6eb7e66747bvandwalle                }
11108c9088d11880553458f09377cc60d6eb7e66747bvandwalle            }
11118c9088d11880553458f09377cc60d6eb7e66747bvandwalle
1112ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            if (DBG) {
1113c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                logDbg("attemptAutoJoin trying candidate id="
1114c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + Integer.toString(config.networkId) + " "
11154dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                        + config.SSID + " key " + config.configKey(true)
11164dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                        + " status=" + config.autoJoinStatus);
1117ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            }
1118f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1119f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate == null) {
1120f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                candidate = config;
1121f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
1122f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG)  {
1123453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("attemptAutoJoin will compare candidate  " + candidate.configKey()
11244dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " with " + config.configKey());
1125f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1126f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
11272451dbcc4f9641df188326215b204b798eb70c46vandwalle                int scorerOrder = compareWifiConfigurationsWithScorer(candidate, config);
1128f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                int order = compareWifiConfigurations(candidate, config);
11292451dbcc4f9641df188326215b204b798eb70c46vandwalle
11302451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (scorerOrder * order < 0) {
11312451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // For debugging purpose, remember that an override happened
11322451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // during that autojoin Attempt
11332451dbcc4f9641df188326215b204b798eb70c46vandwalle                    didOverride = true;
11342451dbcc4f9641df188326215b204b798eb70c46vandwalle                    candidate.numScorerOverride++;
11352451dbcc4f9641df188326215b204b798eb70c46vandwalle                    config.numScorerOverride++;
11362451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
11372451dbcc4f9641df188326215b204b798eb70c46vandwalle
11382451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (scorerOrder != 0) {
11392451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // If the scorer came up with a result then use the scorer's result, else use
11402451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // the order provided by the base comparison function
11412451dbcc4f9641df188326215b204b798eb70c46vandwalle                    order = scorerOrder;
11422451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
11432451dbcc4f9641df188326215b204b798eb70c46vandwalle
11442451dbcc4f9641df188326215b204b798eb70c46vandwalle                // The lastSelectedConfiguration is the configuration the user has manually selected
11452451dbcc4f9641df188326215b204b798eb70c46vandwalle                // thru thru WifiPicker, or that a 3rd party app asked us to connect to via the
11462451dbcc4f9641df188326215b204b798eb70c46vandwalle                // enableNetwork with disableOthers=true WifiManager API
11472451dbcc4f9641df188326215b204b798eb70c46vandwalle                // As this is a direct user choice, we strongly prefer this configuration,
11482451dbcc4f9641df188326215b204b798eb70c46vandwalle                // hence give +/-100
11492451dbcc4f9641df188326215b204b798eb70c46vandwalle                if ((lastSelectedConfiguration != null)
11502451dbcc4f9641df188326215b204b798eb70c46vandwalle                        && candidate.configKey().equals(lastSelectedConfiguration)) {
11512451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // candidate is the last selected configuration,
11522451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // so keep it above connect choices (+/-60) and
11532451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // above RSSI/scorer based selection of linked configuration (+/- 50)
11542451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // by reducing order by -100
11552451dbcc4f9641df188326215b204b798eb70c46vandwalle                    order = order - 100;
11562451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (VDBG)   {
11572451dbcc4f9641df188326215b204b798eb70c46vandwalle                        logDbg("  prefers -100 " + candidate.configKey()
11582451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " over " + config.configKey()
11592451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " because it is the last selected -> "
11602451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + Integer.toString(order));
11612451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
11622451dbcc4f9641df188326215b204b798eb70c46vandwalle                } else if ((lastSelectedConfiguration != null)
11632451dbcc4f9641df188326215b204b798eb70c46vandwalle                        && config.configKey().equals(lastSelectedConfiguration)) {
11642451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // config is the last selected configuration,
11652451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // so keep it above connect choices (+/-60) and
11662451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // above RSSI/scorer based selection of linked configuration (+/- 50)
11672451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // by increasing order by +100
11682451dbcc4f9641df188326215b204b798eb70c46vandwalle                    order = order + 100;
11692451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (VDBG)   {
11702451dbcc4f9641df188326215b204b798eb70c46vandwalle                        logDbg("  prefers +100 " + config.configKey()
11712451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " over " + candidate.configKey()
11722451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " because it is the last selected -> "
11732451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + Integer.toString(order));
11742451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
11752451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
11762451dbcc4f9641df188326215b204b798eb70c46vandwalle
1177f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (order > 0) {
1178931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // Ascending : candidate < config
1179f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    candidate = config;
1180f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1181f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1182f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1183f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
11842451dbcc4f9641df188326215b204b798eb70c46vandwalle        /* Wait for VPN to be available on the system to make use of this code
11852451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Now, go thru scan result to try finding a better untrusted network
1186f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (mNetworkScoreCache != null) {
1187f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi5 = WifiConfiguration.INVALID_RSSI;
1188f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi24 = WifiConfiguration.INVALID_RSSI;
1189f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            WifiConfiguration.Visibility visibility;
1190f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate != null) {
1191f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi5 = candidate.visibility.rssi5;
1192f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi24 = candidate.visibility.rssi24;
1193f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1194f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1195931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Get current date
11962451dbcc4f9641df188326215b204b798eb70c46vandwalle            long nowMs = System.currentTimeMillis();
1197f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
11982451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Look for untrusted scored network only if the current candidate is bad
1199f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (rssi5 < -60 && rssi24 < -70) {
1200f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                for (ScanResult result : scanResultCache.values()) {
12012451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if ((nowMs - result.seen) < 3000) {
1202f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        int score = mNetworkScoreCache.getNetworkScore(result);
1203f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        if (score > 0) {
1204931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                            // Try any arbitrary formula for now, adding apple and oranges,
1205f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                            // i.e. adding network score and "dBm over noise"
12064dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                           if (result.is24GHz()) {
1207f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                if ((result.level + score) > (rssi24 -40)) {
1208931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                                    // Force it as open, TBD should we otherwise verify that this
1209f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    // BSSID only supports open??
1210f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    result.capabilities = "";
1211f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1212931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                                    // Switch to this scan result
1213f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    candidate =
1214c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                                          mWifiConfigStore.wifiConfigurationFromScanResult(result);
1215f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    candidate.ephemeral = true;
1216f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                }
1217f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                           } else {
1218f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                if ((result.level + score) > (rssi5 -30)) {
1219931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                                    // Force it as open, TBD should we otherwise verify that this
1220f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    // BSSID only supports open??
1221f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    result.capabilities = "";
1222f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1223931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                                    // Switch to this scan result
1224f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    candidate =
1225c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                                          mWifiConfigStore.wifiConfigurationFromScanResult(result);
1226f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                    candidate.ephemeral = true;
1227f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                                }
1228f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                           }
1229f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        }
1230f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
1231f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1232f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
12332451dbcc4f9641df188326215b204b798eb70c46vandwalle        }*/
1234b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
1235931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1236931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         *  If candidate is found, check the state of the connection so as
1237931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         *  to decide if we should be acting on this candidate and switching over
1238931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
1239b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        int networkDelta = compareNetwork(candidate);
1240b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (DBG && candidate != null) {
1241b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            logDbg("attemptAutoJoin compare SSID candidate : delta="
1242b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                    + Integer.toString(networkDelta) + " "
1243b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                    + candidate.configKey()
1244c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    + " linked=" + (currentConfiguration != null
1245c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    && currentConfiguration.isLinked(candidate)));
1246b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
12474dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1248931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1249931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * Ask WifiStateMachine permission to switch :
1250931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * if user is currently streaming voice traffic,
1251931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * then we should not be allowed to switch regardless of the delta
1252931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
1253b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (mWifiStateMachine.shouldSwitchNetwork(networkDelta)) {
1254b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (mStaStaSupported) {
1255b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("mStaStaSupported --> error do nothing now ");
1256b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            } else {
1257b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (currentConfiguration != null && currentConfiguration.isLinked(candidate)) {
1258b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    networkSwitchType = AUTO_JOIN_EXTENDED_ROAMING;
1259b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                } else {
1260b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    networkSwitchType = AUTO_JOIN_OUT_OF_NETWORK_ROAMING;
1261b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
1262b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (DBG) {
1263b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("AutoJoin auto connect with netId "
1264b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + Integer.toString(candidate.networkId)
1265b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " to " + candidate.configKey());
1266b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
12672451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (didOverride) {
12682451dbcc4f9641df188326215b204b798eb70c46vandwalle                    candidate.numScorerOverrideAndSwitchedNetwork++;
12692451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
1270b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_CONNECT,
1271b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                        candidate.networkId, networkSwitchType, candidate);
12724dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
1273b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
12744dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1275b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (networkSwitchType == AUTO_JOIN_IDLE) {
1276931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Attempt same WifiConfiguration roaming
1277b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            ScanResult roamCandidate = attemptRoam(currentConfiguration, 3000);
1278b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (roamCandidate != null) {
1279b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (DBG) {
1280b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("AutoJoin auto roam with netId "
1281b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + Integer.toString(currentConfiguration.networkId)
1282b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " " + currentConfiguration.configKey() + " to BSSID="
1283b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + roamCandidate.BSSID + " freq=" + roamCandidate.frequency
1284b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " RSSI=" + roamCandidate.frequency);
1285b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
1286b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                networkSwitchType = AUTO_JOIN_ROAMING;
1287b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle                mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_ROAM,
1288b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle                            currentConfiguration.networkId, 1, roamCandidate);
1289f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1290f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1291b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (VDBG) logDbg("Done attemptAutoJoin status=" + Integer.toString(networkSwitchType));
1292f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
1293f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle}
1294f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1295