WifiAutoJoinController.java revision 49bc8dd35845318cd9bc5ce9064fc1ad33bbece8
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;
20f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.NetworkKey;
21f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.net.NetworkScoreManager;
220c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalleimport android.net.WifiKey;
23c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalleimport android.net.wifi.*;
248639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidsonimport android.net.wifi.WifiConfiguration.KeyMgmt;
2516fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidsonimport android.os.SystemClock;
2616fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidsonimport android.provider.Settings;
27f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalleimport android.os.Process;
28c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalleimport android.text.TextUtils;
29f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport android.util.Log;
30f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
310c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalleimport java.util.ArrayList;
32f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.Iterator;
33f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.HashMap;
34f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalleimport java.util.List;
35f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
36f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle/**
37f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * AutoJoin controller is responsible for WiFi Connect decision
38f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
39f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle * It runs in the thread context of WifiStateMachine
40f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle *
41f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle */
42f22d23092ab37286a5ef9d257d5bb32c421d2669vandwallepublic class WifiAutoJoinController {
43f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
44f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private Context mContext;
45f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiStateMachine mWifiStateMachine;
46f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiConfigStore mWifiConfigStore;
47f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNative mWifiNative;
48f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
49f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private NetworkScoreManager scoreManager;
50f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private WifiNetworkScoreCache mNetworkScoreCache;
51f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
52f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final String TAG = "WifiAutoJoinController ";
53ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    private static boolean DBG = false;
54ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    private static boolean VDBG = false;
55f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private static final boolean mStaStaSupported = false;
56f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
57c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    public static int mScanResultMaximumAge = 40000; /* milliseconds unit */
58833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle    public static int mScanResultAutoJoinAge = 5000; /* milliseconds unit */
59c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
60453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle    private String mCurrentConfigurationKey = null; //used by autojoin
61f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
62f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private HashMap<String, ScanResult> scanResultCache =
63f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            new HashMap<String, ScanResult>();
64f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
65c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    private WifiConnectionStatistics mWifiConnectionStatistics;
66c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
678639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    /** Whether to allow connections to untrusted networks. */
688639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    private boolean mAllowUntrustedConnections = false;
698639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson
70c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    /* For debug purpose only: if the scored override a score */
71c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    boolean didOverride = false;
72c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
73931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Lose the non-auth failure blacklisting after 8 hours
744dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    private final static long loseBlackListHardMilli = 1000 * 60 * 60 * 8;
75931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Lose some temporary blacklisting after 30 minutes
764dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    private final static long loseBlackListSoftMilli = 1000 * 60 * 30;
7727355a942653264388e909a4276196ee63e57811vandwalle
7816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson    /** @see android.provider.Settings.Global#WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS */
7916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson    private static final long DEFAULT_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS = 1000 * 60; // 1 minute
8016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
81b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_IDLE = 0;
82b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_ROAMING = 1;
83b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_EXTENDED_ROAMING = 2;
84b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle    public static final int AUTO_JOIN_OUT_OF_NETWORK_ROAMING = 3;
85b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
8697b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle    public static final int HIGH_THRESHOLD_MODIFIER = 5;
8797b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle
881ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    // Below are AutoJoin wide parameters indicating if we should be aggressive before joining
891ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    // weak network. Note that we cannot join weak network that are going to be marked as unanted by
901ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    // ConnectivityService because this will trigger link flapping.
911ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    /**
921ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     * There was a non-blacklisted configuration that we bailed from because of a weak signal
931ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     */
941ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    boolean didBailDueToWeakRssi = false;
951ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    /**
961ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     * number of time we consecutively bailed out of an eligible network because its signal
971ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     * was too weak
981ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle     */
991ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle    int weakRssiBailCount = 0;
1001ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle
101f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    WifiAutoJoinController(Context c, WifiStateMachine w, WifiConfigStore s,
102c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                           WifiConnectionStatistics st, WifiNative n) {
103f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mContext = c;
104f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiStateMachine = w;
105f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiConfigStore = s;
106f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mWifiNative = n;
107f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        mNetworkScoreCache = null;
108c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        mWifiConnectionStatistics = st;
10921bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle        scoreManager =
11021bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                (NetworkScoreManager) mContext.getSystemService(Context.NETWORK_SCORE_SERVICE);
111f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager == null)
112f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("Registered scoreManager NULL " + " service " + Context.NETWORK_SCORE_SERVICE);
113f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
114f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (scoreManager != null) {
115f13817203179f41620514718c8668ae7e418f8afJeff Davidson            mNetworkScoreCache = new WifiNetworkScoreCache(mContext);
116f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            scoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
117f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        } else {
118f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("No network score service: Couldnt register as a WiFi score Manager, type="
119f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.toString(NetworkKey.TYPE_WIFI)
120f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + " service " + Context.NETWORK_SCORE_SERVICE);
121f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            mNetworkScoreCache = null;
122f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
123f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
124f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
125ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    void enableVerboseLogging(int verbose) {
126ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        if (verbose > 0 ) {
127abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = true;
128ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = true;
129ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        } else {
130abde872adced15dfb6781fb71959453d963326dbYuhao Zheng            DBG = false;
131ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            VDBG = false;
132ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
133ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle    }
134ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle
135931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
136931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * Flush out scan results older than mScanResultMaximumAge
137ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     *
138931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
139f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    private void ageScanResultsOut(int delay) {
140f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (delay <= 0) {
141931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            delay = mScanResultMaximumAge; // Something sane
142f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
143b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        long milli = System.currentTimeMillis();
144f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG) {
145f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("ageScanResultsOut delay " + Integer.valueOf(delay) + " size "
146f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.valueOf(scanResultCache.size()) + " now " + Long.valueOf(milli));
147f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
148f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
149f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        Iterator<HashMap.Entry<String,ScanResult>> iter = scanResultCache.entrySet().iterator();
150f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        while (iter.hasNext()) {
151f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            HashMap.Entry<String,ScanResult> entry = iter.next();
152f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            ScanResult result = entry.getValue();
153f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
154f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if ((result.seen + delay) < milli) {
155f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                iter.remove();
156f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
157f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
158f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
159f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
160be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle    int addToScanCache(List<ScanResult> scanList) {
161be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        int numScanResultsKnown = 0; // Record number of scan results we knew about
162be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        WifiConfiguration associatedConfig = null;
1637b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle        boolean didAssociate = false;
1648242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle        long now = System.currentTimeMillis();
165f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1660c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        ArrayList<NetworkKey> unknownScanResults = new ArrayList<NetworkKey>();
1670c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
168f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for(ScanResult result: scanList) {
1691fcf3c6d2b9ed65573e1e7c55fc5a30ebd364c4fYuhao Zheng            if (result.SSID == null) continue;
170c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
171c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            // Make sure we record the last time we saw this result
172f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            result.seen = System.currentTimeMillis();
173f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
174c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            // Fetch the previous instance for this result
175f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            ScanResult sr = scanResultCache.get(result.BSSID);
176f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (sr != null) {
1778ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                if (mWifiConfigStore.scanResultRssiLevelPatchUp != 0
1788ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                        && result.level == 0
1798ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                        && sr.level < -20) {
1808ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                    // A 'zero' RSSI reading is most likely a chip problem which returns
1818ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                    // an unknown RSSI, hence ignore it
1828ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                    result.level = sr.level;
1838ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                }
1848ccabb81ad304b80dc8eaa162fd322643461529bvandwalle
185931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // If there was a previous cache result for this BSSID, average the RSSI values
186c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                result.averageRssi(sr.level, sr.seen, mScanResultMaximumAge);
187f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
188c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                // Remove the previous Scan Result - this is not necessary
189f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                scanResultCache.remove(result.BSSID);
1908ccabb81ad304b80dc8eaa162fd322643461529bvandwalle            } else if (mWifiConfigStore.scanResultRssiLevelPatchUp != 0 && result.level == 0) {
1918ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                // A 'zero' RSSI reading is most likely a chip problem which returns
1928ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                // an unknown RSSI, hence initialize it to a sane value
1938ccabb81ad304b80dc8eaa162fd322643461529bvandwalle                result.level = mWifiConfigStore.scanResultRssiLevelPatchUp;
194e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            }
195e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle
196e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            if (!mNetworkScoreCache.isScoredNetwork(result)) {
197e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                WifiKey wkey;
198e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                // Quoted SSIDs are the only one valid at this stage
199e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                try {
200e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    wkey = new WifiKey("\"" + result.SSID + "\"", result.BSSID);
201e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                } catch (IllegalArgumentException e) {
202e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    logDbg("AutoJoinController: received badly encoded SSID=[" + result.SSID +
203e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                            "] ->skipping this network");
204e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    wkey = null;
205e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                }
206e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                if (wkey != null) {
207e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    NetworkKey nkey = new NetworkKey(wkey);
208e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    //if we don't know this scan result then request a score from the scorer
209e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    unknownScanResults.add(nkey);
210e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                }
211e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                if (VDBG) {
2127b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    String cap = "";
2137b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    if (result.capabilities != null)
2147b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                        cap = result.capabilities;
215e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    logDbg(result.SSID + " " + result.BSSID + " rssi="
2167b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                            + result.level + " cap " + cap + " is not scored");
217e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                }
2180c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            } else {
219e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                if (VDBG) {
2207b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    String cap = "";
2217b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    if (result.capabilities != null)
2227b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                        cap = result.capabilities;
223e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    int score = mNetworkScoreCache.getNetworkScore(result);
224e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    logDbg(result.SSID + " " + result.BSSID + " rssi="
2257b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                            + result.level + " cap " + cap + " is scored : " + score);
2260c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                }
227f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
228f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
229e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // scanResultCache.put(result.BSSID, new ScanResult(result));
230e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            scanResultCache.put(result.BSSID, result);
231be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            // Add this BSSID to the scanResultCache of a Saved WifiConfiguration
2327b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle            didAssociate = mWifiConfigStore.updateSavedNetworkHistory(result);
233f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
234be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            // If not successful, try to associate this BSSID to an existing Saved WifiConfiguration
2357b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle            if (!didAssociate) {
236be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                // We couldn't associate the scan result to a Saved WifiConfiguration
237c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                // Hence it is untrusted
238c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                result.untrusted = true;
239f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                associatedConfig = mWifiConfigStore.associateWithConfiguration(result);
2401fcf3c6d2b9ed65573e1e7c55fc5a30ebd364c4fYuhao Zheng                if (associatedConfig != null && associatedConfig.SSID != null) {
241f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (VDBG) {
242f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        logDbg("addToScanCache save associated config "
2438242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle                                + associatedConfig.SSID + " with " + result.SSID
2448242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle                                + " status " + associatedConfig.autoJoinStatus
2458242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle                                + " reason " + associatedConfig.disableReason
2468242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle                                + " tsp " + associatedConfig.blackListTimestamp
2478242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle                                + " was " + (now - associatedConfig.blackListTimestamp));
248f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
249be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                    mWifiStateMachine.sendMessage(
250be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                            WifiStateMachine.CMD_AUTO_SAVE_NETWORK, associatedConfig);
2517b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle                    didAssociate = true;
252f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
2530d616ef3bf635dff8722e064c0be842676390ed8vandwalle            } else {
2540d616ef3bf635dff8722e064c0be842676390ed8vandwalle                // If the scan result has been blacklisted fir 18 hours -> unblacklist
2550d616ef3bf635dff8722e064c0be842676390ed8vandwalle                if ((now - result.blackListTimestamp) > loseBlackListHardMilli) {
2560d616ef3bf635dff8722e064c0be842676390ed8vandwalle                    result.setAutoJoinStatus(ScanResult.ENABLED);
2570d616ef3bf635dff8722e064c0be842676390ed8vandwalle                }
258f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
2597b581f46f6c9bc6edf0edd287d47106712fb2144vandwalle            if (didAssociate) {
260be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle                numScanResultsKnown++;
261a0708b09ad17b086c008ab100aec7143d7613c80vandwalle                result.isAutoJoinCandidate ++;
262a0708b09ad17b086c008ab100aec7143d7613c80vandwalle            } else {
263a0708b09ad17b086c008ab100aec7143d7613c80vandwalle                result.isAutoJoinCandidate = 0;
264be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            }
265f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
2660c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle
2670c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        if (unknownScanResults.size() != 0) {
2680c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            NetworkKey[] newKeys =
2690c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle                    unknownScanResults.toArray(new NetworkKey[unknownScanResults.size()]);
270931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Kick the score manager, we will get updated scores asynchronously
2710c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle            scoreManager.requestScores(newKeys);
2720c8b99a3b78e458a5617cc449e2efe69c5bdd531vandwalle        }
273be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        return numScanResultsKnown;
274f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
275f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
276f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void logDbg(String message) {
2770888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle        logDbg(message, false);
278ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    }
279ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
280ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    void logDbg(String message, boolean stackTrace) {
281ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (stackTrace) {
2822f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle            Log.e(TAG, message + " stack:"
283ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[2].getMethodName() + " - "
284ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[3].getMethodName() + " - "
285ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[4].getMethodName() + " - "
286ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    + Thread.currentThread().getStackTrace()[5].getMethodName());
287ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        } else {
2882f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle            Log.e(TAG, message);
289ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        }
290f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
291f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
292931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    // Called directly from WifiStateMachine
293be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle    int newSupplicantResults(boolean doAutoJoin) {
294be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        int numScanResultsKnown;
295e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        List<ScanResult> scanList = mWifiStateMachine.getScanResultsListNoCopyUnsync();
296be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        numScanResultsKnown = addToScanCache(scanList);
297f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(mScanResultMaximumAge);
298be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        if (DBG) {
299be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle            logDbg("newSupplicantResults size=" + Integer.valueOf(scanResultCache.size())
3002f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        + " known=" + numScanResultsKnown + " "
3019f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                        + doAutoJoin);
302be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        }
3037806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle        if (doAutoJoin) {
3047806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            attemptAutoJoin();
3057806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle        }
306005c1ef113192f898499a407dd266393a8d6b076vandwalle        mWifiConfigStore.writeKnownNetworkHistory(false);
307be3095ed758fca076b9ccb9fdae48f7f865c078avandwalle        return numScanResultsKnown;
308f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
309f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
310f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
311931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
312931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * Not used at the moment
313f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * should be a call back from WifiScanner HAL ??
314f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * this function is not hooked and working yet, it will receive scan results from WifiScanners
315f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * with the list of IEs,then populate the capabilities by parsing the IEs and inject the scan
316f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * results as normal.
317f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     */
318f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void newHalScanResults() {
319f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        List<ScanResult> scanList = null;//mWifiScanner.syncGetScanResultsList();
320f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String akm = WifiParser.parse_akm(null, null);
321f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        logDbg(akm);
322f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        addToScanCache(scanList);
323f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        ageScanResultsOut(0);
324f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
325005c1ef113192f898499a407dd266393a8d6b076vandwalle        mWifiConfigStore.writeKnownNetworkHistory(false);
326f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
327f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
328931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
329931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     *  network link quality changed, called directly from WifiTrafficPoller,
330931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * or by listening to Link Quality intent
331931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
332f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    void linkQualitySignificantChange() {
333f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        attemptAutoJoin();
334f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
335f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
336931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
337f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * compare a WifiConfiguration against the current network, return a delta score
338f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * If not associated, and the candidate will always be better
339f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * For instance if the candidate is a home network versus an unknown public wifi,
340f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle     * the delta will be infinite, else compare Kepler scores etc…
341b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle     * Negatve return values from this functions are meaningless per se, just trying to
342b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle     * keep them distinct for debug purpose (i.e. -1, -2 etc...)
343931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
344e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle    private int compareNetwork(WifiConfiguration candidate,
345e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                               String lastSelectedConfiguration) {
346b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (candidate == null)
347b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            return -3;
348b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
349f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration currentNetwork = mWifiStateMachine.getCurrentWifiConfiguration();
350b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (currentNetwork == null) {
351c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // Return any absurdly high score, if we are not connected there is no current
352c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // network to...
353b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle           return 1000;
354b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        }
355f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
356f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (candidate.configKey(true).equals(currentNetwork.configKey(true))) {
357b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            return -2;
358f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
359f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
360b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle        if (DBG) {
361e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            logDbg("compareNetwork will compare " + candidate.configKey()
362e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    + " with current " + currentNetwork.configKey());
363b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle        }
364833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle        int order = compareWifiConfigurations(currentNetwork, candidate);
365e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle
366e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // The lastSelectedConfiguration is the configuration the user has manually selected
367e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // thru WifiPicker, or that a 3rd party app asked us to connect to via the
368e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // enableNetwork with disableOthers=true WifiManager API
369e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // As this is a direct user choice, we strongly prefer this configuration,
370e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        // hence give +/-100
371e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        if ((lastSelectedConfiguration != null)
372e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                && currentNetwork.configKey().equals(lastSelectedConfiguration)) {
373e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // currentNetwork is the last selected configuration,
374e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // so keep it above connect choices (+/-60) and
375e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // above RSSI/scorer based selection of linked configuration (+/- 50)
376e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // by reducing order by -100
377e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            order = order - 100;
378e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            if (VDBG)   {
379e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("     ...and prefers -100 " + currentNetwork.configKey()
380e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " over " + candidate.configKey()
381e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " because it is the last selected -> "
382e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + Integer.toString(order));
383e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            }
384e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        } else if ((lastSelectedConfiguration != null)
385e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                && candidate.configKey().equals(lastSelectedConfiguration)) {
386e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // candidate is the last selected configuration,
387e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // so keep it above connect choices (+/-60) and
388e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // above RSSI/scorer based selection of linked configuration (+/- 50)
389e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            // by increasing order by +100
390e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            order = order + 100;
391e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            if (VDBG)   {
392e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("     ...and prefers +100 " + candidate.configKey()
393e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " over " + currentNetwork.configKey()
394e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " because it is the last selected -> "
395e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + Integer.toString(order));
396e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            }
397e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        }
398e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle
399ede507649471f1113e9e1919812115ca5a6bc0c8vandwalle        return order;
400f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
401f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
402ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle    /**
403ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * update the network history fields fo that configuration
404ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if userTriggered, we mark the configuration as "non selfAdded" since the user has seen it
405ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * and took over management
406ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * - if it is a "connect", remember which network were there at the point of the connect, so
407ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * as those networks get a relative lower score than the selected configuration
40862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle     *
409ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param netId
410ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param userTriggered : if the update come from WiFiManager
411ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle     * @param connect : if the update includes a connect
412931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
41362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle    public void updateConfigurationHistory(int netId, boolean userTriggered, boolean connect) {
414f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration selected = mWifiConfigStore.getWifiConfiguration(netId);
415f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (selected == null) {
416c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            logDbg("updateConfigurationHistory nid=" + netId + " no selected configuration!");
417f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return;
418f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
419f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
420e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        if (selected.SSID == null) {
421c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            logDbg("updateConfigurationHistory nid=" + netId +
422c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    " no SSID in selected configuration!");
423e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            return;
424e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle        }
425e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
42662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        if (userTriggered) {
427931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Reenable autojoin for this network,
42862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            // since the user want to connect to this configuration
42927355a942653264388e909a4276196ee63e57811vandwalle            selected.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
43062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            selected.selfAdded = false;
431e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            selected.dirty = true;
43262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle        }
433f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
434992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (DBG && userTriggered) {
435f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (selected.connectChoices != null) {
436ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
437f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        + Integer.toString(netId) + " now: "
438992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(selected.connectChoices.size())
439992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
440f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
441ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                logDbg("updateConfigurationHistory will update "
442992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + Integer.toString(netId)
443992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        + " uid=" + Integer.toString(selected.creatorUid), true);
444f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
445f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
446f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
447ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle        if (connect && userTriggered) {
448ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle            boolean found = false;
4492451dbcc4f9641df188326215b204b798eb70c46vandwalle            int choice = 0;
450c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            int size = 0;
4519f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle
4529f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // Reset the triggered disabled count, because user wanted to connect to this
4539f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // configuration, and we were not.
4549f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredWifiDisableLowRSSI = 0;
4559f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredWifiDisableBadRSSI = 0;
4569f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredWifiDisableNotHighRSSI = 0;
4579f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            selected.numUserTriggeredJoinAttempts++;
4589f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle
45962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            List<WifiConfiguration> networks =
46062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    mWifiConfigStore.getRecentConfiguredNetworks(12000, false);
461c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            if (networks != null) size = networks.size();
462c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            logDbg("updateConfigurationHistory found " + size + " networks");
46362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle            if (networks != null) {
46462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                for (WifiConfiguration config : networks) {
465992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    if (DBG) {
466992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                        logDbg("updateConfigurationHistory got " + config.SSID + " nid="
467992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                                + Integer.toString(config.networkId));
468992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle                    }
469f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
47062f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (selected.configKey(true).equals(config.configKey(true))) {
471ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        found = true;
47262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        continue;
47362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
474f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
4752451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // Compare RSSI values so as to evaluate the strength of the user preference
4762451dbcc4f9641df188326215b204b798eb70c46vandwalle                    int order = compareWifiConfigurationsRSSI(config, selected, null);
4772451dbcc4f9641df188326215b204b798eb70c46vandwalle
4782451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (order < -30) {
4792451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Selected configuration is worse than the visible configuration
4802451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // hence register a strong choice so as autojoin cannot override this
4812451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // for instance, the user has select a network
4822451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // with 1 bar over a network with 3 bars...
4832451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 60;
4842451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else if (order < -20) {
4852451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 50;
4862451dbcc4f9641df188326215b204b798eb70c46vandwalle                    } else if (order < -10) {
4872451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 40;
4882f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    } else if (order < 20) {
4892451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Selected configuration is about same or has a slightly better RSSI
4902451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // hence register a weaker choice, here a difference of at least +/-30 in
4912451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // RSSI comparison triggered by autoJoin will override the choice
4922451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 30;
4932f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    } else {
4942451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // Selected configuration is better than the visible configuration
4952451dbcc4f9641df188326215b204b798eb70c46vandwalle                        // hence we do not know if the user prefers this configuration strongly
4962451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = 20;
49762f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
498f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
499931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // The selected configuration was preferred over a recently seen config
500931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // hence remember the user's choice:
501931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // add the recently seen config to the selected's connectChoices array
502ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
503ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    if (selected.connectChoices == null) {
504ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        selected.connectChoices = new HashMap<String, Integer>();
505ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    }
506ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle
507ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                    logDbg("updateConfigurationHistory add a choice " + selected.configKey(true)
5080888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                            + " over " + config.configKey(true)
5092451dbcc4f9641df188326215b204b798eb70c46vandwalle                            + " choice " + Integer.toString(choice));
510cf5b8eb8a08c45bd4a82f1f4bb789c8a1b08744fvandwalle
5112451dbcc4f9641df188326215b204b798eb70c46vandwalle                    Integer currentChoice = selected.connectChoices.get(config.configKey(true));
5122f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    if (currentChoice != null) {
5132f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // User has made this choice multiple time in a row, so bump up a lot
5142f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        choice += currentChoice.intValue();
5152451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
5162f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // Add the visible config to the selected's connect choice list
5172f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    selected.connectChoices.put(config.configKey(true), choice);
518f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
51962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (config.connectChoices != null) {
520ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        if (VDBG) {
521ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                            logDbg("updateConfigurationHistory will remove "
52262f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                    + selected.configKey(true) + " from " + config.configKey(true));
523ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        }
524931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Remove the selected from the recently seen config's connectChoice list
52562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                        config.connectChoices.remove(selected.configKey(true));
5260888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle
5270888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        if (selected.linkedConfigurations != null) {
528931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                           // Remove the selected's linked configuration from the
529931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                           // recently seen config's connectChoice list
5300888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           for (String key : selected.linkedConfigurations.keySet()) {
5310888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                               config.connectChoices.remove(key);
5320888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                           }
5330888ce6f90bdaeee799dd8361ea4781e23a33b87vandwalle                        }
53462f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    }
535ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                }
536ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                if (found == false) {
5372451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // We haven't found the configuration that the user just selected in our
5382451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // scan cache.
5392451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // In that case we will need a new scan before attempting to connect to this
5402451dbcc4f9641df188326215b204b798eb70c46vandwalle                     // configuration anyhow and thus we can process the scan results then.
541ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                     logDbg("updateConfigurationHistory try to connect to an old network!! : "
542ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                             + selected.configKey());
54362f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
544f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
54562f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                if (selected.connectChoices != null) {
54662f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                    if (VDBG)
547ecd2b88214b5d214fd1f63a9560caff9058912ddvandwalle                        logDbg("updateConfigurationHistory " + Integer.toString(netId)
54862f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                                + " now: " + Integer.toString(selected.connectChoices.size()));
54962f1d0ca8ea4466628f6ff179b1f20e1279fa7e0vandwalle                }
550f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
551f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
552992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle
553931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // TODO: write only if something changed
554992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        if (userTriggered || connect) {
555005c1ef113192f898499a407dd266393a8d6b076vandwalle            mWifiConfigStore.writeKnownNetworkHistory(false);
556992ae00f25a9cc22cf5db3261bd7e72927069cf7vandwalle        }
557f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
558f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
5592451dbcc4f9641df188326215b204b798eb70c46vandwalle    int getConnectChoice(WifiConfiguration source, WifiConfiguration target) {
5602451dbcc4f9641df188326215b204b798eb70c46vandwalle        Integer choice = null;
5612451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (source == null || target == null) {
5622451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
563f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
564f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
5652451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (source.connectChoices != null
5662451dbcc4f9641df188326215b204b798eb70c46vandwalle                && source.connectChoices.containsKey(target.configKey(true))) {
5672451dbcc4f9641df188326215b204b798eb70c46vandwalle            choice = source.connectChoices.get(target.configKey(true));
5682451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else if (source.linkedConfigurations != null) {
569f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            for (String key : source.linkedConfigurations.keySet()) {
570f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(key);
571f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (config != null) {
572f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if (config.connectChoices != null) {
5732451dbcc4f9641df188326215b204b798eb70c46vandwalle                        choice = config.connectChoices.get(target.configKey(true));
574f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
575f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
576f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
5772451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
5782451dbcc4f9641df188326215b204b798eb70c46vandwalle
5792451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (choice == null) {
5802451dbcc4f9641df188326215b204b798eb70c46vandwalle            //We didn't find the connect choice
5812451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
5822451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else {
5832451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice.intValue() < 0) {
5842451dbcc4f9641df188326215b204b798eb70c46vandwalle                choice = 20; // Compatibility with older files
5852451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
5862451dbcc4f9641df188326215b204b798eb70c46vandwalle            return choice.intValue();
5872451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
5882451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
5892451dbcc4f9641df188326215b204b798eb70c46vandwalle
590815788ba7838fc54310baed3deb9b95548e0ce69vandwalle    int compareWifiConfigurationsFromVisibility(WifiConfiguration a, int aRssiBoost,
591815788ba7838fc54310baed3deb9b95548e0ce69vandwalle             WifiConfiguration b, int bRssiBoost) {
5922451dbcc4f9641df188326215b204b798eb70c46vandwalle
593815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        int aRssiBoost5 = 0; // 5GHz RSSI boost to apply for purpose band selection (5GHz pref)
594815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        int bRssiBoost5 = 0; // 5GHz RSSI boost to apply for purpose band selection (5GHz pref)
595815788ba7838fc54310baed3deb9b95548e0ce69vandwalle
596815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        int aScore = 0;
597815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        int bScore = 0;
598815788ba7838fc54310baed3deb9b95548e0ce69vandwalle
599815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        boolean aPrefers5GHz = false;
600815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        boolean bPrefers5GHz = false;
6014dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
6022451dbcc4f9641df188326215b204b798eb70c46vandwalle        /**
603815788ba7838fc54310baed3deb9b95548e0ce69vandwalle         * Calculate a boost to apply to RSSI value of configuration we want to join on 5GHz:
604815788ba7838fc54310baed3deb9b95548e0ce69vandwalle         * Boost RSSI value of 5GHz bands iff the base value is better than threshold,
605815788ba7838fc54310baed3deb9b95548e0ce69vandwalle         * penalize the RSSI value of 5GHz band iff the base value is lower than threshold
6062451dbcc4f9641df188326215b204b798eb70c46vandwalle         * This implements band preference where we prefer 5GHz if RSSI5 is good enough, whereas
6072451dbcc4f9641df188326215b204b798eb70c46vandwalle         * we prefer 2.4GHz otherwise.
6082451dbcc4f9641df188326215b204b798eb70c46vandwalle         */
609815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        aRssiBoost5 = rssiBoostFrom5GHzRssi(a.visibility.rssi5, a.configKey() + "->");
610815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        bRssiBoost5 = rssiBoostFrom5GHzRssi(b.visibility.rssi5, b.configKey() + "->");
6112451dbcc4f9641df188326215b204b798eb70c46vandwalle
612815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        // Select which band to use for a
613f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle        if (a.visibility.rssi5 + aRssiBoost5 > a.visibility.rssi24) {
6142451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Prefer a's 5GHz
615815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            aPrefers5GHz = true;
616815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        }
617815788ba7838fc54310baed3deb9b95548e0ce69vandwalle
618815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        // Select which band to use for b
619815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        if (b.visibility.rssi5 + bRssiBoost5 > b.visibility.rssi24) {
620815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            // Prefer b's 5GHz
621815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            bPrefers5GHz = true;
622815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        }
623815788ba7838fc54310baed3deb9b95548e0ce69vandwalle
624815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        if (aPrefers5GHz) {
625815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            if (bPrefers5GHz) {
626815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // If both a and b are on 5GHz then we don't apply the 5GHz RSSI boost to either
627815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // one, but directly compare the RSSI values, this improves stability,
628815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // since the 5GHz RSSI boost can introduce large fluctuations
629815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                aScore = a.visibility.rssi5 + aRssiBoost;
630815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            } else {
631815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // If only a is on 5GHz, then apply the 5GHz preference boost to a
632815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                aScore = a.visibility.rssi5 + aRssiBoost + aRssiBoost5;
633815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            }
6342451dbcc4f9641df188326215b204b798eb70c46vandwalle        } else {
635815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            aScore = a.visibility.rssi24 + aRssiBoost;
636f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
6372451dbcc4f9641df188326215b204b798eb70c46vandwalle
638815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        if (bPrefers5GHz) {
639815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            if (aPrefers5GHz) {
640815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // If both a and b are on 5GHz then we don't apply the 5GHz RSSI boost to either
641815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // one, but directly compare the RSSI values, this improves stability,
642815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // since the 5GHz RSSI boost can introduce large fluctuations
643815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                bScore = b.visibility.rssi5 + bRssiBoost;
644815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            } else {
645815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // If only b is on 5GHz, then apply the 5GHz preference boost to b
646815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                bScore = b.visibility.rssi5 + bRssiBoost + bRssiBoost5;
647815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            }
648815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        } else {
649815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            bScore = b.visibility.rssi24 + bRssiBoost;
650815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        }
651815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        if (VDBG) {
652815788ba7838fc54310baed3deb9b95548e0ce69vandwalle            logDbg("        " + a.configKey() + " is5=" + aPrefers5GHz + " score=" + aScore
653f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    + " " + b.configKey() + " is5=" + bPrefers5GHz + " score=" + bScore);
654815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        }
655f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle
656f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle        // Debug only, record RSSI comparison parameters
657f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle        if (a.visibility != null) {
658f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle            a.visibility.score = aScore;
659f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle            a.visibility.currentNetworkBoost = aRssiBoost;
660f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle            a.visibility.bandPreferenceBoost = aRssiBoost5;
661f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle        }
662f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle        if (b.visibility != null) {
663f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle            b.visibility.score = bScore;
664f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle            b.visibility.currentNetworkBoost = bRssiBoost;
665f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle            b.visibility.bandPreferenceBoost = bRssiBoost5;
666f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle        }
667f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle
668815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        // Compare a and b
669815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        // If a score is higher then a > b and the order is descending (negative)
670815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        // If b score is higher then a < b and the order is ascending (positive)
671815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        return bScore - aScore;
672f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
673f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
6742451dbcc4f9641df188326215b204b798eb70c46vandwalle    // Compare WifiConfiguration by RSSI, and return a comparison value in the range [-50, +50]
6752451dbcc4f9641df188326215b204b798eb70c46vandwalle    // The result represents "approximately" an RSSI difference measured in dBM
6762451dbcc4f9641df188326215b204b798eb70c46vandwalle    // Adjusted with various parameters:
6772451dbcc4f9641df188326215b204b798eb70c46vandwalle    // +) current network gets a +15 boost
6782451dbcc4f9641df188326215b204b798eb70c46vandwalle    // +) 5GHz signal, if they are strong enough, get a +15 or +25 boost, representing the
6792451dbcc4f9641df188326215b204b798eb70c46vandwalle    // fact that at short range we prefer 5GHz band as it is cleaner of interference and
6802451dbcc4f9641df188326215b204b798eb70c46vandwalle    // provides for wider channels
6812451dbcc4f9641df188326215b204b798eb70c46vandwalle    int compareWifiConfigurationsRSSI(WifiConfiguration a, WifiConfiguration b,
6822451dbcc4f9641df188326215b204b798eb70c46vandwalle                                      String currentConfiguration) {
683f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
6842451dbcc4f9641df188326215b204b798eb70c46vandwalle
6852451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Boost used so as to favor current config
6862451dbcc4f9641df188326215b204b798eb70c46vandwalle        int aRssiBoost = 0;
6872451dbcc4f9641df188326215b204b798eb70c46vandwalle        int bRssiBoost = 0;
6882451dbcc4f9641df188326215b204b798eb70c46vandwalle
6892451dbcc4f9641df188326215b204b798eb70c46vandwalle        int scoreA;
6902451dbcc4f9641df188326215b204b798eb70c46vandwalle        int scoreB;
6912451dbcc4f9641df188326215b204b798eb70c46vandwalle
6922451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Retrieve the visibility
693f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility astatus = a.visibility;
694f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration.Visibility bstatus = b.visibility;
695f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (astatus == null || bstatus == null) {
6962451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Error visibility wasn't set
697b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurations NULL band status!");
698f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            return 0;
699f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
7002451dbcc4f9641df188326215b204b798eb70c46vandwalle
7012451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply Hysteresis, boost RSSI of current configuration
7022451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (null != currentConfiguration) {
7032451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (a.configKey().equals(currentConfiguration)) {
70493a1fddee50a244d31036cddae6b7db6630fd93dvandwalle                aRssiBoost = mWifiConfigStore.currentNetworkBoost;
7052451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (b.configKey().equals(currentConfiguration)) {
70693a1fddee50a244d31036cddae6b7db6630fd93dvandwalle                bRssiBoost = mWifiConfigStore.currentNetworkBoost;
7072451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
7082451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
7092451dbcc4f9641df188326215b204b798eb70c46vandwalle
7102451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG)  {
711b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurationsRSSI: " + a.configKey()
712f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    + " rssi=" + Integer.toString(astatus.rssi24)
713c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + "," + Integer.toString(astatus.rssi5)
7142451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " boost=" + Integer.toString(aRssiBoost)
715f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    + " " + b.configKey() + " rssi="
716c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + Integer.toString(bstatus.rssi24) + ","
717c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    + Integer.toString(bstatus.rssi5)
7182451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " boost=" + Integer.toString(bRssiBoost)
7192451dbcc4f9641df188326215b204b798eb70c46vandwalle            );
720f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
7212451dbcc4f9641df188326215b204b798eb70c46vandwalle
722815788ba7838fc54310baed3deb9b95548e0ce69vandwalle        order = compareWifiConfigurationsFromVisibility(a, aRssiBoost, b, bRssiBoost);
7232451dbcc4f9641df188326215b204b798eb70c46vandwalle
7242451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Normalize the order to [-50, +50]
7252451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (order > 50) order = 50;
7262451dbcc4f9641df188326215b204b798eb70c46vandwalle        else if (order < -50) order = -50;
7272451dbcc4f9641df188326215b204b798eb70c46vandwalle
7282451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
7292451dbcc4f9641df188326215b204b798eb70c46vandwalle            String prefer = " = ";
7302451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (order > 0) {
7312451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " < "; // Ascending
7322451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (order < 0) {
7332451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " > "; // Descending
7342451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
735b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurationsRSSI " + a.configKey()
7362451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + a.visibility.rssi24
7372451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.rssi5
7382451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + a.visibility.num24
7392451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.num5 + ")"
7402451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + prefer + b.configKey()
7412451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + b.visibility.rssi24
7422451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.rssi5
7432451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + b.visibility.num24
7442451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.num5 + ")"
7452451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " -> " + order);
7462451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
7472451dbcc4f9641df188326215b204b798eb70c46vandwalle
748f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
749f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
750f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
751833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle    /**
752833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle     * b/18490330 only use scorer for untrusted networks
753833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle     *
7542451dbcc4f9641df188326215b204b798eb70c46vandwalle    int compareWifiConfigurationsWithScorer(WifiConfiguration a, WifiConfiguration b) {
7552451dbcc4f9641df188326215b204b798eb70c46vandwalle
75681c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson        boolean aIsActive = false;
75781c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson        boolean bIsActive = false;
7582451dbcc4f9641df188326215b204b798eb70c46vandwalle
7592451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply Hysteresis : boost RSSI of current configuration before
7602451dbcc4f9641df188326215b204b798eb70c46vandwalle        // looking up the score
7612451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (null != mCurrentConfigurationKey) {
7622451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (a.configKey().equals(mCurrentConfigurationKey)) {
76381c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                aIsActive = true;
7642451dbcc4f9641df188326215b204b798eb70c46vandwalle            } else if (b.configKey().equals(mCurrentConfigurationKey)) {
76581c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                bIsActive = true;
7662451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
7672451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
768833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle        int scoreA = getConfigNetworkScore(a, mScanResultAutoJoinAge, aIsActive);
769833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle        int scoreB = getConfigNetworkScore(b, mScanResultAutoJoinAge, bIsActive);
7702451dbcc4f9641df188326215b204b798eb70c46vandwalle
7712451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Both configurations need to have a score for the scorer to be used
7722451dbcc4f9641df188326215b204b798eb70c46vandwalle        // ...and the scores need to be different:-)
7732451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (scoreA == WifiNetworkScoreCache.INVALID_NETWORK_SCORE
7742451dbcc4f9641df188326215b204b798eb70c46vandwalle                || scoreB == WifiNetworkScoreCache.INVALID_NETWORK_SCORE) {
775e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            if (VDBG)  {
776b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    compareWifiConfigurationsWithScorer no-scores: "
777e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                        + a.configKey()
778e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                        + " "
779e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                        + b.configKey());
780e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle            }
7812451dbcc4f9641df188326215b204b798eb70c46vandwalle            return 0;
7822451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
7832451dbcc4f9641df188326215b204b798eb70c46vandwalle
7842451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
7852451dbcc4f9641df188326215b204b798eb70c46vandwalle            String prefer = " = ";
7862451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (scoreA < scoreB) {
7872451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " < ";
7882451dbcc4f9641df188326215b204b798eb70c46vandwalle            } if (scoreA > scoreB) {
7892451dbcc4f9641df188326215b204b798eb70c46vandwalle                prefer = " > ";
7902451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
791b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("    compareWifiConfigurationsWithScorer " + a.configKey()
7922451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + a.visibility.rssi24
7932451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.rssi5
7942451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + a.visibility.num24
7952451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + a.visibility.num5 + ")"
796e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    + " sc=" + scoreA
7972451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + prefer + b.configKey()
7982451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " rssi=(" + b.visibility.rssi24
7992451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.rssi5
8002451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + ") num=(" + b.visibility.num24
8012451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + "," + b.visibility.num5 + ")"
802e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                    + " sc=" + scoreB
8032451dbcc4f9641df188326215b204b798eb70c46vandwalle                    + " -> " + Integer.toString(scoreB - scoreA));
8042451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
805c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
8062451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If scoreA > scoreB, the comparison is descending hence the return value is negative
8072451dbcc4f9641df188326215b204b798eb70c46vandwalle        return scoreB - scoreA;
8082451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
809833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle     */
8102451dbcc4f9641df188326215b204b798eb70c46vandwalle
811f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    int compareWifiConfigurations(WifiConfiguration a, WifiConfiguration b) {
812f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        int order = 0;
813f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        boolean linked = false;
814f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
815453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if ((a.linkedConfigurations != null) && (b.linkedConfigurations != null)
816453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (a.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)
817453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                && (b.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)) {
8182451dbcc4f9641df188326215b204b798eb70c46vandwalle            if ((a.linkedConfigurations.get(b.configKey(true)) != null)
8192451dbcc4f9641df188326215b204b798eb70c46vandwalle                    && (b.linkedConfigurations.get(a.configKey(true)) != null)) {
820f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                linked = true;
821f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
822f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
823f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
824f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (a.ephemeral && b.ephemeral == false) {
825f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
826b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    compareWifiConfigurations ephemeral and prefers " + b.configKey()
827453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + a.configKey());
828f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
829931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            return 1; // b is of higher priority - ascending
830f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
831f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (b.ephemeral && a.ephemeral == false) {
832f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (VDBG) {
833b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    compareWifiConfigurations ephemeral and prefers " + a.configKey()
834453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + " over " + b.configKey());
835f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
836931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            return -1; // a is of higher priority - descending
837f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
838f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
8392451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Apply RSSI, in the range [-5, +5]
8402451dbcc4f9641df188326215b204b798eb70c46vandwalle        // after band adjustment, +n difference roughly corresponds to +10xn dBm
8412451dbcc4f9641df188326215b204b798eb70c46vandwalle        order = order + compareWifiConfigurationsRSSI(a, b, mCurrentConfigurationKey);
842f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
8432451dbcc4f9641df188326215b204b798eb70c46vandwalle        // If the configurations are not linked, compare by user's choice, only a
8442451dbcc4f9641df188326215b204b798eb70c46vandwalle        // very high RSSI difference can then override the choice
8452451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (!linked) {
8462451dbcc4f9641df188326215b204b798eb70c46vandwalle            int choice;
847f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
8482451dbcc4f9641df188326215b204b798eb70c46vandwalle            choice = getConnectChoice(a, b);
8492451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice > 0) {
850931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of higher priority - descending
8512451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = order - choice;
852f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG) {
853b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers " + a.configKey()
854453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + " over " + b.configKey()
855b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " due to user choice of " + choice
856b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " order -> " + Integer.toString(order));
857f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
858f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                if (a.visibility != null) {
859f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    a.visibility.lastChoiceBoost = choice;
860f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    a.visibility.lastChoiceConfig = b.configKey();
861f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                }
8622451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
8632451dbcc4f9641df188326215b204b798eb70c46vandwalle
8642451dbcc4f9641df188326215b204b798eb70c46vandwalle            choice = getConnectChoice(b, a);
8652451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (choice > 0) {
866931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of lower priority - ascending
8672451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = order + choice;
8684dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                if (VDBG) {
869b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers " + b.configKey() + " over "
870b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + a.configKey() + " due to user choice of " + choice
871b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " order ->" + Integer.toString(order));
872f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
873f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                if (b.visibility != null) {
874f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    b.visibility.lastChoiceBoost = choice;
875f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                    b.visibility.lastChoiceConfig = a.configKey();
876f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                }
877f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
878f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
879ede1310be531a84faa08f02c3fd243448dd936ddvandwalle
880f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (order == 0) {
881931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // We don't know anything - pick the last seen i.e. K behavior
882931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // we should do this only for recently picked configurations
883f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (a.priority > b.priority) {
884931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of higher priority - descending
8852451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (VDBG) {
886b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers -1 " + a.configKey() + " over "
887453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + b.configKey() + " due to priority");
888f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
889f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
890f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                order = -1;
891f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else if (a.priority < b.priority) {
892931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // a is of lower priority - ascending
8932451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (VDBG) {
894b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    logDbg("    compareWifiConfigurations prefers +1 " + b.configKey() + " over "
895453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                            + a.configKey() + " due to priority");
896f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
8972451dbcc4f9641df188326215b204b798eb70c46vandwalle                order = 1;
898f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
899f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
900f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
901f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String sorder = " == ";
902931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        if (order > 0) {
903f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " < ";
904931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        } else if (order < 0) {
905f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            sorder = " > ";
906931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        }
907f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
9082451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (VDBG) {
909b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("compareWifiConfigurations: " + a.configKey() + sorder
910453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    + b.configKey() + " order " + Integer.toString(order));
911f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
912f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
913f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        return order;
914f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
915f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
916c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    boolean isBadCandidate(int rssi5, int rssi24) {
917c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        return (rssi5 < -80 && rssi24 < -90);
918c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle    }
919c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
920833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle    /*
921c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    int compareWifiConfigurationsTop(WifiConfiguration a, WifiConfiguration b) {
922c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        int scorerOrder = compareWifiConfigurationsWithScorer(a, b);
923c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        int order = compareWifiConfigurations(a, b);
924c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
925c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        if (scorerOrder * order < 0) {
926b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (VDBG) {
927b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    -> compareWifiConfigurationsTop: " +
928b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                        "scorer override " + scorerOrder + " " + order);
929b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
930c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // For debugging purpose, remember that an override happened
931c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // during that autojoin Attempt
932c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            didOverride = true;
933c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            a.numScorerOverride++;
934c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            b.numScorerOverride++;
935c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        }
936c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
937c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        if (scorerOrder != 0) {
938c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // If the scorer came up with a result then use the scorer's result, else use
939c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            // the order provided by the base comparison function
940c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle            order = scorerOrder;
941c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        }
942c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        return order;
943c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle    }
944833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle    */
945c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle
9469f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle    public int rssiBoostFrom5GHzRssi(int rssi, String dbg) {
9470eebae7334d6129f7ca1344e4b20199794994358vandwalle        if (!mWifiConfigStore.enable5GHzPreference) {
9480eebae7334d6129f7ca1344e4b20199794994358vandwalle            return 0;
9490eebae7334d6129f7ca1344e4b20199794994358vandwalle        }
950e67ec726c07410073575473c0f50dc737629f5davandwalle        if (rssi
9510eebae7334d6129f7ca1344e4b20199794994358vandwalle                > mWifiConfigStore.bandPreferenceBoostThreshold5) {
952e67ec726c07410073575473c0f50dc737629f5davandwalle            // Boost by 2 dB for each point
953e67ec726c07410073575473c0f50dc737629f5davandwalle            //    Start boosting at -65
954e67ec726c07410073575473c0f50dc737629f5davandwalle            //    Boost by 20 if above -55
955e67ec726c07410073575473c0f50dc737629f5davandwalle            //    Boost by 40 if abore -45
9560eebae7334d6129f7ca1344e4b20199794994358vandwalle            int boost = mWifiConfigStore.bandPreferenceBoostFactor5
9570eebae7334d6129f7ca1344e4b20199794994358vandwalle                    *(rssi - mWifiConfigStore.bandPreferenceBoostThreshold5);
958e67ec726c07410073575473c0f50dc737629f5davandwalle            if (boost > 50) {
959815788ba7838fc54310baed3deb9b95548e0ce69vandwalle                // 50 dB boost allows jumping from 2.4 to 5GHz
960e67ec726c07410073575473c0f50dc737629f5davandwalle                // consistently
961e67ec726c07410073575473c0f50dc737629f5davandwalle                boost = 50;
962e67ec726c07410073575473c0f50dc737629f5davandwalle            }
9639f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            if (VDBG && dbg != null) {
964f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                logDbg("        " + dbg + ":    rssi5 " + rssi + " 5GHz-boost " + boost);
9659f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            }
966e67ec726c07410073575473c0f50dc737629f5davandwalle            return boost;
967e67ec726c07410073575473c0f50dc737629f5davandwalle        }
968e67ec726c07410073575473c0f50dc737629f5davandwalle
969e67ec726c07410073575473c0f50dc737629f5davandwalle        if (rssi
9700eebae7334d6129f7ca1344e4b20199794994358vandwalle                < mWifiConfigStore.bandPreferencePenaltyThreshold5) {
9710eebae7334d6129f7ca1344e4b20199794994358vandwalle            // penalize if < -75
9720eebae7334d6129f7ca1344e4b20199794994358vandwalle            int boost = mWifiConfigStore.bandPreferencePenaltyFactor5
9730eebae7334d6129f7ca1344e4b20199794994358vandwalle                    *(rssi - mWifiConfigStore.bandPreferencePenaltyThreshold5);
9740eebae7334d6129f7ca1344e4b20199794994358vandwalle            return boost;
975e67ec726c07410073575473c0f50dc737629f5davandwalle        }
976e67ec726c07410073575473c0f50dc737629f5davandwalle        return 0;
977e67ec726c07410073575473c0f50dc737629f5davandwalle    }
978c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        /**
979e67ec726c07410073575473c0f50dc737629f5davandwalle         * attemptRoam() function implements the core of the same SSID switching algorithm
980e67ec726c07410073575473c0f50dc737629f5davandwalle         *
981e67ec726c07410073575473c0f50dc737629f5davandwalle         * Run thru all recent scan result of a WifiConfiguration and select the
982e67ec726c07410073575473c0f50dc737629f5davandwalle         * best one.
983c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle         */
984e67ec726c07410073575473c0f50dc737629f5davandwalle    public ScanResult attemptRoam(ScanResult a,
985e67ec726c07410073575473c0f50dc737629f5davandwalle                                  WifiConfiguration current, int age, String currentBSSID) {
986b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current == null) {
987b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
988b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam not associated");
989b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
990e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
9914dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
992b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (current.scanResultCache == null) {
993b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
994b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("attemptRoam no scan cache");
995b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
996e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
9974dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
998b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle        if (current.scanResultCache.size() > 6) {
999b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (VDBG)   {
1000c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                logDbg("attemptRoam scan cache size "
1001c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + current.scanResultCache.size() + " --> bail");
1002b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
1003931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Implement same SSID roaming only for configurations
1004c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            // that have less than 4 BSSIDs
1005e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
10064dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
1007b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
10082f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle        if (current.BSSID != null && !current.BSSID.equals("any")) {
1009b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (DBG)   {
10102f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                logDbg("attemptRoam() BSSID is set "
10112f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        + current.BSSID + " -> bail");
1012b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            }
1013e67ec726c07410073575473c0f50dc737629f5davandwalle            return a;
10144dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
10154dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1016931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Determine which BSSID we want to associate to, taking account
1017c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle        // relative strength of 5 and 2.4 GHz BSSIDs
10182451dbcc4f9641df188326215b204b798eb70c46vandwalle        long nowMs = System.currentTimeMillis();
10194dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
102097b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle        for (ScanResult b : current.scanResultCache.values()) {
102197b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int bRssiBoost5 = 0;
102297b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int aRssiBoost5 = 0;
102397b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int bRssiBoost = 0;
102497b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            int aRssiBoost = 0;
1025931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            if ((b.seen == 0) || (b.BSSID == null)
10260d616ef3bf635dff8722e064c0be842676390ed8vandwalle                    || ((nowMs - b.seen) > age)
1027e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    || b.autoJoinStatus != ScanResult.ENABLED
1028e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    || b.numIpConfigFailures > 8) {
10294dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                continue;
10303a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
10314dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1032931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Pick first one
10334dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (a == null) {
10344dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                a = b;
10354dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                continue;
10364dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
10374dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1038e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            if (b.numIpConfigFailures < (a.numIpConfigFailures - 1)) {
1039e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                // Prefer a BSSID that doesn't have less number of Ip config failures
1040e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("attemptRoam: "
1041e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + b.BSSID + " rssi=" + b.level + " ipfail=" +b.numIpConfigFailures
1042e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " freq=" + b.frequency
1043e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " > "
1044e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + a.BSSID + " rssi=" + a.level + " ipfail=" +a.numIpConfigFailures
1045e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " freq=" + a.frequency);
1046e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                a = b;
1047e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                continue;
1048e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle            }
1049e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle
10502451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Apply hysteresis: we favor the currentBSSID by giving it a boost
10517806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            if (currentBSSID != null && currentBSSID.equals(b.BSSID)) {
1052931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Reduce the benefit of hysteresis if RSSI <= -75
10530eebae7334d6129f7ca1344e4b20199794994358vandwalle                if (b.level <= mWifiConfigStore.bandPreferencePenaltyThreshold5) {
10540eebae7334d6129f7ca1344e4b20199794994358vandwalle                    bRssiBoost = mWifiConfigStore.associatedHysteresisLow;
1055c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                } else {
10560eebae7334d6129f7ca1344e4b20199794994358vandwalle                    bRssiBoost = mWifiConfigStore.associatedHysteresisHigh;
1057c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
10584dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
10597806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            if (currentBSSID != null && currentBSSID.equals(a.BSSID)) {
10600eebae7334d6129f7ca1344e4b20199794994358vandwalle                if (a.level <= mWifiConfigStore.bandPreferencePenaltyThreshold5) {
1061931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // Reduce the benefit of hysteresis if RSSI <= -75
10620eebae7334d6129f7ca1344e4b20199794994358vandwalle                    aRssiBoost = mWifiConfigStore.associatedHysteresisLow;
1063c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                } else {
10640eebae7334d6129f7ca1344e4b20199794994358vandwalle                    aRssiBoost = mWifiConfigStore.associatedHysteresisHigh;
1065c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
10664dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
10672451dbcc4f9641df188326215b204b798eb70c46vandwalle
106897b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            // Favor 5GHz: give a boost to 5GHz BSSIDs, with a slightly progressive curve
10692451dbcc4f9641df188326215b204b798eb70c46vandwalle            //   Boost the BSSID if it is on 5GHz, above a threshold
10702451dbcc4f9641df188326215b204b798eb70c46vandwalle            //   But penalize it if it is on 5GHz and below threshold
107197b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //
107297b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //   With he current threshold values, 5GHz network with RSSI above -55
107397b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //   Are given a boost of 30DB which is enough to overcome the current BSSID
107497b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle            //   hysteresis (+14) plus 2.4/5 GHz signal strength difference on most cases
10759f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            //
10769f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // The "current BSSID" Boost must be added to the BSSID's level so as to introduce\
10779f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle            // soem amount of hysteresis
1078e67ec726c07410073575473c0f50dc737629f5davandwalle            if (b.is5GHz()) {
10799f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                bRssiBoost5 = rssiBoostFrom5GHzRssi(b.level + bRssiBoost, b.BSSID);
10804dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
1081e67ec726c07410073575473c0f50dc737629f5davandwalle            if (a.is5GHz()) {
10829f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                aRssiBoost5 = rssiBoostFrom5GHzRssi(a.level + aRssiBoost, a.BSSID);
10834dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
10844dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
10854dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            if (VDBG)  {
1086c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                String comp = " < ";
1087c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                if (b.level + bRssiBoost + bRssiBoost5 > a.level +aRssiBoost + aRssiBoost5) {
1088c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    comp = " > ";
1089c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                }
10904dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                logDbg("attemptRoam: "
1091c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + b.BSSID + " rssi=" + b.level + " boost=" + Integer.toString(bRssiBoost)
109297b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle                        + "/" + Integer.toString(bRssiBoost5) + " freq=" + b.frequency
109397b9c4fef6e372d1f19b333c7a67ff27ef80baf0vandwalle                        + comp
1094c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + a.BSSID + " rssi=" + a.level + " boost=" + Integer.toString(aRssiBoost)
1095c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + "/" + Integer.toString(aRssiBoost5) + " freq=" + a.frequency);
1096c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            }
1097c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle
10982451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Compare the RSSIs after applying the hysteresis boost and the 5GHz
10992451dbcc4f9641df188326215b204b798eb70c46vandwalle            // boost if applicable
1100c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle            if (b.level + bRssiBoost + bRssiBoost5 > a.level +aRssiBoost + aRssiBoost5) {
1101931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // b is the better BSSID
1102c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                a = b;
11034dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
11044dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
11053a2a3d226881cce8a4e511302231d843b0def303vandwalle        if (a != null) {
11063a2a3d226881cce8a4e511302231d843b0def303vandwalle            if (VDBG)  {
11077806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                StringBuilder sb = new StringBuilder();
1108e67ec726c07410073575473c0f50dc737629f5davandwalle                sb.append("attemptRoam: " + current.configKey() +
1109e67ec726c07410073575473c0f50dc737629f5davandwalle                        " Found " + a.BSSID + " rssi=" + a.level + " freq=" + a.frequency);
11107806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                if (currentBSSID != null) {
11117806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                    sb.append(" Current: " + currentBSSID);
11127806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                }
11137806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                sb.append("\n");
11147806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle                logDbg(sb.toString());
11153a2a3d226881cce8a4e511302231d843b0def303vandwalle            }
11164dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle        }
11173a2a3d226881cce8a4e511302231d843b0def303vandwalle        return a;
11184dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle    }
11194dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1120931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle    /**
11212451dbcc4f9641df188326215b204b798eb70c46vandwalle     * getNetworkScore()
11222451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
11232451dbcc4f9641df188326215b204b798eb70c46vandwalle     * if scorer is present, get the network score of a WifiConfiguration
11242451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
11252451dbcc4f9641df188326215b204b798eb70c46vandwalle     * Note: this should be merge with setVisibility
11262451dbcc4f9641df188326215b204b798eb70c46vandwalle     *
11272451dbcc4f9641df188326215b204b798eb70c46vandwalle     * @param config
11282451dbcc4f9641df188326215b204b798eb70c46vandwalle     * @return score
11292451dbcc4f9641df188326215b204b798eb70c46vandwalle     */
113081c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson    int getConfigNetworkScore(WifiConfiguration config, int age, boolean isActive) {
11312451dbcc4f9641df188326215b204b798eb70c46vandwalle
11322451dbcc4f9641df188326215b204b798eb70c46vandwalle        if (mNetworkScoreCache == null) {
1133e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            if (VDBG) {
1134b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("       getConfigNetworkScore for " + config.configKey()
1135e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + "  -> no scorer, hence no scores");
1136e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            }
11371db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle            return WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
11381db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        }
11391db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        if (config.scanResultCache == null) {
1140e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            if (VDBG) {
1141b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("       getConfigNetworkScore for " + config.configKey()
1142e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " -> no scan cache");
1143e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            }
11441db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle            return WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
11452451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
11462451dbcc4f9641df188326215b204b798eb70c46vandwalle
11472451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Get current date
11482451dbcc4f9641df188326215b204b798eb70c46vandwalle        long nowMs = System.currentTimeMillis();
11492451dbcc4f9641df188326215b204b798eb70c46vandwalle
11501db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        int startScore = -10000;
11511db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle
11522451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Run thru all cached scan results
11531db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        for (ScanResult result : config.scanResultCache.values()) {
11542451dbcc4f9641df188326215b204b798eb70c46vandwalle            if ((nowMs - result.seen) < age) {
115581c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                int sc = mNetworkScoreCache.getNetworkScore(result, isActive);
11561db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle                if (sc > startScore) {
11571db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle                    startScore = sc;
11582451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
11592451dbcc4f9641df188326215b204b798eb70c46vandwalle            }
11602451dbcc4f9641df188326215b204b798eb70c46vandwalle        }
11611db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        if (startScore == -10000) {
11621db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle            startScore = WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
11631db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        }
1164e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle        if (VDBG) {
1165e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            if (startScore == WifiNetworkScoreCache.INVALID_NETWORK_SCORE) {
1166b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    getConfigNetworkScore for " + config.configKey()
1167e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " -> no available score");
1168e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            } else {
1169b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                logDbg("    getConfigNetworkScore for " + config.configKey()
117081c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                        + " isActive=" + isActive
1171e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle                        + " score = " + Integer.toString(startScore));
1172e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle            }
1173e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle        }
1174e6574ec7b6b2e7a678da7f77bdaaf31463852b2fvandwalle
11751db63db890fcb9051f402fdfd449eb0b80e2053cvandwalle        return startScore;
11762451dbcc4f9641df188326215b204b798eb70c46vandwalle    }
11772451dbcc4f9641df188326215b204b798eb70c46vandwalle
11782451dbcc4f9641df188326215b204b798eb70c46vandwalle    /**
11798639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson     * Set whether connections to untrusted connections are allowed.
11808639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson     */
11818639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    void setAllowUntrustedConnections(boolean allow) {
11828639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        boolean changed = mAllowUntrustedConnections != allow;
11838639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        mAllowUntrustedConnections = allow;
11848639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        if (changed) {
1185005c1ef113192f898499a407dd266393a8d6b076vandwalle            // Trigger a scan so as to reattempt autojoin
1186005c1ef113192f898499a407dd266393a8d6b076vandwalle            mWifiStateMachine.startScanForUntrustedSettingChange();
11878639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        }
11888639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    }
11898639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson
11908639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    private boolean isOpenNetwork(ScanResult result) {
11918639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson        return !result.capabilities.contains("WEP") &&
11928639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                !result.capabilities.contains("PSK") &&
11938639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                !result.capabilities.contains("EAP");
11948639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    }
11958639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson
119616fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson    private boolean haveRecentlySeenScoredBssid(WifiConfiguration config) {
119716fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        long ephemeralOutOfRangeTimeoutMs = Settings.Global.getLong(
119816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                mContext.getContentResolver(),
119916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                Settings.Global.WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS,
120016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                DEFAULT_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS);
120116fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
120216fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        // Check whether the currently selected network has a score curve. If
120316fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        // ephemeralOutOfRangeTimeoutMs is <= 0, then this is all we check, and we stop here.
120416fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        // Otherwise, we stop here if the currently selected network has a score. If it doesn't, we
120516fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        // keep going - it could be that another BSSID is in range (has been seen recently) which
120616fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        // has a score, even if the one we're immediately connected to doesn't.
120716fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        ScanResult currentScanResult =  mWifiStateMachine.getCurrentScanResult();
120816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        boolean currentNetworkHasScoreCurve = mNetworkScoreCache.hasScoreCurve(currentScanResult);
120916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        if (ephemeralOutOfRangeTimeoutMs <= 0 || currentNetworkHasScoreCurve) {
121016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            if (DBG) {
121116fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                if (currentNetworkHasScoreCurve) {
121216fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                    logDbg("Current network has a score curve, keeping network: "
121316fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                            + currentScanResult);
121416fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                } else {
121516fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                    logDbg("Current network has no score curve, giving up: " + config.SSID);
121616fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                }
121716fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            }
121816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            return currentNetworkHasScoreCurve;
121916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        }
122016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
122116fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        if (config.scanResultCache == null || config.scanResultCache.isEmpty()) {
122216fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            return false;
122316fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        }
122416fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
122516fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        long currentTimeMs = System.currentTimeMillis();
122616fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        for (ScanResult result : config.scanResultCache.values()) {
122716fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            if (currentTimeMs > result.seen
122816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                    && currentTimeMs - result.seen < ephemeralOutOfRangeTimeoutMs
122916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                    && mNetworkScoreCache.hasScoreCurve(result)) {
123016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                if (DBG) {
123116fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                    logDbg("Found scored BSSID, keeping network: " + result.BSSID);
123216fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                }
123316fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                return true;
123416fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            }
123516fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        }
123616fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
123716fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        if (DBG) {
123816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson            logDbg("No recently scored BSSID found, giving up connection: " + config.SSID);
123916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        }
124016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson        return false;
124116fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson    }
124216fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson
12438639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson    /**
1244931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     * attemptAutoJoin() function implements the core of the a network switching algorithm
124568fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle     * Return false if no acceptable networks were found.
1246931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle     */
124768fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle    boolean attemptAutoJoin() {
124868fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle        boolean found = false;
1249c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle        didOverride = false;
12501ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        didBailDueToWeakRssi = false;
1251b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        int networkSwitchType = AUTO_JOIN_IDLE;
12524dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
12538242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle        long now = System.currentTimeMillis();
12548242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle
12558c9088d11880553458f09377cc60d6eb7e66747bvandwalle        String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration();
12568c9088d11880553458f09377cc60d6eb7e66747bvandwalle
1257931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Reset the currentConfiguration Key, and set it only if WifiStateMachine and
1258453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        // supplicant agree
1259453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        mCurrentConfigurationKey = null;
1260453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        WifiConfiguration currentConfiguration = mWifiStateMachine.getCurrentWifiConfiguration();
1261453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
1262f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        WifiConfiguration candidate = null;
1263f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1264931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Obtain the subset of recently seen networks
1265833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle        List<WifiConfiguration> list =
1266833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                mWifiConfigStore.getRecentConfiguredNetworks(mScanResultAutoJoinAge, false);
1267f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (list == null) {
12682f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle            if (VDBG)  logDbg("attemptAutoJoin nothing known=" +
12692f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    mWifiConfigStore.getconfiguredNetworkSize());
127068fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle            return false;
1271f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1272f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1273931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        // Find the currently connected network: ask the supplicant directly
127499d385e3b4d34841d6efcfd7cc9bf1d5ae25de14vandwalle        String val = mWifiNative.status(true);
127549bc8dd35845318cd9bc5ce9064fc1ad33bbece8xinhe
127649bc8dd35845318cd9bc5ce9064fc1ad33bbece8xinhe        if(val == null) {
127749bc8dd35845318cd9bc5ce9064fc1ad33bbece8xinhe            return false;
127849bc8dd35845318cd9bc5ce9064fc1ad33bbece8xinhe        }
127949bc8dd35845318cd9bc5ce9064fc1ad33bbece8xinhe
1280f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        String status[] = val.split("\\r?\\n");
1281f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        if (VDBG) {
1282f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            logDbg("attemptAutoJoin() status=" + val + " split="
1283f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    + Integer.toString(status.length));
1284f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1285f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1286b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        int supplicantNetId = -1;
1287f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for (String key : status) {
1288f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (key.regionMatches(0, "id=", 0, 3)) {
1289f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                int idx = 3;
1290b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                supplicantNetId = 0;
1291f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                while (idx < key.length()) {
1292f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    char c = key.charAt(idx);
1293f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1294f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    if ((c >= 0x30) && (c <= 0x39)) {
1295b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                        supplicantNetId *= 10;
1296b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                        supplicantNetId += c - 0x30;
1297f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        idx++;
1298f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    } else {
1299f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        break;
1300f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
1301f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
130256d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle            } else if (key.contains("wpa_state=ASSOCIATING")
130356d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                    || key.contains("wpa_state=ASSOCIATED")
130456d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                    || key.contains("wpa_state=FOUR_WAY_HANDSHAKE")
130556d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                    || key.contains("wpa_state=GROUP_KEY_HANDSHAKE")) {
130656d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                if (DBG) {
130756d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                    logDbg("attemptAutoJoin: bail out due to sup state " + key);
130856d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                }
130956d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // After WifiStateMachine ask the supplicant to associate or reconnect
131056d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // we might still obtain scan results from supplicant
131156d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // however the supplicant state in the mWifiInfo and supplicant state tracker
131256d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // are updated when we get the supplicant state change message which can be
131356d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // processed after the SCAN_RESULT message, so at this point the framework doesn't
131456d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // know that supplicant is ASSOCIATING.
131556d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // A good fix for this race condition would be for the WifiStateMachine to add
131656d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // a new transient state where it expects to get the supplicant message indicating
131756d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // that it started the association process and within which critical operations
131856d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // like autojoin should be deleted.
131956d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle
132056d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // This transient state would remove the need for the roam Wathchdog which
132156d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // basically does that.
132256d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle
132356d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // At the moment, we just query the supplicant state synchronously with the
132456d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // mWifiNative.status() command, which allow us to know that
132556d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // supplicant has started association process, even though we didnt yet get the
132656d0178183460eed9afbd85e5c0d215e27d5f5bcvandwalle                // SUPPLICANT_STATE_CHANGE message.
132768fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                return false;
1328f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1329f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1330ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        if (DBG) {
13317806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            String conf = "";
1332b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            String last = "";
13337806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            if (currentConfiguration != null) {
1334e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                conf = " current=" + currentConfiguration.configKey();
1335b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1336b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (lastSelectedConfiguration != null) {
13372f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                last = " last=" + lastSelectedConfiguration;
13387806f8c800754da0f76d7a0c1a6a590381dac7a8vandwalle            }
1339ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            logDbg("attemptAutoJoin() num recent config " + Integer.toString(list.size())
1340b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + conf + last
1341b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + " ---> suppNetId=" + Integer.toString(supplicantNetId));
1342ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle        }
1343f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1344453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        if (currentConfiguration != null) {
13452451dbcc4f9641df188326215b204b798eb70c46vandwalle            if (supplicantNetId != currentConfiguration.networkId
1346005c1ef113192f898499a407dd266393a8d6b076vandwalle                    // https://b.corp.google.com/issue?id=16484607
1347005c1ef113192f898499a407dd266393a8d6b076vandwalle                    // mark this condition as an error only if the mismatched networkId are valid
13482451dbcc4f9641df188326215b204b798eb70c46vandwalle                    && supplicantNetId != WifiConfiguration.INVALID_NETWORK_ID
13492451dbcc4f9641df188326215b204b798eb70c46vandwalle                    && currentConfiguration.networkId != WifiConfiguration.INVALID_NETWORK_ID) {
1350453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                logDbg("attemptAutoJoin() ERROR wpa_supplicant out of sync nid="
1351b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                        + Integer.toString(supplicantNetId) + " WifiStateMachine="
1352453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                        + Integer.toString(currentConfiguration.networkId));
1353b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                mWifiStateMachine.disconnectCommand();
135468fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                return false;
13558639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson            } else if (currentConfiguration.ephemeral && (!mAllowUntrustedConnections ||
135616fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                    !haveRecentlySeenScoredBssid(currentConfiguration))) {
13578639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                // The current connection is untrusted (the framework added it), but we're either
135816fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                // no longer allowed to connect to such networks, the score has been nullified
135916fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                // since we connected, or the scored BSSID has gone out of range.
136016fdf07021858fd116d96a5fb00ddb3c166d5ae6Jeff Davidson                // Drop the current connection and perform the rest of autojoin.
13618639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                logDbg("attemptAutoJoin() disconnecting from unwanted ephemeral network");
1362f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                mWifiStateMachine.disconnectCommand(Process.WIFI_UID,
1363f57f8918b8c5872ff4bb141fa9e407bec8442e8dvandwalle                        mAllowUntrustedConnections ? 1 : 0);
136468fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                return false;
1365453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            } else {
1366453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                mCurrentConfigurationKey = currentConfiguration.configKey();
1367453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle            }
13688c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle        } else {
13698c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle            if (supplicantNetId != WifiConfiguration.INVALID_NETWORK_ID) {
13708c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                // Maybe in the process of associating, skip this attempt
137168fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                return false;
13728c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle            }
1373453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle        }
1374453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle
1375b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        int currentNetId = -1;
1376b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (currentConfiguration != null) {
1377931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // If we are associated to a configuration, it will
1378b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            // be compared thru the compareNetwork function
1379b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle            currentNetId = currentConfiguration.networkId;
1380b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        }
1381b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle
1382931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1383931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * Run thru all visible configurations without looking at the one we
1384c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle         * are currently associated to
13854dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle         * select Best Network candidate from known WifiConfigurations
1386931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
1387f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        for (WifiConfiguration config : list) {
1388e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            if (config.SSID == null) {
1389b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                continue;
1390e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle            }
1391e86c962bb99a8b126ed64ddcc6b112161549e26dvandwalle
139227355a942653264388e909a4276196ee63e57811vandwalle            if (config.autoJoinStatus >=
139327355a942653264388e909a4276196ee63e57811vandwalle                    WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
1394abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                // Wait for 5 minutes before reenabling config that have known,
1395abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                // repeated connection or DHCP failures
1396abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                if (config.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE
1397abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        || config.disableReason
1398abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        == WifiConfiguration.DISABLED_ASSOCIATION_REJECT
1399abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        || config.disableReason
1400abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        == WifiConfiguration.DISABLED_AUTH_FAILURE) {
1401abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                    if (config.blackListTimestamp == 0
1402abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                            || (config.blackListTimestamp > now)) {
1403abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        // Sanitize the timestamp
1404abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        config.blackListTimestamp = now;
1405abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                    }
1406abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                    if ((now - config.blackListTimestamp) >
1407abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                            mWifiConfigStore.wifiConfigBlacklistMinTimeMilli) {
1408abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        // Re-enable the WifiConfiguration
1409abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        config.status = WifiConfiguration.Status.ENABLED;
1410abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle
1411abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        // Reset the blacklist condition
1412abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        config.numConnectionFailures = 0;
1413abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        config.numIpConfigFailures = 0;
1414abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        config.numAuthFailures = 0;
1415abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
1416abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle
1417abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        config.dirty = true;
1418abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                    } else {
1419abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        if (VDBG) {
1420abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                            long delay = mWifiConfigStore.wifiConfigBlacklistMinTimeMilli
1421abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                                    - (now - config.blackListTimestamp);
1422abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                            logDbg("attemptautoJoin " + config.configKey()
1423abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                                    + " dont unblacklist yet, waiting for "
1424abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                                    + delay + " ms");
1425abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                        }
1426abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                    }
1427abd1740f753ac14e9dec8fced8d3de5059122c2avandwalle                }
1428931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Avoid networks disabled because of AUTH failure altogether
1429ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
1430ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                    logDbg("attemptAutoJoin skip candidate due to auto join status "
1431ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + Integer.toString(config.autoJoinStatus) + " key "
1432e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                            + config.configKey(true)
14338242cc81341c80ab5bc057ffdad99a3a1d95be5cvandwalle                            + " reason " + config.disableReason);
1434ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
1435f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
1436f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1437f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1438e487a4648dd41881e754f1224aaedead78a0777dSky Faber            if (config.userApproved == WifiConfiguration.USER_PENDING ||
1439e487a4648dd41881e754f1224aaedead78a0777dSky Faber                    config.userApproved == WifiConfiguration.USER_BANNED) {
1440e487a4648dd41881e754f1224aaedead78a0777dSky Faber                if (DBG) {
1441e487a4648dd41881e754f1224aaedead78a0777dSky Faber                    logDbg("attemptAutoJoin skip candidate due to user approval status "
1442e487a4648dd41881e754f1224aaedead78a0777dSky Faber                            + WifiConfiguration.userApprovedAsString(config.userApproved) + " key "
1443e487a4648dd41881e754f1224aaedead78a0777dSky Faber                            + config.configKey(true));
1444e487a4648dd41881e754f1224aaedead78a0777dSky Faber                }
1445e487a4648dd41881e754f1224aaedead78a0777dSky Faber                continue;
1446e487a4648dd41881e754f1224aaedead78a0777dSky Faber            }
1447e487a4648dd41881e754f1224aaedead78a0777dSky Faber
1448931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Try to un-blacklist based on elapsed time
144927355a942653264388e909a4276196ee63e57811vandwalle            if (config.blackListTimestamp > 0) {
145027355a942653264388e909a4276196ee63e57811vandwalle                if (now < config.blackListTimestamp) {
1451931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    /**
1452931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * looks like there was a change in the system clock since we black listed, and
1453931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * timestamp is not meaningful anymore, hence lose it.
1454931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                     * this event should be rare enough so that we still want to lose the black list
14552451dbcc4f9641df188326215b204b798eb70c46vandwalle                     */
145627355a942653264388e909a4276196ee63e57811vandwalle                    config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
145727355a942653264388e909a4276196ee63e57811vandwalle                } else {
14584dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    if ((now - config.blackListTimestamp) > loseBlackListHardMilli) {
1459931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Reenable it after 18 hours, i.e. next day
146027355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
14614dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    } else if ((now - config.blackListTimestamp) > loseBlackListSoftMilli) {
1462931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                        // Lose blacklisting due to bad link
146327355a942653264388e909a4276196ee63e57811vandwalle                        config.setAutoJoinStatus(config.autoJoinStatus - 8);
146427355a942653264388e909a4276196ee63e57811vandwalle                    }
146527355a942653264388e909a4276196ee63e57811vandwalle                }
146627355a942653264388e909a4276196ee63e57811vandwalle            }
146727355a942653264388e909a4276196ee63e57811vandwalle
1468931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Try to unblacklist based on good visibility
14698c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle            if (config.visibility.rssi5 < mWifiConfigStore.thresholdUnblacklistThreshold5Soft
14708c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                    && config.visibility.rssi24
14718c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                    < mWifiConfigStore.thresholdUnblacklistThreshold24Soft) {
147227355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
1473c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    logDbg("attemptAutoJoin do not unblacklist due to low visibility "
14744dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.autoJoinStatus
14754dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " key " + config.configKey(true)
14764dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " rssi=(" + config.visibility.rssi24
14774dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.rssi5
14784dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
14794dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
148027355a942653264388e909a4276196ee63e57811vandwalle                }
14818c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle            } else if (config.visibility.rssi5 < mWifiConfigStore.thresholdUnblacklistThreshold5Hard
14828c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                    && config.visibility.rssi24
14838c0a54e9b0d3713cab52d06ad8fd7f3a1b6f73a8vandwalle                    < mWifiConfigStore.thresholdUnblacklistThreshold24Hard) {
1484931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // If the network is simply temporary disabled, don't allow reconnect until
1485931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // RSSI becomes good enough
148627355a942653264388e909a4276196ee63e57811vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 1);
148727355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
148827355a942653264388e909a4276196ee63e57811vandwalle                    logDbg("attemptAutoJoin good candidate seen, bumped soft -> status="
148927355a942653264388e909a4276196ee63e57811vandwalle                            + config.autoJoinStatus
1490b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " " + config.configKey(true) + " rssi=("
14914dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.visibility.rssi24 + "," + config.visibility.rssi5
14924dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
14934dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
149427355a942653264388e909a4276196ee63e57811vandwalle                }
149527355a942653264388e909a4276196ee63e57811vandwalle            } else {
1496c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                config.setAutoJoinStatus(config.autoJoinStatus - 3);
149727355a942653264388e909a4276196ee63e57811vandwalle                if (DBG) {
149827355a942653264388e909a4276196ee63e57811vandwalle                    logDbg("attemptAutoJoin good candidate seen, bumped hard -> status="
149927355a942653264388e909a4276196ee63e57811vandwalle                            + config.autoJoinStatus
1500b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " " + config.configKey(true) + " rssi=("
15014dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.visibility.rssi24 + "," + config.visibility.rssi5
15024dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
15034dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
150427355a942653264388e909a4276196ee63e57811vandwalle                }
150527355a942653264388e909a4276196ee63e57811vandwalle            }
150627355a942653264388e909a4276196ee63e57811vandwalle
150727355a942653264388e909a4276196ee63e57811vandwalle            if (config.autoJoinStatus >=
150827355a942653264388e909a4276196ee63e57811vandwalle                    WifiConfiguration.AUTO_JOIN_TEMPORARY_DISABLED) {
1509931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                // Network is blacklisted, skip
15104dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                if (DBG) {
15114dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    logDbg("attemptAutoJoin skip blacklisted -> status="
15124dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.autoJoinStatus
1513b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            + " " + config.configKey(true) + " rssi=("
15144dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + config.visibility.rssi24 + "," + config.visibility.rssi5
15154dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + ") num=(" + config.visibility.num24
15164dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + "," + config.visibility.num5 + ")");
15174dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                }
151827355a942653264388e909a4276196ee63e57811vandwalle                continue;
151927355a942653264388e909a4276196ee63e57811vandwalle            }
1520f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (config.networkId == currentNetId) {
1521ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                if (DBG) {
152221bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                    logDbg("attemptAutoJoin skip current candidate  "
152321bc54cb37a0085b1c909cb4d55ebb12a2facefbvandwalle                            + Integer.toString(currentNetId)
1524ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                            + " key " + config.configKey(true));
1525ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle                }
1526f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                continue;
1527f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1528f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
15290eebae7334d6129f7ca1344e4b20199794994358vandwalle            boolean isLastSelected = false;
15300eebae7334d6129f7ca1344e4b20199794994358vandwalle            if (lastSelectedConfiguration != null &&
15310eebae7334d6129f7ca1344e4b20199794994358vandwalle                    config.configKey().equals(lastSelectedConfiguration)) {
15320eebae7334d6129f7ca1344e4b20199794994358vandwalle                isLastSelected = true;
15330eebae7334d6129f7ca1344e4b20199794994358vandwalle            }
15340eebae7334d6129f7ca1344e4b20199794994358vandwalle
15350eebae7334d6129f7ca1344e4b20199794994358vandwalle            if (config.visibility == null) {
15360eebae7334d6129f7ca1344e4b20199794994358vandwalle                continue;
15370eebae7334d6129f7ca1344e4b20199794994358vandwalle            }
15384fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle
15394fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle            if (config.lastRoamingFailure != 0
15404fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                    && currentConfiguration != null
15414fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                    && (lastSelectedConfiguration == null
15424fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                    || !config.configKey().equals(lastSelectedConfiguration))) {
15434fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                // Apply blacklisting for roaming to this config if:
15444fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                //   - the target config had a recent roaming failure
15454fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                //   - we are currently associated
15464fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                //   - the target config is not the last selected
15474fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                if (now > config.lastRoamingFailure
15484fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                        && (now - config.lastRoamingFailure)
15494fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                        < config.roamingFailureBlackListTimeMilli) {
15504fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                    if (DBG) {
15514fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                        logDbg("compareNetwork not switching to " + config.configKey()
15524fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                                + " from current " + currentConfiguration.configKey()
15534fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                                + " because it is blacklisted due to roam failure, "
15544fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                                + " blacklist remain time = "
15554fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                                + (now - config.lastRoamingFailure) + " ms");
15564fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                    }
15574fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                    continue;
15584fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle                }
15594fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle            }
15604fa99f57077ab287d6ed1b51cf308c44ce8bbe0bvandwalle
15611ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            int boost = config.autoJoinUseAggressiveJoinAttemptThreshold + weakRssiBailCount;
15620eebae7334d6129f7ca1344e4b20199794994358vandwalle            if ((config.visibility.rssi5 + boost)
15630eebae7334d6129f7ca1344e4b20199794994358vandwalle                        < mWifiConfigStore.thresholdInitialAutoJoinAttemptMin5RSSI
15640eebae7334d6129f7ca1344e4b20199794994358vandwalle                        && (config.visibility.rssi24 + boost)
15650eebae7334d6129f7ca1344e4b20199794994358vandwalle                        < mWifiConfigStore.thresholdInitialAutoJoinAttemptMin24RSSI) {
15660eebae7334d6129f7ca1344e4b20199794994358vandwalle                if (DBG) {
15670eebae7334d6129f7ca1344e4b20199794994358vandwalle                    logDbg("attemptAutoJoin skip due to low visibility -> status="
15680eebae7334d6129f7ca1344e4b20199794994358vandwalle                            + config.autoJoinStatus
15690eebae7334d6129f7ca1344e4b20199794994358vandwalle                            + " key " + config.configKey(true) + " rssi="
15700eebae7334d6129f7ca1344e4b20199794994358vandwalle                            + config.visibility.rssi24 + ", " + config.visibility.rssi5
15710eebae7334d6129f7ca1344e4b20199794994358vandwalle                            + " num=" + config.visibility.num24
15720eebae7334d6129f7ca1344e4b20199794994358vandwalle                            + ", " + config.visibility.num5);
15730eebae7334d6129f7ca1344e4b20199794994358vandwalle                }
15740eebae7334d6129f7ca1344e4b20199794994358vandwalle
1575c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                // Don't try to autojoin a network that is too far but
1576c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                // If that configuration is a user's choice however, try anyway
15770eebae7334d6129f7ca1344e4b20199794994358vandwalle                if (!isLastSelected) {
15780eebae7334d6129f7ca1344e4b20199794994358vandwalle                    config.autoJoinBailedDueToLowRssi = true;
15791ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                    didBailDueToWeakRssi = true;
15808c9088d11880553458f09377cc60d6eb7e66747bvandwalle                    continue;
15810eebae7334d6129f7ca1344e4b20199794994358vandwalle                } else {
15820eebae7334d6129f7ca1344e4b20199794994358vandwalle                    // Next time, try to be a bit more aggressive in auto-joining
15830eebae7334d6129f7ca1344e4b20199794994358vandwalle                    if (config.autoJoinUseAggressiveJoinAttemptThreshold
1584dd0c558776fcfba3f754bb0cd6533f2c9c23ec1evandwalle                            < WifiConfiguration.MAX_INITIAL_AUTO_JOIN_RSSI_BOOST
1585dd0c558776fcfba3f754bb0cd6533f2c9c23ec1evandwalle                            && config.autoJoinBailedDueToLowRssi) {
1586dd0c558776fcfba3f754bb0cd6533f2c9c23ec1evandwalle                        config.autoJoinUseAggressiveJoinAttemptThreshold += 4;
15874dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                    }
15888c9088d11880553458f09377cc60d6eb7e66747bvandwalle                }
15890eebae7334d6129f7ca1344e4b20199794994358vandwalle            }
1590d30127db46224e45554f8964209221bba8ad41d9vandwalle            if (config.numNoInternetAccessReports > 0
1591d30127db46224e45554f8964209221bba8ad41d9vandwalle                    && !isLastSelected
1592d30127db46224e45554f8964209221bba8ad41d9vandwalle                    && !config.validatedInternetAccess) {
1593d30127db46224e45554f8964209221bba8ad41d9vandwalle                // Avoid autoJoining this network because last time we used it, it didn't
1594d30127db46224e45554f8964209221bba8ad41d9vandwalle                // have internet access, and we never manage to validate internet access on this
1595d30127db46224e45554f8964209221bba8ad41d9vandwalle                // network configuration
15960eebae7334d6129f7ca1344e4b20199794994358vandwalle                if (DBG) {
1597d30127db46224e45554f8964209221bba8ad41d9vandwalle                    logDbg("attemptAutoJoin skip candidate due to no InternetAccess  "
1598d30127db46224e45554f8964209221bba8ad41d9vandwalle                            + config.configKey(true)
1599d30127db46224e45554f8964209221bba8ad41d9vandwalle                            + " num reports " + config.numNoInternetAccessReports);
16009f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                }
16010eebae7334d6129f7ca1344e4b20199794994358vandwalle                continue;
16028c9088d11880553458f09377cc60d6eb7e66747bvandwalle            }
16038c9088d11880553458f09377cc60d6eb7e66747bvandwalle
1604ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            if (DBG) {
1605e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                String cur = "";
1606e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                if (candidate != null) {
1607e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                    cur = " current candidate " + candidate.configKey();
1608e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                }
1609e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                logDbg("attemptAutoJoin trying id="
1610c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                        + Integer.toString(config.networkId) + " "
1611b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                        + config.configKey(true)
1612e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + " status=" + config.autoJoinStatus
1613e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle                        + cur);
1614ed9938883ae2dade81c8be6cd6ceaef3febd5239vandwalle            }
1615f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1616f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate == null) {
1617f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                candidate = config;
1618f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            } else {
1619f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (VDBG)  {
1620453aee50caf7e332e77ab3d995d7c87a958e4fd4vandwalle                    logDbg("attemptAutoJoin will compare candidate  " + candidate.configKey()
16214dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle                            + " with " + config.configKey());
1622f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1623833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                int order = compareWifiConfigurations(candidate, config);
16242451dbcc4f9641df188326215b204b798eb70c46vandwalle
16252451dbcc4f9641df188326215b204b798eb70c46vandwalle                // The lastSelectedConfiguration is the configuration the user has manually selected
1626c290d8dff6172d5fde7b9dfd74d3a20785dab246vandwalle                // thru WifiPicker, or that a 3rd party app asked us to connect to via the
16272451dbcc4f9641df188326215b204b798eb70c46vandwalle                // enableNetwork with disableOthers=true WifiManager API
16282451dbcc4f9641df188326215b204b798eb70c46vandwalle                // As this is a direct user choice, we strongly prefer this configuration,
16292451dbcc4f9641df188326215b204b798eb70c46vandwalle                // hence give +/-100
16302451dbcc4f9641df188326215b204b798eb70c46vandwalle                if ((lastSelectedConfiguration != null)
16312451dbcc4f9641df188326215b204b798eb70c46vandwalle                        && candidate.configKey().equals(lastSelectedConfiguration)) {
16322451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // candidate is the last selected configuration,
16332451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // so keep it above connect choices (+/-60) and
16342451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // above RSSI/scorer based selection of linked configuration (+/- 50)
16352451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // by reducing order by -100
16362451dbcc4f9641df188326215b204b798eb70c46vandwalle                    order = order - 100;
16372451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (VDBG)   {
16382f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        logDbg("     ...and prefers -100 " + candidate.configKey()
16392451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " over " + config.configKey()
16402451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " because it is the last selected -> "
16412451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + Integer.toString(order));
16422451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
16432451dbcc4f9641df188326215b204b798eb70c46vandwalle                } else if ((lastSelectedConfiguration != null)
16442451dbcc4f9641df188326215b204b798eb70c46vandwalle                        && config.configKey().equals(lastSelectedConfiguration)) {
16452451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // config is the last selected configuration,
16462451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // so keep it above connect choices (+/-60) and
16472451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // above RSSI/scorer based selection of linked configuration (+/- 50)
16482451dbcc4f9641df188326215b204b798eb70c46vandwalle                    // by increasing order by +100
16492451dbcc4f9641df188326215b204b798eb70c46vandwalle                    order = order + 100;
16502451dbcc4f9641df188326215b204b798eb70c46vandwalle                    if (VDBG)   {
16512f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        logDbg("     ...and prefers +100 " + config.configKey()
16522451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " over " + candidate.configKey()
16532451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + " because it is the last selected -> "
16542451dbcc4f9641df188326215b204b798eb70c46vandwalle                                + Integer.toString(order));
16552451dbcc4f9641df188326215b204b798eb70c46vandwalle                    }
16562451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
16572451dbcc4f9641df188326215b204b798eb70c46vandwalle
1658f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                if (order > 0) {
1659931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle                    // Ascending : candidate < config
1660f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    candidate = config;
1661f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1662f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1663f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1664f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
16652451dbcc4f9641df188326215b204b798eb70c46vandwalle        // Now, go thru scan result to try finding a better untrusted network
1666833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle        if (mNetworkScoreCache != null && mAllowUntrustedConnections) {
1667f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi5 = WifiConfiguration.INVALID_RSSI;
1668f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            int rssi24 = WifiConfiguration.INVALID_RSSI;
1669f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            if (candidate != null) {
1670f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi5 = candidate.visibility.rssi5;
1671f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                rssi24 = candidate.visibility.rssi24;
1672f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1673f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1674931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Get current date
16752451dbcc4f9641df188326215b204b798eb70c46vandwalle            long nowMs = System.currentTimeMillis();
1676c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            int currentScore = -10000;
1677c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            // The untrusted network with highest score
1678c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            ScanResult untrustedCandidate = null;
16792451dbcc4f9641df188326215b204b798eb70c46vandwalle            // Look for untrusted scored network only if the current candidate is bad
1680c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            if (isBadCandidate(rssi24, rssi5)) {
1681f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                for (ScanResult result : scanResultCache.values()) {
1682c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // We look only at untrusted networks with a valid SSID
1683c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    // A trusted result would have been looked at thru it's Wificonfiguration
16848639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                    if (TextUtils.isEmpty(result.SSID) || !result.untrusted ||
16858639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                            !isOpenNetwork(result)) {
1686c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        continue;
1687c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                    }
16882c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                    String quotedSSID = "\"" + result.SSID + "\"";
16892c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                    if (mWifiConfigStore.mDeletedEphemeralSSIDs.contains(quotedSSID)) {
16902ce99b40c36ed0352b31aa85d5f9383d5f0506f5vandwalle                        // SSID had been Forgotten by user, then don't score it
16912ce99b40c36ed0352b31aa85d5f9383d5f0506f5vandwalle                        continue;
16922ce99b40c36ed0352b31aa85d5f9383d5f0506f5vandwalle                    }
1693833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                    if ((nowMs - result.seen) < mScanResultAutoJoinAge) {
1694c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        // Increment usage count for the network
16952c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                        mWifiConnectionStatistics.incrementOrAddUntrusted(quotedSSID, 0, 1);
1696c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle
16972c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                        boolean isActiveNetwork = currentConfiguration != null
16982c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                                && currentConfiguration.SSID.equals(quotedSSID);
169981c9ea6c343bc7f8d87095237e59844a974d0b70Jeff Davidson                        int score = mNetworkScoreCache.getNetworkScore(result, isActiveNetwork);
1700c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                        if (score != WifiNetworkScoreCache.INVALID_NETWORK_SCORE
1701c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                && score > currentScore) {
1702c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            // Highest score: Select this candidate
1703c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            currentScore = score;
1704c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            untrustedCandidate = result;
1705c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            if (VDBG) {
1706c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                logDbg("AutoJoinController: found untrusted candidate "
1707c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                        + result.SSID
1708c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                + " RSSI=" + result.level
1709c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                + " freq=" + result.frequency
1710c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                                + " score=" + score);
1711c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                            }
1712f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                        }
1713f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                    }
1714f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle                }
1715f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1716c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            if (untrustedCandidate != null) {
17178639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                // At this point, we have an untrusted network candidate.
17188639f6266cb70bf92d1561af43ac2d7b2b97298eJeff Davidson                // Create the new ephemeral configuration and see if we should switch over
1719833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                candidate =
1720833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                        mWifiConfigStore.wifiConfigurationFromScanResult(untrustedCandidate);
1721833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                candidate.allowedKeyManagement.set(KeyMgmt.NONE);
1722833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                candidate.ephemeral = true;
1723c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle            }
1724c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle        }
1725b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle
17261ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        long lastUnwanted =
17271ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                System.currentTimeMillis()
17281ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                        - mWifiConfigStore.lastUnwantedNetworkDisconnectTimestamp;
17291ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        if (candidate == null
17301ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && lastSelectedConfiguration == null
17311ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && currentConfiguration == null
17321ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && didBailDueToWeakRssi
17331ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                && (mWifiConfigStore.lastUnwantedNetworkDisconnectTimestamp == 0
17341ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                    || lastUnwanted > (1000 * 60 * 60 * 24 * 7))
17351ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                ) {
17361ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // We are bailing out of autojoin although we are seeing a weak configuration, and
17371ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - we didn't find another valid candidate
17381ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - we are not connected
17391ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - without a user network selection choice
17401ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // - ConnectivityService has not triggered an unwanted network disconnect
17411ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            //       on this device for a week (hence most likely there is no SIM card or cellular)
17421ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // If all those conditions are met, then boost the RSSI of the weak networks
17431ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            // that we are seeing so as we will eventually pick one
17441ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            if (weakRssiBailCount < 10)
17451ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                weakRssiBailCount += 1;
17461ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        } else {
17471ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle            if (weakRssiBailCount > 0)
17481ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                weakRssiBailCount -= 1;
17491ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle        }
17501ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle
1751931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1752931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         *  If candidate is found, check the state of the connection so as
1753931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         *  to decide if we should be acting on this candidate and switching over
1754931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
1755e0aa0a004d161173992a0e9af1b431fae91f4a71vandwalle        int networkDelta = compareNetwork(candidate, lastSelectedConfiguration);
1756b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle        if (DBG && candidate != null) {
1757b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            String doSwitch = "";
1758b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            String current = "";
1759b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (networkDelta < 0) {
1760b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                doSwitch = " -> not switching";
1761b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1762b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            if (currentConfiguration != null) {
17632f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                current = " with current " + currentConfiguration.configKey();
1764b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            }
1765b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle            logDbg("attemptAutoJoin networkSwitching candidate "
1766b57df70bdf17ba45ef4d18b11414cb24dcbe1fb9vandwalle                    + candidate.configKey()
1767b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + current
1768c6f06c628ee3583b60ff31a7da442e0ac7b26d97vandwalle                    + " linked=" + (currentConfiguration != null
1769b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                            && currentConfiguration.isLinked(candidate))
1770b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + " : delta="
1771b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + Integer.toString(networkDelta) + " "
1772b664cfeab6f02e24376ea0a15beb83d142f0b14dvandwalle                    + doSwitch);
1773b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
17744dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1775931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle        /**
1776931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * Ask WifiStateMachine permission to switch :
1777931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * if user is currently streaming voice traffic,
1778931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         * then we should not be allowed to switch regardless of the delta
1779931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle         */
1780b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (mWifiStateMachine.shouldSwitchNetwork(networkDelta)) {
1781b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            if (mStaStaSupported) {
1782b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                logDbg("mStaStaSupported --> error do nothing now ");
1783b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle            } else {
1784b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (currentConfiguration != null && currentConfiguration.isLinked(candidate)) {
1785b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    networkSwitchType = AUTO_JOIN_EXTENDED_ROAMING;
1786b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                } else {
1787b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    networkSwitchType = AUTO_JOIN_OUT_OF_NETWORK_ROAMING;
1788b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
1789b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (DBG) {
1790b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("AutoJoin auto connect with netId "
1791b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + Integer.toString(candidate.networkId)
1792b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " to " + candidate.configKey());
1793b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
17942451dbcc4f9641df188326215b204b798eb70c46vandwalle                if (didOverride) {
17952451dbcc4f9641df188326215b204b798eb70c46vandwalle                    candidate.numScorerOverrideAndSwitchedNetwork++;
17962451dbcc4f9641df188326215b204b798eb70c46vandwalle                }
1797c298087de50ea56c31a4ade7ee1e83b313bb63c7vandwalle                candidate.numAssociation++;
1798e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                mWifiConnectionStatistics.numAutoJoinAttempt++;
17999f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle
18002c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                if (candidate.ephemeral) {
18012c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                    // We found a new candidate that we are going to connect to, then
18022c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                    // increase its connection count
18032c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                    mWifiConnectionStatistics.
18042c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                            incrementOrAddUntrusted(candidate.SSID, 1, 0);
18052c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson                }
18062c9b6297f3cd74780a084634320d03a413a3b779Jeff Davidson
18072f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                if (candidate.BSSID == null || candidate.BSSID.equals("any")) {
18082f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // First step we selected the configuration we want to connect to
18092f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // Second step: Look for the best Scan result for this configuration
18102f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    // TODO this algorithm should really be done in one step
18112f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    String currentBSSID = mWifiStateMachine.getCurrentBSSID();
1812833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                    ScanResult roamCandidate =
1813833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                            attemptRoam(null, candidate, mScanResultAutoJoinAge, null);
18142f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    if (roamCandidate != null && currentBSSID != null
18152f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                            && currentBSSID.equals(roamCandidate.BSSID)) {
18162f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // Sanity, we were already asociated to that candidate
18172f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        roamCandidate = null;
18182f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    }
18192f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                    if (roamCandidate != null && roamCandidate.is5GHz()) {
18202f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // If the configuration hasn't a default BSSID selected, and the best
18212f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // candidate is 5GHZ, then select this candidate so as WifiStateMachine and
18222f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        // supplicant will pick it first
18232f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        candidate.autoJoinBSSID = roamCandidate.BSSID;
18242f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        if (VDBG) {
18252f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                            logDbg("AutoJoinController: lock to 5GHz "
18262f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                                    + candidate.autoJoinBSSID
18272f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                                    + " RSSI=" + roamCandidate.level
18282f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                                    + " freq=" + roamCandidate.frequency);
18292f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle                        }
1830448c9536a302c58a79e271b1721c08b8882f800evandwalle                    } else {
1831448c9536a302c58a79e271b1721c08b8882f800evandwalle                        // We couldnt find a roam candidate
1832448c9536a302c58a79e271b1721c08b8882f800evandwalle                        candidate.autoJoinBSSID = "any";
18339f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                    }
18349f3349fa2cd39d690d1e2b7c3b71ced412e24f2cvandwalle                }
1835448c9536a302c58a79e271b1721c08b8882f800evandwalle                mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_CONNECT,
1836448c9536a302c58a79e271b1721c08b8882f800evandwalle                            candidate.networkId, networkSwitchType, candidate);
183768fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                found = true;
18384dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle            }
1839b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        }
18404dc6f3a322806b25d50039614cde1b94fe91ab17vandwalle
1841b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (networkSwitchType == AUTO_JOIN_IDLE) {
1842e67ec726c07410073575473c0f50dc737629f5davandwalle            String currentBSSID = mWifiStateMachine.getCurrentBSSID();
1843931338d1533d1bd11ba0e5aebb4e4b7b2c8ab056vandwalle            // Attempt same WifiConfiguration roaming
1844833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle            ScanResult roamCandidate =
1845833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                    attemptRoam(null, currentConfiguration, mScanResultAutoJoinAge, currentBSSID);
1846e67ec726c07410073575473c0f50dc737629f5davandwalle            /**
1847e67ec726c07410073575473c0f50dc737629f5davandwalle             *  TODO: (post L initial release)
1848e67ec726c07410073575473c0f50dc737629f5davandwalle             *  consider handling linked configurations roaming (i.e. extended Roaming)
1849e67ec726c07410073575473c0f50dc737629f5davandwalle             *  thru the attemptRoam function which makes use of the RSSI roaming threshold.
1850e67ec726c07410073575473c0f50dc737629f5davandwalle             *  At the moment, extended roaming is only handled thru the attemptAutoJoin()
1851e67ec726c07410073575473c0f50dc737629f5davandwalle             *  function which compare configurations.
1852e67ec726c07410073575473c0f50dc737629f5davandwalle             *
1853e67ec726c07410073575473c0f50dc737629f5davandwalle             *  The advantage of making use of attemptRoam function is that this function
1854e67ec726c07410073575473c0f50dc737629f5davandwalle             *  will looks at all the BSSID of each configurations, instead of only looking
1855e67ec726c07410073575473c0f50dc737629f5davandwalle             *  at WifiConfiguration.visibility which keeps trackonly of the RSSI/band of the
1856e67ec726c07410073575473c0f50dc737629f5davandwalle             *  two highest BSSIDs.
1857e67ec726c07410073575473c0f50dc737629f5davandwalle             */
1858e67ec726c07410073575473c0f50dc737629f5davandwalle            // Attempt linked WifiConfiguration roaming
1859e67ec726c07410073575473c0f50dc737629f5davandwalle            /* if (currentConfiguration != null
1860e67ec726c07410073575473c0f50dc737629f5davandwalle                    && currentConfiguration.linkedConfigurations != null) {
1861e67ec726c07410073575473c0f50dc737629f5davandwalle                for (String key : currentConfiguration.linkedConfigurations.keySet()) {
1862e67ec726c07410073575473c0f50dc737629f5davandwalle                    WifiConfiguration link = mWifiConfigStore.getWifiConfiguration(key);
1863e67ec726c07410073575473c0f50dc737629f5davandwalle                    if (link != null) {
1864833dcce8f6712f7594f06ea33208e3e106c15afcvandwalle                        roamCandidate = attemptRoam(roamCandidate, link, mScanResultAutoJoinAge,
1865e67ec726c07410073575473c0f50dc737629f5davandwalle                                currentBSSID);
1866e67ec726c07410073575473c0f50dc737629f5davandwalle                    }
1867e67ec726c07410073575473c0f50dc737629f5davandwalle                }
1868e67ec726c07410073575473c0f50dc737629f5davandwalle            }*/
1869e67ec726c07410073575473c0f50dc737629f5davandwalle            if (roamCandidate != null && currentBSSID != null
1870e67ec726c07410073575473c0f50dc737629f5davandwalle                    && currentBSSID.equals(roamCandidate.BSSID)) {
1871e67ec726c07410073575473c0f50dc737629f5davandwalle                roamCandidate = null;
1872e67ec726c07410073575473c0f50dc737629f5davandwalle            }
18732f2cf21662275a0e93d7d7a6ad3d98b4c596dcf0vandwalle            if (roamCandidate != null && mWifiStateMachine.shouldSwitchNetwork(999)) {
1874b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                if (DBG) {
1875b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                    logDbg("AutoJoin auto roam with netId "
1876b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + Integer.toString(currentConfiguration.networkId)
1877b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + " " + currentConfiguration.configKey() + " to BSSID="
1878b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                            + roamCandidate.BSSID + " freq=" + roamCandidate.frequency
18791ec92c57244311c7fca3ab6b244a06c2b2b58902vandwalle                            + " RSSI=" + roamCandidate.level);
1880b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                }
1881b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle                networkSwitchType = AUTO_JOIN_ROAMING;
1882e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle                mWifiConnectionStatistics.numAutoRoamAttempt++;
1883e8c89583e489d451880471b7cc7659bd9fa802f4vandwalle
1884b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle                mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_ROAM,
1885b07da189850a4bfa268f8ab9be7867935eb2ecb5vandwalle                            currentConfiguration.networkId, 1, roamCandidate);
188668fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle                found = true;
1887f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle            }
1888f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle        }
1889b97e66604f472f67c233bb8f8d9630bb36131e2cvandwalle        if (VDBG) logDbg("Done attemptAutoJoin status=" + Integer.toString(networkSwitchType));
189068fee36dac1dda5c596c00ef33fdbc0962e9ec9fvandwalle        return found;
1891f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle    }
1892f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle}
1893f22d23092ab37286a5ef9d257d5bb32c421d2669vandwalle
1894