• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server;
18 
19 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
20 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
21 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
22 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
23 import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
24 
25 import android.app.AlarmManager;
26 import android.app.PendingIntent;
27 import android.bluetooth.BluetoothA2dp;
28 import android.content.BroadcastReceiver;
29 import android.content.ContentResolver;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.IntentFilter;
33 import android.content.pm.PackageManager;
34 import android.net.wifi.IWifiManager;
35 import android.net.wifi.WifiInfo;
36 import android.net.wifi.WifiManager;
37 import android.net.wifi.WifiNative;
38 import android.net.wifi.WifiStateTracker;
39 import android.net.wifi.ScanResult;
40 import android.net.wifi.WifiConfiguration;
41 import android.net.wifi.SupplicantState;
42 import android.net.NetworkStateTracker;
43 import android.net.DhcpInfo;
44 import android.net.NetworkUtils;
45 import android.os.Binder;
46 import android.os.Handler;
47 import android.os.HandlerThread;
48 import android.os.IBinder;
49 import android.os.Looper;
50 import android.os.Message;
51 import android.os.PowerManager;
52 import android.os.Process;
53 import android.os.RemoteException;
54 import android.os.ServiceManager;
55 import android.provider.Settings;
56 import android.util.Log;
57 import android.text.TextUtils;
58 
59 import java.util.ArrayList;
60 import java.util.BitSet;
61 import java.util.HashMap;
62 import java.util.LinkedHashMap;
63 import java.util.List;
64 import java.util.Map;
65 import java.util.regex.Pattern;
66 import java.io.FileDescriptor;
67 import java.io.PrintWriter;
68 
69 import com.android.internal.app.IBatteryStats;
70 import android.backup.IBackupManager;
71 import com.android.server.am.BatteryStatsService;
72 
73 /**
74  * WifiService handles remote WiFi operation requests by implementing
75  * the IWifiManager interface. It also creates a WifiMonitor to listen
76  * for Wifi-related events.
77  *
78  * @hide
79  */
80 public class WifiService extends IWifiManager.Stub {
81     private static final String TAG = "WifiService";
82     private static final boolean DBG = false;
83     private static final Pattern scanResultPattern = Pattern.compile("\t+");
84     private final WifiStateTracker mWifiStateTracker;
85 
86     private Context mContext;
87     private int mWifiState;
88 
89     private AlarmManager mAlarmManager;
90     private PendingIntent mIdleIntent;
91     private static final int IDLE_REQUEST = 0;
92     private boolean mScreenOff;
93     private boolean mDeviceIdle;
94     private int mPluggedType;
95 
96     // true if the user enabled Wifi while in airplane mode
97     private boolean mAirplaneModeOverwridden;
98 
99     private final LockList mLocks = new LockList();
100     // some wifi lock statistics
101     private int mFullLocksAcquired;
102     private int mFullLocksReleased;
103     private int mScanLocksAcquired;
104     private int mScanLocksReleased;
105 
106     private final List<Multicaster> mMulticasters =
107             new ArrayList<Multicaster>();
108     private int mMulticastEnabled;
109     private int mMulticastDisabled;
110 
111     private final IBatteryStats mBatteryStats;
112 
113     /**
114      * See {@link Settings.Gservices#WIFI_IDLE_MS}. This is the default value if a
115      * Settings.Gservices value is not present. This timeout value is chosen as
116      * the approximate point at which the battery drain caused by Wi-Fi
117      * being enabled but not active exceeds the battery drain caused by
118      * re-establishing a connection to the mobile data network.
119      */
120     private static final long DEFAULT_IDLE_MILLIS = 15 * 60 * 1000; /* 15 minutes */
121 
122     private static final String WAKELOCK_TAG = "WifiService";
123 
124     /**
125      * The maximum amount of time to hold the wake lock after a disconnect
126      * caused by stopping the driver. Establishing an EDGE connection has been
127      * observed to take about 5 seconds under normal circumstances. This
128      * provides a bit of extra margin.
129      * <p>
130      * See {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}.
131      * This is the default value if a Settings.Secure value is not present.
132      */
133     private static final int DEFAULT_WAKELOCK_TIMEOUT = 8000;
134 
135     // Wake lock used by driver-stop operation
136     private static PowerManager.WakeLock sDriverStopWakeLock;
137     // Wake lock used by other operations
138     private static PowerManager.WakeLock sWakeLock;
139 
140     private static final int MESSAGE_ENABLE_WIFI      = 0;
141     private static final int MESSAGE_DISABLE_WIFI     = 1;
142     private static final int MESSAGE_STOP_WIFI        = 2;
143     private static final int MESSAGE_START_WIFI       = 3;
144     private static final int MESSAGE_RELEASE_WAKELOCK = 4;
145 
146     private final  WifiHandler mWifiHandler;
147 
148     /*
149      * Cache of scan results objects (size is somewhat arbitrary)
150      */
151     private static final int SCAN_RESULT_CACHE_SIZE = 80;
152     private final LinkedHashMap<String, ScanResult> mScanResultCache;
153 
154     /*
155      * Character buffer used to parse scan results (optimization)
156      */
157     private static final int SCAN_RESULT_BUFFER_SIZE = 512;
158     private boolean mNeedReconfig;
159 
160     /*
161      * Last UID that asked to enable WIFI.
162      */
163     private int mLastEnableUid = Process.myUid();
164 
165     /**
166      * Number of allowed radio frequency channels in various regulatory domains.
167      * This list is sufficient for 802.11b/g networks (2.4GHz range).
168      */
169     private static int[] sValidRegulatoryChannelCounts = new int[] {11, 13, 14};
170 
171     private static final String ACTION_DEVICE_IDLE =
172             "com.android.server.WifiManager.action.DEVICE_IDLE";
173 
WifiService(Context context, WifiStateTracker tracker)174     WifiService(Context context, WifiStateTracker tracker) {
175         mContext = context;
176         mWifiStateTracker = tracker;
177         mWifiStateTracker.enableRssiPolling(true);
178         mBatteryStats = BatteryStatsService.getService();
179 
180         mScanResultCache = new LinkedHashMap<String, ScanResult>(
181             SCAN_RESULT_CACHE_SIZE, 0.75f, true) {
182                 /*
183                  * Limit the cache size by SCAN_RESULT_CACHE_SIZE
184                  * elements
185                  */
186                 public boolean removeEldestEntry(Map.Entry eldest) {
187                     return SCAN_RESULT_CACHE_SIZE < this.size();
188                 }
189             };
190 
191         HandlerThread wifiThread = new HandlerThread("WifiService");
192         wifiThread.start();
193         mWifiHandler = new WifiHandler(wifiThread.getLooper());
194 
195         mWifiState = WIFI_STATE_DISABLED;
196         boolean wifiEnabled = getPersistedWifiEnabled();
197 
198         mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
199         Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
200         mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
201 
202         PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
203         sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
204         sDriverStopWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
205         mWifiStateTracker.setReleaseWakeLockCallback(
206                 new Runnable() {
207                     public void run() {
208                         mWifiHandler.removeMessages(MESSAGE_RELEASE_WAKELOCK);
209                         synchronized (sDriverStopWakeLock) {
210                             if (sDriverStopWakeLock.isHeld()) {
211                                 sDriverStopWakeLock.release();
212                             }
213                         }
214                     }
215                 }
216         );
217 
218         Log.i(TAG, "WifiService starting up with Wi-Fi " +
219                 (wifiEnabled ? "enabled" : "disabled"));
220 
221         mContext.registerReceiver(
222                 new BroadcastReceiver() {
223                     @Override
224                     public void onReceive(Context context, Intent intent) {
225                         // clear our flag indicating the user has overwridden airplane mode
226                         mAirplaneModeOverwridden = false;
227                         updateWifiState();
228                     }
229                 },
230                 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
231 
232         setWifiEnabledBlocking(wifiEnabled, false, Process.myUid());
233     }
234 
getPersistedWifiEnabled()235     private boolean getPersistedWifiEnabled() {
236         final ContentResolver cr = mContext.getContentResolver();
237         try {
238             return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON) == 1;
239         } catch (Settings.SettingNotFoundException e) {
240             Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, 0);
241             return false;
242         }
243     }
244 
persistWifiEnabled(boolean enabled)245     private void persistWifiEnabled(boolean enabled) {
246         final ContentResolver cr = mContext.getContentResolver();
247         Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, enabled ? 1 : 0);
248     }
249 
getNetworkStateTracker()250     NetworkStateTracker getNetworkStateTracker() {
251         return mWifiStateTracker;
252     }
253 
254     /**
255      * see {@link android.net.wifi.WifiManager#pingSupplicant()}
256      * @return {@code true} if the operation succeeds
257      */
pingSupplicant()258     public boolean pingSupplicant() {
259         enforceChangePermission();
260         synchronized (mWifiStateTracker) {
261             return WifiNative.pingCommand();
262         }
263     }
264 
265     /**
266      * see {@link android.net.wifi.WifiManager#startScan()}
267      * @return {@code true} if the operation succeeds
268      */
startScan(boolean forceActive)269     public boolean startScan(boolean forceActive) {
270         enforceChangePermission();
271         synchronized (mWifiStateTracker) {
272             switch (mWifiStateTracker.getSupplicantState()) {
273                 case DISCONNECTED:
274                 case INACTIVE:
275                 case SCANNING:
276                 case DORMANT:
277                     break;
278                 default:
279                     WifiNative.setScanResultHandlingCommand(
280                             WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY);
281                     break;
282             }
283             return WifiNative.scanCommand(forceActive);
284         }
285     }
286 
287     /**
288      * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
289      * @param enable {@code true} to enable, {@code false} to disable.
290      * @return {@code true} if the enable/disable operation was
291      *         started or is already in the queue.
292      */
setWifiEnabled(boolean enable)293     public boolean setWifiEnabled(boolean enable) {
294         enforceChangePermission();
295         if (mWifiHandler == null) return false;
296 
297         synchronized (mWifiHandler) {
298             // caller may not have WAKE_LOCK permission - it's not required here
299             long ident = Binder.clearCallingIdentity();
300             sWakeLock.acquire();
301             Binder.restoreCallingIdentity(ident);
302 
303             mLastEnableUid = Binder.getCallingUid();
304             // set a flag if the user is enabling Wifi while in airplane mode
305             mAirplaneModeOverwridden = (enable && isAirplaneModeOn() && isAirplaneToggleable());
306             sendEnableMessage(enable, true, Binder.getCallingUid());
307         }
308 
309         return true;
310     }
311 
312     /**
313      * Enables/disables Wi-Fi synchronously.
314      * @param enable {@code true} to turn Wi-Fi on, {@code false} to turn it off.
315      * @param persist {@code true} if the setting should be persisted.
316      * @param uid The UID of the process making the request.
317      * @return {@code true} if the operation succeeds (or if the existing state
318      *         is the same as the requested state)
319      */
setWifiEnabledBlocking(boolean enable, boolean persist, int uid)320     private boolean setWifiEnabledBlocking(boolean enable, boolean persist, int uid) {
321         final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;
322 
323         if (mWifiState == eventualWifiState) {
324             return true;
325         }
326         if (enable && isAirplaneModeOn() && !mAirplaneModeOverwridden) {
327             return false;
328         }
329 
330         setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);
331 
332         if (enable) {
333             if (!WifiNative.loadDriver()) {
334                 Log.e(TAG, "Failed to load Wi-Fi driver.");
335                 setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
336                 return false;
337             }
338             if (!WifiNative.startSupplicant()) {
339                 WifiNative.unloadDriver();
340                 Log.e(TAG, "Failed to start supplicant daemon.");
341                 setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
342                 return false;
343             }
344             registerForBroadcasts();
345             mWifiStateTracker.startEventLoop();
346         } else {
347 
348             mContext.unregisterReceiver(mReceiver);
349            // Remove notification (it will no-op if it isn't visible)
350             mWifiStateTracker.setNotificationVisible(false, 0, false, 0);
351 
352             boolean failedToStopSupplicantOrUnloadDriver = false;
353             if (!WifiNative.stopSupplicant()) {
354                 Log.e(TAG, "Failed to stop supplicant daemon.");
355                 setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
356                 failedToStopSupplicantOrUnloadDriver = true;
357             }
358 
359             // We must reset the interface before we unload the driver
360             mWifiStateTracker.resetInterface(false);
361 
362             if (!WifiNative.unloadDriver()) {
363                 Log.e(TAG, "Failed to unload Wi-Fi driver.");
364                 if (!failedToStopSupplicantOrUnloadDriver) {
365                     setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
366                     failedToStopSupplicantOrUnloadDriver = true;
367                 }
368             }
369             if (failedToStopSupplicantOrUnloadDriver) {
370                 return false;
371             }
372         }
373 
374         // Success!
375 
376         if (persist) {
377             persistWifiEnabled(enable);
378         }
379         setWifiEnabledState(eventualWifiState, uid);
380 
381         return true;
382     }
383 
setWifiEnabledState(int wifiState, int uid)384     private void setWifiEnabledState(int wifiState, int uid) {
385         final int previousWifiState = mWifiState;
386 
387         long ident = Binder.clearCallingIdentity();
388         try {
389             if (wifiState == WIFI_STATE_ENABLED) {
390                 mBatteryStats.noteWifiOn(uid);
391             } else if (wifiState == WIFI_STATE_DISABLED) {
392                 mBatteryStats.noteWifiOff(uid);
393             }
394         } catch (RemoteException e) {
395         } finally {
396             Binder.restoreCallingIdentity(ident);
397         }
398 
399         // Update state
400         mWifiState = wifiState;
401 
402         // Broadcast
403         final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
404         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
405         intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
406         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
407         mContext.sendStickyBroadcast(intent);
408     }
409 
enforceAccessPermission()410     private void enforceAccessPermission() {
411         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
412                                                 "WifiService");
413     }
414 
enforceChangePermission()415     private void enforceChangePermission() {
416         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
417                                                 "WifiService");
418 
419     }
420 
enforceMulticastChangePermission()421     private void enforceMulticastChangePermission() {
422         mContext.enforceCallingOrSelfPermission(
423                 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
424                 "WifiService");
425     }
426 
427     /**
428      * see {@link WifiManager#getWifiState()}
429      * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
430      *         {@link WifiManager#WIFI_STATE_DISABLING},
431      *         {@link WifiManager#WIFI_STATE_ENABLED},
432      *         {@link WifiManager#WIFI_STATE_ENABLING},
433      *         {@link WifiManager#WIFI_STATE_UNKNOWN}
434      */
getWifiEnabledState()435     public int getWifiEnabledState() {
436         enforceAccessPermission();
437         return mWifiState;
438     }
439 
440     /**
441      * see {@link android.net.wifi.WifiManager#disconnect()}
442      * @return {@code true} if the operation succeeds
443      */
disconnect()444     public boolean disconnect() {
445         enforceChangePermission();
446         synchronized (mWifiStateTracker) {
447             return WifiNative.disconnectCommand();
448         }
449     }
450 
451     /**
452      * see {@link android.net.wifi.WifiManager#reconnect()}
453      * @return {@code true} if the operation succeeds
454      */
reconnect()455     public boolean reconnect() {
456         enforceChangePermission();
457         synchronized (mWifiStateTracker) {
458             return WifiNative.reconnectCommand();
459         }
460     }
461 
462     /**
463      * see {@link android.net.wifi.WifiManager#reassociate()}
464      * @return {@code true} if the operation succeeds
465      */
reassociate()466     public boolean reassociate() {
467         enforceChangePermission();
468         synchronized (mWifiStateTracker) {
469             return WifiNative.reassociateCommand();
470         }
471     }
472 
473     /**
474      * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
475      * @return the list of configured networks
476      */
getConfiguredNetworks()477     public List<WifiConfiguration> getConfiguredNetworks() {
478         enforceAccessPermission();
479         String listStr;
480         /*
481          * We don't cache the list, because we want to allow
482          * for the possibility that the configuration file
483          * has been modified through some external means,
484          * such as the wpa_cli command line program.
485          */
486         synchronized (mWifiStateTracker) {
487             listStr = WifiNative.listNetworksCommand();
488         }
489         List<WifiConfiguration> networks =
490             new ArrayList<WifiConfiguration>();
491         if (listStr == null)
492             return networks;
493 
494         String[] lines = listStr.split("\n");
495         // Skip the first line, which is a header
496        for (int i = 1; i < lines.length; i++) {
497            String[] result = lines[i].split("\t");
498            // network-id | ssid | bssid | flags
499            WifiConfiguration config = new WifiConfiguration();
500            try {
501                config.networkId = Integer.parseInt(result[0]);
502            } catch(NumberFormatException e) {
503                continue;
504            }
505            if (result.length > 3) {
506                if (result[3].indexOf("[CURRENT]") != -1)
507                    config.status = WifiConfiguration.Status.CURRENT;
508                else if (result[3].indexOf("[DISABLED]") != -1)
509                    config.status = WifiConfiguration.Status.DISABLED;
510                else
511                    config.status = WifiConfiguration.Status.ENABLED;
512            } else
513                config.status = WifiConfiguration.Status.ENABLED;
514            synchronized (mWifiStateTracker) {
515                readNetworkVariables(config);
516            }
517            networks.add(config);
518        }
519 
520         return networks;
521     }
522 
523     /**
524      * Read the variables from the supplicant daemon that are needed to
525      * fill in the WifiConfiguration object.
526      * <p/>
527      * The caller must hold the synchronization monitor.
528      * @param config the {@link WifiConfiguration} object to be filled in.
529      */
readNetworkVariables(WifiConfiguration config)530     private static void readNetworkVariables(WifiConfiguration config) {
531 
532         int netId = config.networkId;
533         if (netId < 0)
534             return;
535 
536         /*
537          * TODO: maybe should have a native method that takes an array of
538          * variable names and returns an array of values. But we'd still
539          * be doing a round trip to the supplicant daemon for each variable.
540          */
541         String value;
542 
543         value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.ssidVarName);
544         if (!TextUtils.isEmpty(value)) {
545             config.SSID = value;
546         } else {
547             config.SSID = null;
548         }
549 
550         value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.bssidVarName);
551         if (!TextUtils.isEmpty(value)) {
552             config.BSSID = value;
553         } else {
554             config.BSSID = null;
555         }
556 
557         value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName);
558         config.priority = -1;
559         if (!TextUtils.isEmpty(value)) {
560             try {
561                 config.priority = Integer.parseInt(value);
562             } catch (NumberFormatException ignore) {
563             }
564         }
565 
566         value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.hiddenSSIDVarName);
567         config.hiddenSSID = false;
568         if (!TextUtils.isEmpty(value)) {
569             try {
570                 config.hiddenSSID = Integer.parseInt(value) != 0;
571             } catch (NumberFormatException ignore) {
572             }
573         }
574 
575         value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepTxKeyIdxVarName);
576         config.wepTxKeyIndex = -1;
577         if (!TextUtils.isEmpty(value)) {
578             try {
579                 config.wepTxKeyIndex = Integer.parseInt(value);
580             } catch (NumberFormatException ignore) {
581             }
582         }
583 
584         /*
585          * Get up to 4 WEP keys. Note that the actual keys are not passed back,
586          * just a "*" if the key is set, or the null string otherwise.
587          */
588         for (int i = 0; i < 4; i++) {
589             value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepKeyVarNames[i]);
590             if (!TextUtils.isEmpty(value)) {
591                 config.wepKeys[i] = value;
592             } else {
593                 config.wepKeys[i] = null;
594             }
595         }
596 
597         /*
598          * Get the private shared key. Note that the actual keys are not passed back,
599          * just a "*" if the key is set, or the null string otherwise.
600          */
601         value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.pskVarName);
602         if (!TextUtils.isEmpty(value)) {
603             config.preSharedKey = value;
604         } else {
605             config.preSharedKey = null;
606         }
607 
608         value = WifiNative.getNetworkVariableCommand(config.networkId,
609                 WifiConfiguration.Protocol.varName);
610         if (!TextUtils.isEmpty(value)) {
611             String vals[] = value.split(" ");
612             for (String val : vals) {
613                 int index =
614                     lookupString(val, WifiConfiguration.Protocol.strings);
615                 if (0 <= index) {
616                     config.allowedProtocols.set(index);
617                 }
618             }
619         }
620 
621         value = WifiNative.getNetworkVariableCommand(config.networkId,
622                 WifiConfiguration.KeyMgmt.varName);
623         if (!TextUtils.isEmpty(value)) {
624             String vals[] = value.split(" ");
625             for (String val : vals) {
626                 int index =
627                     lookupString(val, WifiConfiguration.KeyMgmt.strings);
628                 if (0 <= index) {
629                     config.allowedKeyManagement.set(index);
630                 }
631             }
632         }
633 
634         value = WifiNative.getNetworkVariableCommand(config.networkId,
635                 WifiConfiguration.AuthAlgorithm.varName);
636         if (!TextUtils.isEmpty(value)) {
637             String vals[] = value.split(" ");
638             for (String val : vals) {
639                 int index =
640                     lookupString(val, WifiConfiguration.AuthAlgorithm.strings);
641                 if (0 <= index) {
642                     config.allowedAuthAlgorithms.set(index);
643                 }
644             }
645         }
646 
647         value = WifiNative.getNetworkVariableCommand(config.networkId,
648                 WifiConfiguration.PairwiseCipher.varName);
649         if (!TextUtils.isEmpty(value)) {
650             String vals[] = value.split(" ");
651             for (String val : vals) {
652                 int index =
653                     lookupString(val, WifiConfiguration.PairwiseCipher.strings);
654                 if (0 <= index) {
655                     config.allowedPairwiseCiphers.set(index);
656                 }
657             }
658         }
659 
660         value = WifiNative.getNetworkVariableCommand(config.networkId,
661                 WifiConfiguration.GroupCipher.varName);
662         if (!TextUtils.isEmpty(value)) {
663             String vals[] = value.split(" ");
664             for (String val : vals) {
665                 int index =
666                     lookupString(val, WifiConfiguration.GroupCipher.strings);
667                 if (0 <= index) {
668                     config.allowedGroupCiphers.set(index);
669                 }
670             }
671         }
672 
673         for (WifiConfiguration.EnterpriseField field :
674                 config.enterpriseFields) {
675             value = WifiNative.getNetworkVariableCommand(netId,
676                     field.varName());
677             if (!TextUtils.isEmpty(value)) {
678                 field.setValue(value);
679             }
680         }
681     }
682 
683     /**
684      * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
685      * @return the supplicant-assigned identifier for the new or updated
686      * network if the operation succeeds, or {@code -1} if it fails
687      */
addOrUpdateNetwork(WifiConfiguration config)688     public synchronized int addOrUpdateNetwork(WifiConfiguration config) {
689         enforceChangePermission();
690         /*
691          * If the supplied networkId is -1, we create a new empty
692          * network configuration. Otherwise, the networkId should
693          * refer to an existing configuration.
694          */
695         int netId = config.networkId;
696         boolean newNetwork = netId == -1;
697         boolean doReconfig;
698         int currentPriority;
699         // networkId of -1 means we want to create a new network
700         if (newNetwork) {
701             netId = WifiNative.addNetworkCommand();
702             if (netId < 0) {
703                 if (DBG) {
704                     Log.d(TAG, "Failed to add a network!");
705                 }
706                 return -1;
707             }
708             doReconfig = true;
709         } else {
710             String priorityVal = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName);
711             currentPriority = -1;
712             if (!TextUtils.isEmpty(priorityVal)) {
713                 try {
714                     currentPriority = Integer.parseInt(priorityVal);
715                 } catch (NumberFormatException ignore) {
716                 }
717             }
718             doReconfig = currentPriority != config.priority;
719         }
720         mNeedReconfig = mNeedReconfig || doReconfig;
721 
722         setVariables: {
723             /*
724              * Note that if a networkId for a non-existent network
725              * was supplied, then the first setNetworkVariableCommand()
726              * will fail, so we don't bother to make a separate check
727              * for the validity of the ID up front.
728              */
729 
730             if (config.SSID != null &&
731                 !WifiNative.setNetworkVariableCommand(
732                     netId,
733                     WifiConfiguration.ssidVarName,
734                     config.SSID)) {
735                 if (DBG) {
736                     Log.d(TAG, "failed to set SSID: "+config.SSID);
737                 }
738                 break setVariables;
739             }
740 
741             if (config.BSSID != null &&
742                 !WifiNative.setNetworkVariableCommand(
743                     netId,
744                     WifiConfiguration.bssidVarName,
745                     config.BSSID)) {
746                 if (DBG) {
747                     Log.d(TAG, "failed to set BSSID: "+config.BSSID);
748                 }
749                 break setVariables;
750             }
751 
752             String allowedKeyManagementString =
753                 makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings);
754             if (config.allowedKeyManagement.cardinality() != 0 &&
755                 !WifiNative.setNetworkVariableCommand(
756                     netId,
757                     WifiConfiguration.KeyMgmt.varName,
758                     allowedKeyManagementString)) {
759                 if (DBG) {
760                     Log.d(TAG, "failed to set key_mgmt: "+
761                           allowedKeyManagementString);
762                 }
763                 break setVariables;
764             }
765 
766             String allowedProtocolsString =
767                 makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings);
768             if (config.allowedProtocols.cardinality() != 0 &&
769                 !WifiNative.setNetworkVariableCommand(
770                     netId,
771                     WifiConfiguration.Protocol.varName,
772                     allowedProtocolsString)) {
773                 if (DBG) {
774                     Log.d(TAG, "failed to set proto: "+
775                           allowedProtocolsString);
776                 }
777                 break setVariables;
778             }
779 
780             String allowedAuthAlgorithmsString =
781                 makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings);
782             if (config.allowedAuthAlgorithms.cardinality() != 0 &&
783                 !WifiNative.setNetworkVariableCommand(
784                     netId,
785                     WifiConfiguration.AuthAlgorithm.varName,
786                     allowedAuthAlgorithmsString)) {
787                 if (DBG) {
788                     Log.d(TAG, "failed to set auth_alg: "+
789                           allowedAuthAlgorithmsString);
790                 }
791                 break setVariables;
792             }
793 
794             String allowedPairwiseCiphersString =
795                 makeString(config.allowedPairwiseCiphers, WifiConfiguration.PairwiseCipher.strings);
796             if (config.allowedPairwiseCiphers.cardinality() != 0 &&
797                 !WifiNative.setNetworkVariableCommand(
798                     netId,
799                     WifiConfiguration.PairwiseCipher.varName,
800                     allowedPairwiseCiphersString)) {
801                 if (DBG) {
802                     Log.d(TAG, "failed to set pairwise: "+
803                           allowedPairwiseCiphersString);
804                 }
805                 break setVariables;
806             }
807 
808             String allowedGroupCiphersString =
809                 makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings);
810             if (config.allowedGroupCiphers.cardinality() != 0 &&
811                 !WifiNative.setNetworkVariableCommand(
812                     netId,
813                     WifiConfiguration.GroupCipher.varName,
814                     allowedGroupCiphersString)) {
815                 if (DBG) {
816                     Log.d(TAG, "failed to set group: "+
817                           allowedGroupCiphersString);
818                 }
819                 break setVariables;
820             }
821 
822             // Prevent client screw-up by passing in a WifiConfiguration we gave it
823             // by preventing "*" as a key.
824             if (config.preSharedKey != null && !config.preSharedKey.equals("*") &&
825                 !WifiNative.setNetworkVariableCommand(
826                     netId,
827                     WifiConfiguration.pskVarName,
828                     config.preSharedKey)) {
829                 if (DBG) {
830                     Log.d(TAG, "failed to set psk: "+config.preSharedKey);
831                 }
832                 break setVariables;
833             }
834 
835             boolean hasSetKey = false;
836             if (config.wepKeys != null) {
837                 for (int i = 0; i < config.wepKeys.length; i++) {
838                     // Prevent client screw-up by passing in a WifiConfiguration we gave it
839                     // by preventing "*" as a key.
840                     if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) {
841                         if (!WifiNative.setNetworkVariableCommand(
842                                 netId,
843                                 WifiConfiguration.wepKeyVarNames[i],
844                                 config.wepKeys[i])) {
845                             if (DBG) {
846                                 Log.d(TAG,
847                                       "failed to set wep_key"+i+": " +
848                                       config.wepKeys[i]);
849                             }
850                             break setVariables;
851                         }
852                         hasSetKey = true;
853                     }
854                 }
855             }
856 
857             if (hasSetKey) {
858                 if (!WifiNative.setNetworkVariableCommand(
859                         netId,
860                         WifiConfiguration.wepTxKeyIdxVarName,
861                         Integer.toString(config.wepTxKeyIndex))) {
862                     if (DBG) {
863                         Log.d(TAG,
864                               "failed to set wep_tx_keyidx: "+
865                               config.wepTxKeyIndex);
866                     }
867                     break setVariables;
868                 }
869             }
870 
871             if (!WifiNative.setNetworkVariableCommand(
872                     netId,
873                     WifiConfiguration.priorityVarName,
874                     Integer.toString(config.priority))) {
875                 if (DBG) {
876                     Log.d(TAG, config.SSID + ": failed to set priority: "
877                           +config.priority);
878                 }
879                 break setVariables;
880             }
881 
882             if (config.hiddenSSID && !WifiNative.setNetworkVariableCommand(
883                     netId,
884                     WifiConfiguration.hiddenSSIDVarName,
885                     Integer.toString(config.hiddenSSID ? 1 : 0))) {
886                 if (DBG) {
887                     Log.d(TAG, config.SSID + ": failed to set hiddenSSID: "+
888                           config.hiddenSSID);
889                 }
890                 break setVariables;
891             }
892 
893             for (WifiConfiguration.EnterpriseField field
894                     : config.enterpriseFields) {
895                 String varName = field.varName();
896                 String value = field.value();
897                 if ((value != null) && !WifiNative.setNetworkVariableCommand(
898                     netId,
899                     varName,
900                     value)) {
901                     if (DBG) {
902                         Log.d(TAG, config.SSID + ": failed to set " + varName +
903                               ": " + value);
904                     }
905                     break setVariables;
906                 }
907             }
908 
909             return netId;
910         }
911 
912         /*
913          * For an update, if one of the setNetworkVariable operations fails,
914          * we might want to roll back all the changes already made. But the
915          * chances are that if anything is going to go wrong, it'll happen
916          * the first time we try to set one of the variables.
917          */
918         if (newNetwork) {
919             removeNetwork(netId);
920             if (DBG) {
921                 Log.d(TAG,
922                       "Failed to set a network variable, removed network: "
923                       + netId);
924             }
925         }
926         return -1;
927     }
928 
makeString(BitSet set, String[] strings)929     private static String makeString(BitSet set, String[] strings) {
930         StringBuffer buf = new StringBuffer();
931         int nextSetBit = -1;
932 
933         /* Make sure all set bits are in [0, strings.length) to avoid
934          * going out of bounds on strings.  (Shouldn't happen, but...) */
935         set = set.get(0, strings.length);
936 
937         while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
938             buf.append(strings[nextSetBit].replace('_', '-')).append(' ');
939         }
940 
941         // remove trailing space
942         if (set.cardinality() > 0) {
943             buf.setLength(buf.length() - 1);
944         }
945 
946         return buf.toString();
947     }
948 
lookupString(String string, String[] strings)949     private static int lookupString(String string, String[] strings) {
950         int size = strings.length;
951 
952         string = string.replace('-', '_');
953 
954         for (int i = 0; i < size; i++)
955             if (string.equals(strings[i]))
956                 return i;
957 
958         if (DBG) {
959             // if we ever get here, we should probably add the
960             // value to WifiConfiguration to reflect that it's
961             // supported by the WPA supplicant
962             Log.w(TAG, "Failed to look-up a string: " + string);
963         }
964 
965         return -1;
966     }
967 
968     /**
969      * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
970      * @param netId the integer that identifies the network configuration
971      * to the supplicant
972      * @return {@code true} if the operation succeeded
973      */
removeNetwork(int netId)974     public boolean removeNetwork(int netId) {
975         enforceChangePermission();
976 
977         return mWifiStateTracker.removeNetwork(netId);
978     }
979 
980     /**
981      * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
982      * @param netId the integer that identifies the network configuration
983      * to the supplicant
984      * @param disableOthers if true, disable all other networks.
985      * @return {@code true} if the operation succeeded
986      */
enableNetwork(int netId, boolean disableOthers)987     public boolean enableNetwork(int netId, boolean disableOthers) {
988         enforceChangePermission();
989 
990         synchronized (mWifiStateTracker) {
991             String ifname = mWifiStateTracker.getInterfaceName();
992             NetworkUtils.enableInterface(ifname);
993             boolean result = WifiNative.enableNetworkCommand(netId, disableOthers);
994             if (!result) {
995                 NetworkUtils.disableInterface(ifname);
996             }
997             return result;
998         }
999     }
1000 
1001     /**
1002      * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
1003      * @param netId the integer that identifies the network configuration
1004      * to the supplicant
1005      * @return {@code true} if the operation succeeded
1006      */
disableNetwork(int netId)1007     public boolean disableNetwork(int netId) {
1008         enforceChangePermission();
1009 
1010         synchronized (mWifiStateTracker) {
1011             return WifiNative.disableNetworkCommand(netId);
1012         }
1013     }
1014 
1015     /**
1016      * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
1017      * @return the Wi-Fi information, contained in {@link WifiInfo}.
1018      */
getConnectionInfo()1019     public WifiInfo getConnectionInfo() {
1020         enforceAccessPermission();
1021         /*
1022          * Make sure we have the latest information, by sending
1023          * a status request to the supplicant.
1024          */
1025         return mWifiStateTracker.requestConnectionInfo();
1026     }
1027 
1028     /**
1029      * Return the results of the most recent access point scan, in the form of
1030      * a list of {@link ScanResult} objects.
1031      * @return the list of results
1032      */
getScanResults()1033     public List<ScanResult> getScanResults() {
1034         enforceAccessPermission();
1035         String reply;
1036         synchronized (mWifiStateTracker) {
1037             reply = WifiNative.scanResultsCommand();
1038         }
1039         if (reply == null) {
1040             return null;
1041         }
1042 
1043         List<ScanResult> scanList = new ArrayList<ScanResult>();
1044 
1045         int lineCount = 0;
1046 
1047         int replyLen = reply.length();
1048         // Parse the result string, keeping in mind that the last line does
1049         // not end with a newline.
1050         for (int lineBeg = 0, lineEnd = 0; lineEnd <= replyLen; ++lineEnd) {
1051             if (lineEnd == replyLen || reply.charAt(lineEnd) == '\n') {
1052                 ++lineCount;
1053                 /*
1054                  * Skip the first line, which is a header
1055                  */
1056                 if (lineCount == 1) {
1057                     lineBeg = lineEnd + 1;
1058                     continue;
1059                 }
1060                 if (lineEnd > lineBeg) {
1061                     String line = reply.substring(lineBeg, lineEnd);
1062                     ScanResult scanResult = parseScanResult(line);
1063                     if (scanResult != null) {
1064                         scanList.add(scanResult);
1065                     } else if (DBG) {
1066                         Log.w(TAG, "misformatted scan result for: " + line);
1067                     }
1068                 }
1069                 lineBeg = lineEnd + 1;
1070             }
1071         }
1072         mWifiStateTracker.setScanResultsList(scanList);
1073         return scanList;
1074     }
1075 
1076     /**
1077      * Parse the scan result line passed to us by wpa_supplicant (helper).
1078      * @param line the line to parse
1079      * @return the {@link ScanResult} object
1080      */
parseScanResult(String line)1081     private ScanResult parseScanResult(String line) {
1082         ScanResult scanResult = null;
1083         if (line != null) {
1084             /*
1085              * Cache implementation (LinkedHashMap) is not synchronized, thus,
1086              * must synchronized here!
1087              */
1088             synchronized (mScanResultCache) {
1089                 String[] result = scanResultPattern.split(line);
1090                 if (3 <= result.length && result.length <= 5) {
1091                     String bssid = result[0];
1092                     // bssid | frequency | level | flags | ssid
1093                     int frequency;
1094                     int level;
1095                     try {
1096                         frequency = Integer.parseInt(result[1]);
1097                         level = Integer.parseInt(result[2]);
1098                         /* some implementations avoid negative values by adding 256
1099                          * so we need to adjust for that here.
1100                          */
1101                         if (level > 0) level -= 256;
1102                     } catch (NumberFormatException e) {
1103                         frequency = 0;
1104                         level = 0;
1105                     }
1106 
1107                     /*
1108                      * The formatting of the results returned by
1109                      * wpa_supplicant is intended to make the fields
1110                      * line up nicely when printed,
1111                      * not to make them easy to parse. So we have to
1112                      * apply some heuristics to figure out which field
1113                      * is the SSID and which field is the flags.
1114                      */
1115                     String ssid;
1116                     String flags;
1117                     if (result.length == 4) {
1118                         if (result[3].charAt(0) == '[') {
1119                             flags = result[3];
1120                             ssid = "";
1121                         } else {
1122                             flags = "";
1123                             ssid = result[3];
1124                         }
1125                     } else if (result.length == 5) {
1126                         flags = result[3];
1127                         ssid = result[4];
1128                     } else {
1129                         // Here, we must have 3 fields: no flags and ssid
1130                         // set
1131                         flags = "";
1132                         ssid = "";
1133                     }
1134 
1135                     // bssid + ssid is the hash key
1136                     String key = bssid + ssid;
1137                     scanResult = mScanResultCache.get(key);
1138                     if (scanResult != null) {
1139                         scanResult.level = level;
1140                         scanResult.SSID = ssid;
1141                         scanResult.capabilities = flags;
1142                         scanResult.frequency = frequency;
1143                     } else {
1144                         // Do not add scan results that have no SSID set
1145                         if (0 < ssid.trim().length()) {
1146                             scanResult =
1147                                 new ScanResult(
1148                                     ssid, bssid, flags, level, frequency);
1149                             mScanResultCache.put(key, scanResult);
1150                         }
1151                     }
1152                 } else {
1153                     Log.w(TAG, "Misformatted scan result text with " +
1154                           result.length + " fields: " + line);
1155                 }
1156             }
1157         }
1158 
1159         return scanResult;
1160     }
1161 
1162     /**
1163      * Parse the "flags" field passed back in a scan result by wpa_supplicant,
1164      * and construct a {@code WifiConfiguration} that describes the encryption,
1165      * key management, and authenticaion capabilities of the access point.
1166      * @param flags the string returned by wpa_supplicant
1167      * @return the {@link WifiConfiguration} object, filled in
1168      */
parseScanFlags(String flags)1169     WifiConfiguration parseScanFlags(String flags) {
1170         WifiConfiguration config = new WifiConfiguration();
1171 
1172         if (flags.length() == 0) {
1173             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
1174         }
1175         // ... to be implemented
1176         return config;
1177     }
1178 
1179     /**
1180      * Tell the supplicant to persist the current list of configured networks.
1181      * @return {@code true} if the operation succeeded
1182      */
saveConfiguration()1183     public boolean saveConfiguration() {
1184         boolean result;
1185         enforceChangePermission();
1186         synchronized (mWifiStateTracker) {
1187             result = WifiNative.saveConfigCommand();
1188             if (result && mNeedReconfig) {
1189                 mNeedReconfig = false;
1190                 result = WifiNative.reloadConfigCommand();
1191 
1192                 if (result) {
1193                     Intent intent = new Intent(WifiManager.NETWORK_IDS_CHANGED_ACTION);
1194                     mContext.sendBroadcast(intent);
1195                 }
1196             }
1197         }
1198         // Inform the backup manager about a data change
1199         IBackupManager ibm = IBackupManager.Stub.asInterface(
1200                 ServiceManager.getService(Context.BACKUP_SERVICE));
1201         if (ibm != null) {
1202             try {
1203                 ibm.dataChanged("com.android.providers.settings");
1204             } catch (Exception e) {
1205                 // Try again later
1206             }
1207         }
1208         return result;
1209     }
1210 
1211     /**
1212      * Set the number of radio frequency channels that are allowed to be used
1213      * in the current regulatory domain. This method should be used only
1214      * if the correct number of channels cannot be determined automatically
1215      * for some reason. If the operation is successful, the new value may be
1216      * persisted as a Secure setting.
1217      * @param numChannels the number of allowed channels. Must be greater than 0
1218      * and less than or equal to 16.
1219      * @param persist {@code true} if the setting should be remembered.
1220      * @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
1221      * {@code numChannels} is outside the valid range.
1222      */
setNumAllowedChannels(int numChannels, boolean persist)1223     public boolean setNumAllowedChannels(int numChannels, boolean persist) {
1224         Log.i(TAG, "WifiService trying to setNumAllowed to "+numChannels+
1225                 " with persist set to "+persist);
1226         enforceChangePermission();
1227         /*
1228          * Validate the argument. We'd like to let the Wi-Fi driver do this,
1229          * but if Wi-Fi isn't currently enabled, that's not possible, and
1230          * we want to persist the setting anyway,so that it will take
1231          * effect when Wi-Fi does become enabled.
1232          */
1233         boolean found = false;
1234         for (int validChan : sValidRegulatoryChannelCounts) {
1235             if (validChan == numChannels) {
1236                 found = true;
1237                 break;
1238             }
1239         }
1240         if (!found) {
1241             return false;
1242         }
1243 
1244         if (persist) {
1245             Settings.Secure.putInt(mContext.getContentResolver(),
1246                                    Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
1247                                    numChannels);
1248         }
1249         mWifiStateTracker.setNumAllowedChannels(numChannels);
1250         return true;
1251     }
1252 
1253     /**
1254      * Return the number of frequency channels that are allowed
1255      * to be used in the current regulatory domain.
1256      * @return the number of allowed channels, or {@code -1} if an error occurs
1257      */
getNumAllowedChannels()1258     public int getNumAllowedChannels() {
1259         int numChannels;
1260 
1261         enforceAccessPermission();
1262         synchronized (mWifiStateTracker) {
1263             /*
1264              * If we can't get the value from the driver (e.g., because
1265              * Wi-Fi is not currently enabled), get the value from
1266              * Settings.
1267              */
1268             numChannels = WifiNative.getNumAllowedChannelsCommand();
1269             if (numChannels < 0) {
1270                 numChannels = Settings.Secure.getInt(mContext.getContentResolver(),
1271                                                      Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
1272                                                      -1);
1273             }
1274         }
1275         return numChannels;
1276     }
1277 
1278     /**
1279      * Return the list of valid values for the number of allowed radio channels
1280      * for various regulatory domains.
1281      * @return the list of channel counts
1282      */
getValidChannelCounts()1283     public int[] getValidChannelCounts() {
1284         enforceAccessPermission();
1285         return sValidRegulatoryChannelCounts;
1286     }
1287 
1288     /**
1289      * Return the DHCP-assigned addresses from the last successful DHCP request,
1290      * if any.
1291      * @return the DHCP information
1292      */
getDhcpInfo()1293     public DhcpInfo getDhcpInfo() {
1294         enforceAccessPermission();
1295         return mWifiStateTracker.getDhcpInfo();
1296     }
1297 
1298     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1299         @Override
1300         public void onReceive(Context context, Intent intent) {
1301             String action = intent.getAction();
1302 
1303             long idleMillis = Settings.Gservices.getLong(mContext.getContentResolver(),
1304                                                   Settings.Gservices.WIFI_IDLE_MS, DEFAULT_IDLE_MILLIS);
1305             int stayAwakeConditions =
1306                     Settings.System.getInt(mContext.getContentResolver(),
1307                                            Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
1308             if (action.equals(Intent.ACTION_SCREEN_ON)) {
1309                 Log.d(TAG, "ACTION_SCREEN_ON");
1310                 mAlarmManager.cancel(mIdleIntent);
1311                 mDeviceIdle = false;
1312                 mScreenOff = false;
1313                 mWifiStateTracker.enableRssiPolling(true);
1314             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1315                 Log.d(TAG, "ACTION_SCREEN_OFF");
1316                 mScreenOff = true;
1317                 mWifiStateTracker.enableRssiPolling(false);
1318                 /*
1319                  * Set a timer to put Wi-Fi to sleep, but only if the screen is off
1320                  * AND the "stay on while plugged in" setting doesn't match the
1321                  * current power conditions (i.e, not plugged in, plugged in to USB,
1322                  * or plugged in to AC).
1323                  */
1324                 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
1325                     WifiInfo info = mWifiStateTracker.requestConnectionInfo();
1326                     if (info.getSupplicantState() != SupplicantState.COMPLETED) {
1327                         // we used to go to sleep immediately, but this caused some race conditions
1328                         // we don't have time to track down for this release.  Delay instead, but not
1329                         // as long as we would if connected (below)
1330                         // TODO - fix the race conditions and switch back to the immediate turn-off
1331                         long triggerTime = System.currentTimeMillis() + (2*60*1000); // 2 min
1332                         Log.d(TAG, "setting ACTION_DEVICE_IDLE timer for 120,000 ms");
1333                         mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
1334                         //  // do not keep Wifi awake when screen is off if Wifi is not associated
1335                         //  mDeviceIdle = true;
1336                         //  updateWifiState();
1337                     } else {
1338                         long triggerTime = System.currentTimeMillis() + idleMillis;
1339                         Log.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
1340                         mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
1341                     }
1342                 }
1343                 /* we can return now -- there's nothing to do until we get the idle intent back */
1344                 return;
1345             } else if (action.equals(ACTION_DEVICE_IDLE)) {
1346                 Log.d(TAG, "got ACTION_DEVICE_IDLE");
1347                 mDeviceIdle = true;
1348             } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
1349                 /*
1350                  * Set a timer to put Wi-Fi to sleep, but only if the screen is off
1351                  * AND we are transitioning from a state in which the device was supposed
1352                  * to stay awake to a state in which it is not supposed to stay awake.
1353                  * If "stay awake" state is not changing, we do nothing, to avoid resetting
1354                  * the already-set timer.
1355                  */
1356                 int pluggedType = intent.getIntExtra("plugged", 0);
1357                 Log.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType);
1358                 if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) &&
1359                         !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) {
1360                     long triggerTime = System.currentTimeMillis() + idleMillis;
1361                     Log.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
1362                     mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
1363                     mPluggedType = pluggedType;
1364                     return;
1365                 }
1366                 mPluggedType = pluggedType;
1367             } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
1368                 boolean isBluetoothPlaying =
1369                         intent.getIntExtra(
1370                                 BluetoothA2dp.EXTRA_SINK_STATE,
1371                                 BluetoothA2dp.STATE_DISCONNECTED) == BluetoothA2dp.STATE_PLAYING;
1372                 mWifiStateTracker.setBluetoothScanMode(isBluetoothPlaying);
1373             } else {
1374                 return;
1375             }
1376 
1377             updateWifiState();
1378         }
1379 
1380         /**
1381          * Determines whether the Wi-Fi chipset should stay awake or be put to
1382          * sleep. Looks at the setting for the sleep policy and the current
1383          * conditions.
1384          *
1385          * @see #shouldDeviceStayAwake(int, int)
1386          */
1387         private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) {
1388             int wifiSleepPolicy = Settings.System.getInt(mContext.getContentResolver(),
1389                     Settings.System.WIFI_SLEEP_POLICY, Settings.System.WIFI_SLEEP_POLICY_DEFAULT);
1390 
1391             if (wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER) {
1392                 // Never sleep
1393                 return true;
1394             } else if ((wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) &&
1395                     (pluggedType != 0)) {
1396                 // Never sleep while plugged, and we're plugged
1397                 return true;
1398             } else {
1399                 // Default
1400                 return shouldDeviceStayAwake(stayAwakeConditions, pluggedType);
1401             }
1402         }
1403 
1404         /**
1405          * Determine whether the bit value corresponding to {@code pluggedType} is set in
1406          * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value
1407          * of {@code 0} isn't really a plugged type, but rather an indication that the
1408          * device isn't plugged in at all, there is no bit value corresponding to a
1409          * {@code pluggedType} value of {@code 0}. That is why we shift by
1410          * {@code pluggedType&nbsp;&#8212;&nbsp;1} instead of by {@code pluggedType}.
1411          * @param stayAwakeConditions a bit string specifying which "plugged types" should
1412          * keep the device (and hence Wi-Fi) awake.
1413          * @param pluggedType the type of plug (USB, AC, or none) for which the check is
1414          * being made
1415          * @return {@code true} if {@code pluggedType} indicates that the device is
1416          * supposed to stay awake, {@code false} otherwise.
1417          */
1418         private boolean shouldDeviceStayAwake(int stayAwakeConditions, int pluggedType) {
1419             return (stayAwakeConditions & pluggedType) != 0;
1420         }
1421     };
1422 
sendEnableMessage(boolean enable, boolean persist, int uid)1423     private void sendEnableMessage(boolean enable, boolean persist, int uid) {
1424         Message msg = Message.obtain(mWifiHandler,
1425                                      (enable ? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI),
1426                                      (persist ? 1 : 0), uid);
1427         msg.sendToTarget();
1428     }
1429 
sendStartMessage(boolean scanOnlyMode)1430     private void sendStartMessage(boolean scanOnlyMode) {
1431         Message.obtain(mWifiHandler, MESSAGE_START_WIFI, scanOnlyMode ? 1 : 0, 0).sendToTarget();
1432     }
1433 
updateWifiState()1434     private void updateWifiState() {
1435         boolean wifiEnabled = getPersistedWifiEnabled();
1436         boolean airplaneMode = isAirplaneModeOn() && !mAirplaneModeOverwridden;
1437         boolean lockHeld = mLocks.hasLocks();
1438         int strongestLockMode;
1439         boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;
1440         boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
1441         if (mDeviceIdle && lockHeld) {
1442             strongestLockMode = mLocks.getStrongestLockMode();
1443         } else {
1444             strongestLockMode = WifiManager.WIFI_MODE_FULL;
1445         }
1446 
1447         synchronized (mWifiHandler) {
1448             if (mWifiState == WIFI_STATE_ENABLING && !airplaneMode) {
1449                 return;
1450             }
1451             if (wifiShouldBeEnabled) {
1452                 if (wifiShouldBeStarted) {
1453                     sWakeLock.acquire();
1454                     sendEnableMessage(true, false, mLastEnableUid);
1455                     sWakeLock.acquire();
1456                     sendStartMessage(strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
1457                 } else {
1458                     int wakeLockTimeout =
1459                             Settings.Secure.getInt(
1460                                     mContext.getContentResolver(),
1461                                     Settings.Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
1462                                     DEFAULT_WAKELOCK_TIMEOUT);
1463                     /*
1464                      * The following wakelock is held in order to ensure
1465                      * that the connectivity manager has time to fail over
1466                      * to the mobile data network. The connectivity manager
1467                      * releases it once mobile data connectivity has been
1468                      * established. If connectivity cannot be established,
1469                      * the wakelock is released after wakeLockTimeout
1470                      * milliseconds have elapsed.
1471                      */
1472                     sDriverStopWakeLock.acquire();
1473                     mWifiHandler.sendEmptyMessage(MESSAGE_STOP_WIFI);
1474                     mWifiHandler.sendEmptyMessageDelayed(MESSAGE_RELEASE_WAKELOCK, wakeLockTimeout);
1475                 }
1476             } else {
1477                 sWakeLock.acquire();
1478                 sendEnableMessage(false, false, mLastEnableUid);
1479             }
1480         }
1481     }
1482 
registerForBroadcasts()1483     private void registerForBroadcasts() {
1484         IntentFilter intentFilter = new IntentFilter();
1485         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
1486         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
1487         intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
1488         intentFilter.addAction(ACTION_DEVICE_IDLE);
1489         intentFilter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
1490         mContext.registerReceiver(mReceiver, intentFilter);
1491     }
1492 
isAirplaneSensitive()1493     private boolean isAirplaneSensitive() {
1494         String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
1495                 Settings.System.AIRPLANE_MODE_RADIOS);
1496         return airplaneModeRadios == null
1497             || airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
1498     }
1499 
isAirplaneToggleable()1500     private boolean isAirplaneToggleable() {
1501         String toggleableRadios = Settings.System.getString(mContext.getContentResolver(),
1502                 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
1503         return toggleableRadios != null
1504             && toggleableRadios.contains(Settings.System.RADIO_WIFI);
1505     }
1506 
1507     /**
1508      * Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is
1509      * currently on.
1510      * @return {@code true} if airplane mode is on.
1511      */
isAirplaneModeOn()1512     private boolean isAirplaneModeOn() {
1513         return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(),
1514                 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
1515     }
1516 
1517     /**
1518      * Handler that allows posting to the WifiThread.
1519      */
1520     private class WifiHandler extends Handler {
WifiHandler(Looper looper)1521         public WifiHandler(Looper looper) {
1522             super(looper);
1523         }
1524 
1525         @Override
handleMessage(Message msg)1526         public void handleMessage(Message msg) {
1527             switch (msg.what) {
1528 
1529                 case MESSAGE_ENABLE_WIFI:
1530                     setWifiEnabledBlocking(true, msg.arg1 == 1, msg.arg2);
1531                     sWakeLock.release();
1532                     break;
1533 
1534                 case MESSAGE_START_WIFI:
1535                     mWifiStateTracker.setScanOnlyMode(msg.arg1 != 0);
1536                     mWifiStateTracker.restart();
1537                     sWakeLock.release();
1538                     break;
1539 
1540                 case MESSAGE_DISABLE_WIFI:
1541                     // a non-zero msg.arg1 value means the "enabled" setting
1542                     // should be persisted
1543                     setWifiEnabledBlocking(false, msg.arg1 == 1, msg.arg2);
1544                     sWakeLock.release();
1545                     break;
1546 
1547                 case MESSAGE_STOP_WIFI:
1548                     mWifiStateTracker.disconnectAndStop();
1549                     // don't release wakelock
1550                     break;
1551 
1552                 case MESSAGE_RELEASE_WAKELOCK:
1553                     synchronized (sDriverStopWakeLock) {
1554                         if (sDriverStopWakeLock.isHeld()) {
1555                             sDriverStopWakeLock.release();
1556                         }
1557                     }
1558                     break;
1559             }
1560         }
1561     }
1562 
1563     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1564     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1565         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1566                 != PackageManager.PERMISSION_GRANTED) {
1567             pw.println("Permission Denial: can't dump WifiService from from pid="
1568                     + Binder.getCallingPid()
1569                     + ", uid=" + Binder.getCallingUid());
1570             return;
1571         }
1572         pw.println("Wi-Fi is " + stateName(mWifiState));
1573         pw.println("Stay-awake conditions: " +
1574                 Settings.System.getInt(mContext.getContentResolver(),
1575                                        Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
1576         pw.println();
1577 
1578         pw.println("Internal state:");
1579         pw.println(mWifiStateTracker);
1580         pw.println();
1581         pw.println("Latest scan results:");
1582         List<ScanResult> scanResults = mWifiStateTracker.getScanResultsList();
1583         if (scanResults != null && scanResults.size() != 0) {
1584             pw.println("  BSSID              Frequency   RSSI  Flags             SSID");
1585             for (ScanResult r : scanResults) {
1586                 pw.printf("  %17s  %9d  %5d  %-16s  %s%n",
1587                                          r.BSSID,
1588                                          r.frequency,
1589                                          r.level,
1590                                          r.capabilities,
1591                                          r.SSID == null ? "" : r.SSID);
1592             }
1593         }
1594         pw.println();
1595         pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
1596                 mScanLocksAcquired + " scan");
1597         pw.println("Locks released: " + mFullLocksReleased + " full, " +
1598                 mScanLocksReleased + " scan");
1599         pw.println();
1600         pw.println("Locks held:");
1601         mLocks.dump(pw);
1602     }
1603 
stateName(int wifiState)1604     private static String stateName(int wifiState) {
1605         switch (wifiState) {
1606             case WIFI_STATE_DISABLING:
1607                 return "disabling";
1608             case WIFI_STATE_DISABLED:
1609                 return "disabled";
1610             case WIFI_STATE_ENABLING:
1611                 return "enabling";
1612             case WIFI_STATE_ENABLED:
1613                 return "enabled";
1614             case WIFI_STATE_UNKNOWN:
1615                 return "unknown state";
1616             default:
1617                 return "[invalid state]";
1618         }
1619     }
1620 
1621     private class WifiLock extends DeathRecipient {
WifiLock(int lockMode, String tag, IBinder binder)1622         WifiLock(int lockMode, String tag, IBinder binder) {
1623             super(lockMode, tag, binder);
1624         }
1625 
binderDied()1626         public void binderDied() {
1627             synchronized (mLocks) {
1628                 releaseWifiLockLocked(mBinder);
1629             }
1630         }
1631 
toString()1632         public String toString() {
1633             return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
1634         }
1635     }
1636 
1637     private class LockList {
1638         private List<WifiLock> mList;
1639 
LockList()1640         private LockList() {
1641             mList = new ArrayList<WifiLock>();
1642         }
1643 
hasLocks()1644         private synchronized boolean hasLocks() {
1645             return !mList.isEmpty();
1646         }
1647 
getStrongestLockMode()1648         private synchronized int getStrongestLockMode() {
1649             if (mList.isEmpty()) {
1650                 return WifiManager.WIFI_MODE_FULL;
1651             }
1652             for (WifiLock l : mList) {
1653                 if (l.mMode == WifiManager.WIFI_MODE_FULL) {
1654                     return WifiManager.WIFI_MODE_FULL;
1655                 }
1656             }
1657             return WifiManager.WIFI_MODE_SCAN_ONLY;
1658         }
1659 
addLock(WifiLock lock)1660         private void addLock(WifiLock lock) {
1661             if (findLockByBinder(lock.mBinder) < 0) {
1662                 mList.add(lock);
1663             }
1664         }
1665 
removeLock(IBinder binder)1666         private WifiLock removeLock(IBinder binder) {
1667             int index = findLockByBinder(binder);
1668             if (index >= 0) {
1669                 WifiLock ret = mList.remove(index);
1670                 ret.unlinkDeathRecipient();
1671                 return ret;
1672             } else {
1673                 return null;
1674             }
1675         }
1676 
findLockByBinder(IBinder binder)1677         private int findLockByBinder(IBinder binder) {
1678             int size = mList.size();
1679             for (int i = size - 1; i >= 0; i--)
1680                 if (mList.get(i).mBinder == binder)
1681                     return i;
1682             return -1;
1683         }
1684 
dump(PrintWriter pw)1685         private void dump(PrintWriter pw) {
1686             for (WifiLock l : mList) {
1687                 pw.print("    ");
1688                 pw.println(l);
1689             }
1690         }
1691     }
1692 
acquireWifiLock(IBinder binder, int lockMode, String tag)1693     public boolean acquireWifiLock(IBinder binder, int lockMode, String tag) {
1694         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1695         if (lockMode != WifiManager.WIFI_MODE_FULL && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY) {
1696             return false;
1697         }
1698         WifiLock wifiLock = new WifiLock(lockMode, tag, binder);
1699         synchronized (mLocks) {
1700             return acquireWifiLockLocked(wifiLock);
1701         }
1702     }
1703 
acquireWifiLockLocked(WifiLock wifiLock)1704     private boolean acquireWifiLockLocked(WifiLock wifiLock) {
1705         Log.d(TAG, "acquireWifiLockLocked: " + wifiLock);
1706 
1707         mLocks.addLock(wifiLock);
1708 
1709         int uid = Binder.getCallingUid();
1710         long ident = Binder.clearCallingIdentity();
1711         try {
1712             switch(wifiLock.mMode) {
1713             case WifiManager.WIFI_MODE_FULL:
1714                 ++mFullLocksAcquired;
1715                 mBatteryStats.noteFullWifiLockAcquired(uid);
1716                 break;
1717             case WifiManager.WIFI_MODE_SCAN_ONLY:
1718                 ++mScanLocksAcquired;
1719                 mBatteryStats.noteScanWifiLockAcquired(uid);
1720                 break;
1721             }
1722         } catch (RemoteException e) {
1723         } finally {
1724             Binder.restoreCallingIdentity(ident);
1725         }
1726 
1727         updateWifiState();
1728         return true;
1729     }
1730 
releaseWifiLock(IBinder lock)1731     public boolean releaseWifiLock(IBinder lock) {
1732         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1733         synchronized (mLocks) {
1734             return releaseWifiLockLocked(lock);
1735         }
1736     }
1737 
releaseWifiLockLocked(IBinder lock)1738     private boolean releaseWifiLockLocked(IBinder lock) {
1739         boolean hadLock;
1740 
1741         WifiLock wifiLock = mLocks.removeLock(lock);
1742 
1743         Log.d(TAG, "releaseWifiLockLocked: " + wifiLock);
1744 
1745         hadLock = (wifiLock != null);
1746 
1747         if (hadLock) {
1748             int uid = Binder.getCallingUid();
1749             long ident = Binder.clearCallingIdentity();
1750             try {
1751                 switch(wifiLock.mMode) {
1752                     case WifiManager.WIFI_MODE_FULL:
1753                         ++mFullLocksReleased;
1754                         mBatteryStats.noteFullWifiLockReleased(uid);
1755                         break;
1756                     case WifiManager.WIFI_MODE_SCAN_ONLY:
1757                         ++mScanLocksReleased;
1758                         mBatteryStats.noteScanWifiLockReleased(uid);
1759                         break;
1760                 }
1761             } catch (RemoteException e) {
1762             } finally {
1763                 Binder.restoreCallingIdentity(ident);
1764             }
1765         }
1766         // TODO - should this only happen if you hadLock?
1767         updateWifiState();
1768         return hadLock;
1769     }
1770 
1771     private abstract class DeathRecipient
1772             implements IBinder.DeathRecipient {
1773         String mTag;
1774         int mMode;
1775         IBinder mBinder;
1776 
DeathRecipient(int mode, String tag, IBinder binder)1777         DeathRecipient(int mode, String tag, IBinder binder) {
1778             super();
1779             mTag = tag;
1780             mMode = mode;
1781             mBinder = binder;
1782             try {
1783                 mBinder.linkToDeath(this, 0);
1784             } catch (RemoteException e) {
1785                 binderDied();
1786             }
1787         }
1788 
unlinkDeathRecipient()1789         void unlinkDeathRecipient() {
1790             mBinder.unlinkToDeath(this, 0);
1791         }
1792     }
1793 
1794     private class Multicaster extends DeathRecipient {
Multicaster(String tag, IBinder binder)1795         Multicaster(String tag, IBinder binder) {
1796             super(Binder.getCallingUid(), tag, binder);
1797         }
1798 
binderDied()1799         public void binderDied() {
1800             Log.e(TAG, "Multicaster binderDied");
1801             synchronized (mMulticasters) {
1802                 int i = mMulticasters.indexOf(this);
1803                 if (i != -1) {
1804                     removeMulticasterLocked(i, mMode);
1805                 }
1806             }
1807         }
1808 
toString()1809         public String toString() {
1810             return "Multicaster{" + mTag + " binder=" + mBinder + "}";
1811         }
1812 
getUid()1813         public int getUid() {
1814             return mMode;
1815         }
1816     }
1817 
acquireMulticastLock(IBinder binder, String tag)1818     public void acquireMulticastLock(IBinder binder, String tag) {
1819         enforceMulticastChangePermission();
1820 
1821         synchronized (mMulticasters) {
1822             mMulticastEnabled++;
1823             mMulticasters.add(new Multicaster(tag, binder));
1824             // Note that we could call stopPacketFiltering only when
1825             // our new size == 1 (first call), but this function won't
1826             // be called often and by making the stopPacket call each
1827             // time we're less fragile and self-healing.
1828             synchronized (mWifiStateTracker) {
1829                 WifiNative.stopPacketFiltering();
1830             }
1831         }
1832 
1833         int uid = Binder.getCallingUid();
1834         Long ident = Binder.clearCallingIdentity();
1835         try {
1836             mBatteryStats.noteWifiMulticastEnabled(uid);
1837         } catch (RemoteException e) {
1838         } finally {
1839             Binder.restoreCallingIdentity(ident);
1840         }
1841     }
1842 
releaseMulticastLock()1843     public void releaseMulticastLock() {
1844         enforceMulticastChangePermission();
1845 
1846         int uid = Binder.getCallingUid();
1847         synchronized (mMulticasters) {
1848             mMulticastDisabled++;
1849             int size = mMulticasters.size();
1850             for (int i = size - 1; i >= 0; i--) {
1851                 Multicaster m = mMulticasters.get(i);
1852                 if ((m != null) && (m.getUid() == uid)) {
1853                     removeMulticasterLocked(i, uid);
1854                 }
1855             }
1856         }
1857     }
1858 
removeMulticasterLocked(int i, int uid)1859     private void removeMulticasterLocked(int i, int uid)
1860     {
1861         Multicaster removed = mMulticasters.remove(i);
1862         if (removed != null) {
1863             removed.unlinkDeathRecipient();
1864         }
1865         if (mMulticasters.size() == 0) {
1866             synchronized (mWifiStateTracker) {
1867                 WifiNative.startPacketFiltering();
1868             }
1869         }
1870 
1871         Long ident = Binder.clearCallingIdentity();
1872         try {
1873             mBatteryStats.noteWifiMulticastDisabled(uid);
1874         } catch (RemoteException e) {
1875         } finally {
1876             Binder.restoreCallingIdentity(ident);
1877         }
1878     }
1879 
isMulticastEnabled()1880     public boolean isMulticastEnabled() {
1881         enforceAccessPermission();
1882 
1883         synchronized (mMulticasters) {
1884             return (mMulticasters.size() > 0);
1885         }
1886     }
1887 }
1888