• 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 static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
26 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
27 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
28 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
29 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
30 
31 import android.app.AlarmManager;
32 import android.app.PendingIntent;
33 import android.bluetooth.BluetoothA2dp;
34 import android.bluetooth.BluetoothDevice;
35 import android.content.BroadcastReceiver;
36 import android.content.ContentResolver;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.IntentFilter;
40 import android.content.pm.PackageManager;
41 import android.net.wifi.IWifiManager;
42 import android.net.wifi.WifiInfo;
43 import android.net.wifi.WifiManager;
44 import android.net.wifi.WifiNative;
45 import android.net.wifi.WifiStateTracker;
46 import android.net.wifi.ScanResult;
47 import android.net.wifi.WifiConfiguration;
48 import android.net.wifi.SupplicantState;
49 import android.net.wifi.WifiConfiguration.KeyMgmt;
50 import android.net.ConnectivityManager;
51 import android.net.InterfaceConfiguration;
52 import android.net.NetworkStateTracker;
53 import android.net.DhcpInfo;
54 import android.net.NetworkUtils;
55 import android.os.Binder;
56 import android.os.Environment;
57 import android.os.Handler;
58 import android.os.HandlerThread;
59 import android.os.IBinder;
60 import android.os.INetworkManagementService;
61 import android.os.Looper;
62 import android.os.Message;
63 import android.os.PowerManager;
64 import android.os.Process;
65 import android.os.RemoteException;
66 import android.os.ServiceManager;
67 import android.os.WorkSource;
68 import android.provider.Settings;
69 import android.util.Slog;
70 import android.text.TextUtils;
71 
72 import java.io.BufferedInputStream;
73 import java.io.BufferedOutputStream;
74 import java.io.DataInputStream;
75 import java.io.DataOutputStream;
76 import java.io.EOFException;
77 import java.io.FileDescriptor;
78 import java.io.FileInputStream;
79 import java.io.FileOutputStream;
80 import java.io.IOException;
81 import java.io.PrintWriter;
82 import java.net.UnknownHostException;
83 import java.util.ArrayList;
84 import java.util.BitSet;
85 import java.util.HashMap;
86 import java.util.LinkedHashMap;
87 import java.util.List;
88 import java.util.Map;
89 import java.util.Set;
90 import java.util.regex.Pattern;
91 import java.util.UUID;
92 
93 import com.android.internal.app.IBatteryStats;
94 import android.app.backup.IBackupManager;
95 import com.android.server.am.BatteryStatsService;
96 import com.android.internal.R;
97 
98 /**
99  * WifiService handles remote WiFi operation requests by implementing
100  * the IWifiManager interface. It also creates a WifiMonitor to listen
101  * for Wifi-related events.
102  *
103  * @hide
104  */
105 public class WifiService extends IWifiManager.Stub {
106     private static final String TAG = "WifiService";
107     private static final boolean DBG = false;
108     private static final Pattern scanResultPattern = Pattern.compile("\t+");
109     private final WifiStateTracker mWifiStateTracker;
110     /* TODO: fetch a configurable interface */
111     private static final String SOFTAP_IFACE = "wl0.1";
112 
113     private Context mContext;
114     private int mWifiApState;
115 
116     private AlarmManager mAlarmManager;
117     private PendingIntent mIdleIntent;
118     private static final int IDLE_REQUEST = 0;
119     private boolean mScreenOff;
120     private boolean mDeviceIdle;
121     private int mPluggedType;
122 
123     private enum DriverAction {DRIVER_UNLOAD, NO_DRIVER_UNLOAD};
124 
125     // true if the user enabled Wifi while in airplane mode
126     private boolean mAirplaneModeOverwridden;
127 
128     private final LockList mLocks = new LockList();
129     // some wifi lock statistics
130     private int mFullHighPerfLocksAcquired;
131     private int mFullHighPerfLocksReleased;
132     private int mFullLocksAcquired;
133     private int mFullLocksReleased;
134     private int mScanLocksAcquired;
135     private int mScanLocksReleased;
136 
137     private final List<Multicaster> mMulticasters =
138             new ArrayList<Multicaster>();
139     private int mMulticastEnabled;
140     private int mMulticastDisabled;
141 
142     private final IBatteryStats mBatteryStats;
143 
144     private INetworkManagementService nwService;
145     ConnectivityManager mCm;
146     private WifiWatchdogService mWifiWatchdogService = null;
147     private String[] mWifiRegexs;
148 
149     /**
150      * See {@link Settings.Secure#WIFI_IDLE_MS}. This is the default value if a
151      * Settings.Secure value is not present. This timeout value is chosen as
152      * the approximate point at which the battery drain caused by Wi-Fi
153      * being enabled but not active exceeds the battery drain caused by
154      * re-establishing a connection to the mobile data network.
155      */
156     private static final long DEFAULT_IDLE_MILLIS = 15 * 60 * 1000; /* 15 minutes */
157 
158     private static final String WAKELOCK_TAG = "*wifi*";
159 
160     /**
161      * The maximum amount of time to hold the wake lock after a disconnect
162      * caused by stopping the driver. Establishing an EDGE connection has been
163      * observed to take about 5 seconds under normal circumstances. This
164      * provides a bit of extra margin.
165      * <p>
166      * See {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}.
167      * This is the default value if a Settings.Secure value is not present.
168      */
169     private static final int DEFAULT_WAKELOCK_TIMEOUT = 8000;
170 
171     // Wake lock used by driver-stop operation
172     private static PowerManager.WakeLock sDriverStopWakeLock;
173     // Wake lock used by other operations
174     private static PowerManager.WakeLock sWakeLock;
175 
176     private static final int MESSAGE_ENABLE_WIFI        = 0;
177     private static final int MESSAGE_DISABLE_WIFI       = 1;
178     private static final int MESSAGE_STOP_WIFI          = 2;
179     private static final int MESSAGE_START_WIFI         = 3;
180     private static final int MESSAGE_RELEASE_WAKELOCK   = 4;
181     private static final int MESSAGE_UPDATE_STATE       = 5;
182     private static final int MESSAGE_START_ACCESS_POINT = 6;
183     private static final int MESSAGE_STOP_ACCESS_POINT  = 7;
184     private static final int MESSAGE_SET_CHANNELS       = 8;
185     private static final int MESSAGE_ENABLE_NETWORKS    = 9;
186     private static final int MESSAGE_START_SCAN         = 10;
187     private static final int MESSAGE_REPORT_WORKSOURCE  = 11;
188     private static final int MESSAGE_ENABLE_RSSI_POLLING = 12;
189     private static final int MESSAGE_WRITE_WIFI_AP_CONFIG = 13;
190     private static final int MESSAGE_READ_WIFI_AP_CONFIG = 14;
191 
192 
193     private final  WifiHandler mWifiHandler;
194 
195     /*
196      * Cache of scan results objects (size is somewhat arbitrary)
197      */
198     private static final int SCAN_RESULT_CACHE_SIZE = 80;
199     private final LinkedHashMap<String, ScanResult> mScanResultCache;
200 
201     /*
202      * Character buffer used to parse scan results (optimization)
203      */
204     private static final int SCAN_RESULT_BUFFER_SIZE = 512;
205     private boolean mNeedReconfig;
206 
207     /**
208      * Temporary for computing UIDS that are responsible for starting WIFI.
209      * Protected by mWifiStateTracker lock.
210      */
211     private final WorkSource mTmpWorkSource = new WorkSource();
212 
213     /*
214      * Last UID that asked to enable WIFI.
215      */
216     private int mLastEnableUid = Process.myUid();
217 
218     /*
219      * Last UID that asked to enable WIFI AP.
220      */
221     private int mLastApEnableUid = Process.myUid();
222 
223 
224     /**
225      * Number of allowed radio frequency channels in various regulatory domains.
226      * This list is sufficient for 802.11b/g networks (2.4GHz range).
227      */
228     private static int[] sValidRegulatoryChannelCounts = new int[] {11, 13, 14};
229 
230     private static final String ACTION_DEVICE_IDLE =
231             "com.android.server.WifiManager.action.DEVICE_IDLE";
232 
233     private static final String WIFIAP_CONFIG_FILE = Environment.getDataDirectory() +
234             "/misc/wifi/softap.conf";
235 
236     private static final int WIFIAP_CONFIG_VERSION = 1;
237     private WifiConfiguration mWifiApConfig = new WifiConfiguration();
238     private final Object mWifiApConfigLock = new Object();
239 
WifiService(Context context, WifiStateTracker tracker)240     WifiService(Context context, WifiStateTracker tracker) {
241         mContext = context;
242         mWifiStateTracker = tracker;
243         mWifiStateTracker.enableRssiPolling(true);
244         mBatteryStats = BatteryStatsService.getService();
245 
246         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
247         nwService = INetworkManagementService.Stub.asInterface(b);
248 
249         mScanResultCache = new LinkedHashMap<String, ScanResult>(
250             SCAN_RESULT_CACHE_SIZE, 0.75f, true) {
251                 /*
252                  * Limit the cache size by SCAN_RESULT_CACHE_SIZE
253                  * elements
254                  */
255                 public boolean removeEldestEntry(Map.Entry eldest) {
256                     return SCAN_RESULT_CACHE_SIZE < this.size();
257                 }
258             };
259 
260         HandlerThread wifiThread = new HandlerThread("WifiService");
261         wifiThread.start();
262         mWifiHandler = new WifiHandler(wifiThread.getLooper());
263 
264         mWifiStateTracker.setWifiState(WIFI_STATE_DISABLED);
265         mWifiApState = WIFI_AP_STATE_DISABLED;
266 
267         mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
268         Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
269         mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
270 
271         PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
272         sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
273         sDriverStopWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
274 
275         mContext.registerReceiver(
276                 new BroadcastReceiver() {
277                     @Override
278                     public void onReceive(Context context, Intent intent) {
279                         // clear our flag indicating the user has overwridden airplane mode
280                         mAirplaneModeOverwridden = false;
281                         // on airplane disable, restore Wifi if the saved state indicates so
282                         if (!isAirplaneModeOn() && testAndClearWifiSavedState()) {
283                             persistWifiEnabled(true);
284                         }
285                         updateWifiState();
286                     }
287                 },
288                 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
289 
290         mContext.registerReceiver(
291             new BroadcastReceiver() {
292                 @Override
293                 public void onReceive(Context context, Intent intent) {
294 
295                   ArrayList<String> available = intent.getStringArrayListExtra(
296                           ConnectivityManager.EXTRA_AVAILABLE_TETHER);
297                   ArrayList<String> active = intent.getStringArrayListExtra(
298                           ConnectivityManager.EXTRA_ACTIVE_TETHER);
299                   updateTetherState(available, active);
300 
301                 }
302             },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
303 
304         //Initiate a read of Wifi Ap configuration
305         Message.obtain(mWifiHandler, MESSAGE_READ_WIFI_AP_CONFIG).sendToTarget();
306     }
307 
308     /**
309      * Check if Wi-Fi needs to be enabled and start
310      * if needed
311      *
312      * This function is used only at boot time
313      */
startWifi()314     public void startWifi() {
315         /* Start if Wi-Fi is enabled or the saved state indicates Wi-Fi was on */
316         boolean wifiEnabled = !isAirplaneModeOn()
317                 && (getPersistedWifiEnabled() || testAndClearWifiSavedState());
318         Slog.i(TAG, "WifiService starting up with Wi-Fi " +
319                 (wifiEnabled ? "enabled" : "disabled"));
320         setWifiEnabled(wifiEnabled);
321     }
322 
updateTetherState(ArrayList<String> available, ArrayList<String> tethered)323     private void updateTetherState(ArrayList<String> available, ArrayList<String> tethered) {
324 
325         boolean wifiTethered = false;
326         boolean wifiAvailable = false;
327 
328         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
329         INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
330 
331         mCm = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
332         mWifiRegexs = mCm.getTetherableWifiRegexs();
333 
334         for (String intf : available) {
335             for (String regex : mWifiRegexs) {
336                 if (intf.matches(regex)) {
337 
338                     InterfaceConfiguration ifcg = null;
339                     try {
340                         ifcg = service.getInterfaceConfig(intf);
341                         if (ifcg != null) {
342                             /* IP/netmask: 192.168.43.1/255.255.255.0 */
343                             ifcg.ipAddr = (192 << 24) + (168 << 16) + (43 << 8) + 1;
344                             ifcg.netmask = (255 << 24) + (255 << 16) + (255 << 8) + 0;
345                             ifcg.interfaceFlags = "up";
346 
347                             service.setInterfaceConfig(intf, ifcg);
348                         }
349                     } catch (Exception e) {
350                         Slog.e(TAG, "Error configuring interface " + intf + ", :" + e);
351                         try {
352                             nwService.stopAccessPoint();
353                         } catch (Exception ee) {
354                             Slog.e(TAG, "Could not stop AP, :" + ee);
355                         }
356                         setWifiApEnabledState(WIFI_AP_STATE_FAILED, 0, DriverAction.DRIVER_UNLOAD);
357                         return;
358                     }
359 
360                     if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
361                         Slog.e(TAG, "Error tethering "+intf);
362                     }
363                     break;
364                 }
365             }
366         }
367     }
368 
testAndClearWifiSavedState()369     private boolean testAndClearWifiSavedState() {
370         final ContentResolver cr = mContext.getContentResolver();
371         int wifiSavedState = 0;
372         try {
373             wifiSavedState = Settings.Secure.getInt(cr, Settings.Secure.WIFI_SAVED_STATE);
374             if(wifiSavedState == 1)
375                 Settings.Secure.putInt(cr, Settings.Secure.WIFI_SAVED_STATE, 0);
376         } catch (Settings.SettingNotFoundException e) {
377             ;
378         }
379         return (wifiSavedState == 1);
380     }
381 
getPersistedWifiEnabled()382     private boolean getPersistedWifiEnabled() {
383         final ContentResolver cr = mContext.getContentResolver();
384         try {
385             return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON) == 1;
386         } catch (Settings.SettingNotFoundException e) {
387             Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, 0);
388             return false;
389         }
390     }
391 
persistWifiEnabled(boolean enabled)392     private void persistWifiEnabled(boolean enabled) {
393         final ContentResolver cr = mContext.getContentResolver();
394         Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, enabled ? 1 : 0);
395     }
396 
getNetworkStateTracker()397     NetworkStateTracker getNetworkStateTracker() {
398         return mWifiStateTracker;
399     }
400 
401     /**
402      * see {@link android.net.wifi.WifiManager#pingSupplicant()}
403      * @return {@code true} if the operation succeeds
404      */
pingSupplicant()405     public boolean pingSupplicant() {
406         enforceChangePermission();
407 
408         return mWifiStateTracker.ping();
409     }
410 
411     /**
412      * see {@link android.net.wifi.WifiManager#startScan()}
413      */
startScan(boolean forceActive)414     public void startScan(boolean forceActive) {
415         enforceChangePermission();
416         if (mWifiHandler == null) return;
417 
418         Message.obtain(mWifiHandler, MESSAGE_START_SCAN, forceActive ? 1 : 0, 0).sendToTarget();
419     }
420 
421     /**
422      * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
423      * @param enable {@code true} to enable, {@code false} to disable.
424      * @return {@code true} if the enable/disable operation was
425      *         started or is already in the queue.
426      */
setWifiEnabled(boolean enable)427     public boolean setWifiEnabled(boolean enable) {
428         enforceChangePermission();
429         if (mWifiHandler == null) return false;
430 
431         synchronized (mWifiHandler) {
432             // caller may not have WAKE_LOCK permission - it's not required here
433             long ident = Binder.clearCallingIdentity();
434             sWakeLock.acquire();
435             Binder.restoreCallingIdentity(ident);
436 
437             mLastEnableUid = Binder.getCallingUid();
438             // set a flag if the user is enabling Wifi while in airplane mode
439             mAirplaneModeOverwridden = (enable && isAirplaneModeOn() && isAirplaneToggleable());
440             sendEnableMessage(enable, true, Binder.getCallingUid());
441         }
442 
443         return true;
444     }
445 
446     /**
447      * Enables/disables Wi-Fi synchronously.
448      * @param enable {@code true} to turn Wi-Fi on, {@code false} to turn it off.
449      * @param persist {@code true} if the setting should be persisted.
450      * @param uid The UID of the process making the request.
451      * @return {@code true} if the operation succeeds (or if the existing state
452      *         is the same as the requested state)
453      */
setWifiEnabledBlocking(boolean enable, boolean persist, int uid)454     private boolean setWifiEnabledBlocking(boolean enable, boolean persist, int uid) {
455         final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;
456         final int wifiState = mWifiStateTracker.getWifiState();
457 
458         if (wifiState == eventualWifiState) {
459             return true;
460         }
461         if (enable && isAirplaneModeOn() && !mAirplaneModeOverwridden) {
462             return false;
463         }
464 
465         /**
466          * Multiple calls to unregisterReceiver() cause exception and a system crash.
467          * This can happen if a supplicant is lost (or firmware crash occurs) and user indicates
468          * disable wifi at the same time.
469          * Avoid doing a disable when the current Wifi state is UNKNOWN
470          * TODO: Handle driver load fail and supplicant lost as seperate states
471          */
472         if ((wifiState == WIFI_STATE_UNKNOWN) && !enable) {
473             return false;
474         }
475 
476         /**
477          * Fail Wifi if AP is enabled
478          * TODO: Deprecate WIFI_STATE_UNKNOWN and rename it
479          * WIFI_STATE_FAILED
480          */
481         if ((mWifiApState == WIFI_AP_STATE_ENABLED) && enable) {
482             setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
483             return false;
484         }
485 
486         setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);
487 
488         if (enable) {
489             if (!mWifiStateTracker.loadDriver()) {
490                 Slog.e(TAG, "Failed to load Wi-Fi driver.");
491                 setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
492                 return false;
493             }
494             if (!mWifiStateTracker.startSupplicant()) {
495                 mWifiStateTracker.unloadDriver();
496                 Slog.e(TAG, "Failed to start supplicant daemon.");
497                 setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
498                 return false;
499             }
500 
501             registerForBroadcasts();
502             mWifiStateTracker.startEventLoop();
503 
504         } else {
505 
506             mContext.unregisterReceiver(mReceiver);
507            // Remove notification (it will no-op if it isn't visible)
508             mWifiStateTracker.setNotificationVisible(false, 0, false, 0);
509 
510             boolean failedToStopSupplicantOrUnloadDriver = false;
511 
512             if (!mWifiStateTracker.stopSupplicant()) {
513                 Slog.e(TAG, "Failed to stop supplicant daemon.");
514                 setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
515                 failedToStopSupplicantOrUnloadDriver = true;
516             }
517 
518             /**
519              * Reset connections and disable interface
520              * before we unload the driver
521              */
522             mWifiStateTracker.resetConnections(true);
523 
524             if (!mWifiStateTracker.unloadDriver()) {
525                 Slog.e(TAG, "Failed to unload Wi-Fi driver.");
526                 if (!failedToStopSupplicantOrUnloadDriver) {
527                     setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
528                     failedToStopSupplicantOrUnloadDriver = true;
529                 }
530             }
531 
532             if (failedToStopSupplicantOrUnloadDriver) {
533                 return false;
534             }
535         }
536 
537         // Success!
538 
539         if (persist) {
540             persistWifiEnabled(enable);
541         }
542         setWifiEnabledState(eventualWifiState, uid);
543         return true;
544     }
545 
setWifiEnabledState(int wifiState, int uid)546     private void setWifiEnabledState(int wifiState, int uid) {
547         final int previousWifiState = mWifiStateTracker.getWifiState();
548 
549         long ident = Binder.clearCallingIdentity();
550         try {
551             if (wifiState == WIFI_STATE_ENABLED) {
552                 mBatteryStats.noteWifiOn();
553             } else if (wifiState == WIFI_STATE_DISABLED) {
554                 mBatteryStats.noteWifiOff();
555             }
556         } catch (RemoteException e) {
557         } finally {
558             Binder.restoreCallingIdentity(ident);
559         }
560 
561         // Update state
562         mWifiStateTracker.setWifiState(wifiState);
563 
564         // Broadcast
565         final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
566         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
567         intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
568         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
569         mContext.sendStickyBroadcast(intent);
570     }
571 
enforceAccessPermission()572     private void enforceAccessPermission() {
573         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
574                                                 "WifiService");
575     }
576 
enforceChangePermission()577     private void enforceChangePermission() {
578         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
579                                                 "WifiService");
580 
581     }
582 
enforceMulticastChangePermission()583     private void enforceMulticastChangePermission() {
584         mContext.enforceCallingOrSelfPermission(
585                 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
586                 "WifiService");
587     }
588 
589     /**
590      * see {@link WifiManager#getWifiState()}
591      * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
592      *         {@link WifiManager#WIFI_STATE_DISABLING},
593      *         {@link WifiManager#WIFI_STATE_ENABLED},
594      *         {@link WifiManager#WIFI_STATE_ENABLING},
595      *         {@link WifiManager#WIFI_STATE_UNKNOWN}
596      */
getWifiEnabledState()597     public int getWifiEnabledState() {
598         enforceAccessPermission();
599         return mWifiStateTracker.getWifiState();
600     }
601 
602     /**
603      * see {@link android.net.wifi.WifiManager#disconnect()}
604      * @return {@code true} if the operation succeeds
605      */
disconnect()606     public boolean disconnect() {
607         enforceChangePermission();
608 
609         return mWifiStateTracker.disconnect();
610     }
611 
612     /**
613      * see {@link android.net.wifi.WifiManager#reconnect()}
614      * @return {@code true} if the operation succeeds
615      */
reconnect()616     public boolean reconnect() {
617         enforceChangePermission();
618 
619         return mWifiStateTracker.reconnectCommand();
620     }
621 
622     /**
623      * see {@link android.net.wifi.WifiManager#reassociate()}
624      * @return {@code true} if the operation succeeds
625      */
reassociate()626     public boolean reassociate() {
627         enforceChangePermission();
628 
629         return mWifiStateTracker.reassociate();
630     }
631 
632     /**
633      * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
634      * @param wifiConfig SSID, security and channel details as
635      *        part of WifiConfiguration
636      * @param enabled, true to enable and false to disable
637      * @return {@code true} if the start operation was
638      *         started or is already in the queue.
639      */
setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled)640     public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
641         enforceChangePermission();
642         if (mWifiHandler == null) return false;
643 
644         synchronized (mWifiHandler) {
645 
646             long ident = Binder.clearCallingIdentity();
647             sWakeLock.acquire();
648             Binder.restoreCallingIdentity(ident);
649 
650             mLastApEnableUid = Binder.getCallingUid();
651             sendAccessPointMessage(enabled, wifiConfig, Binder.getCallingUid());
652         }
653 
654         return true;
655     }
656 
getWifiApConfiguration()657     public WifiConfiguration getWifiApConfiguration() {
658         enforceAccessPermission();
659         synchronized (mWifiApConfigLock) {
660             WifiConfiguration config = new WifiConfiguration();
661             config.SSID = mWifiApConfig.SSID;
662             if (mWifiApConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
663                 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
664                 config.preSharedKey = mWifiApConfig.preSharedKey;
665             } else {
666                 config.allowedKeyManagement.set(KeyMgmt.NONE);
667             }
668             return config;
669         }
670     }
671 
setWifiApConfiguration(WifiConfiguration wifiConfig)672     public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
673         enforceChangePermission();
674         if (wifiConfig == null)
675             return;
676         Message.obtain(mWifiHandler, MESSAGE_WRITE_WIFI_AP_CONFIG, wifiConfig).sendToTarget();
677     }
678 
679     /* Generate a default WPA2 based configuration with a random password.
680 
681        We are changing the Wifi Ap configuration storage from secure settings to a
682        flat file accessible only by the system. A WPA2 based default configuration
683        will keep the device secure after the update */
setDefaultWifiApConfiguration()684     private void setDefaultWifiApConfiguration() {
685         synchronized (mWifiApConfigLock) {
686             mWifiApConfig.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default);
687             mWifiApConfig.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
688             String randomUUID = UUID.randomUUID().toString();
689             //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
690             mWifiApConfig.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9,13);
691         }
692     }
693 
writeWifiApConfigBlocked(WifiConfiguration wifiConfig)694     private void writeWifiApConfigBlocked(WifiConfiguration wifiConfig) {
695         DataOutputStream out = null;
696         try {
697             out = new DataOutputStream(new BufferedOutputStream(
698                         new FileOutputStream(WIFIAP_CONFIG_FILE)));
699 
700             out.writeInt(WIFIAP_CONFIG_VERSION);
701             out.writeUTF(wifiConfig.SSID);
702             if(wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
703                 out.writeInt(KeyMgmt.WPA_PSK);
704                 out.writeUTF(wifiConfig.preSharedKey);
705             } else {
706                 out.writeInt(KeyMgmt.NONE);
707             }
708             synchronized (mWifiApConfigLock) {
709                 mWifiApConfig = wifiConfig;
710             }
711         } catch (IOException e) {
712             Slog.e(TAG, "Error writing hotspot configuration" + e);
713         } finally {
714             if (out != null) {
715                 try {
716                     out.close();
717                 } catch (IOException e) {}
718             }
719         }
720     }
721 
readWifiApConfigBlocked()722     private void readWifiApConfigBlocked() {
723         DataInputStream in = null;
724         try {
725             WifiConfiguration config = new WifiConfiguration();
726             in = new DataInputStream(new BufferedInputStream(new FileInputStream(
727                             WIFIAP_CONFIG_FILE)));
728 
729             int version = in.readInt();
730             if (version != 1) {
731                 Slog.e(TAG, "Bad version on hotspot configuration file, set defaults");
732                 setDefaultWifiApConfiguration();
733                 return;
734             }
735             config.SSID = in.readUTF();
736             int authType = in.readInt();
737             config.allowedKeyManagement.set(authType);
738             if (authType != KeyMgmt.NONE) {
739                 config.preSharedKey = in.readUTF();
740             }
741             synchronized (mWifiApConfigLock) {
742                 mWifiApConfig = config;
743             }
744         } catch (IOException ignore) {
745             setDefaultWifiApConfiguration();
746         } finally {
747             if (in != null) {
748                 try {
749                     in.close();
750                 } catch (IOException e) {}
751             }
752         }
753     }
754 
755 
756     /**
757      * Enables/disables Wi-Fi AP synchronously. The driver is loaded
758      * and soft access point configured as a single operation.
759      * @param enable {@code true} to turn Wi-Fi on, {@code false} to turn it off.
760      * @param uid The UID of the process making the request.
761      * @param wifiConfig The WifiConfiguration for AP
762      * @return {@code true} if the operation succeeds (or if the existing state
763      *         is the same as the requested state)
764      */
setWifiApEnabledBlocking(boolean enable, int uid, WifiConfiguration wifiConfig)765     private boolean setWifiApEnabledBlocking(boolean enable,
766                                 int uid, WifiConfiguration wifiConfig) {
767         final int eventualWifiApState = enable ? WIFI_AP_STATE_ENABLED : WIFI_AP_STATE_DISABLED;
768 
769         if (mWifiApState == eventualWifiApState) {
770             /* Configuration changed on a running access point */
771             if(enable && (wifiConfig != null)) {
772                 try {
773                     nwService.setAccessPoint(wifiConfig, mWifiStateTracker.getInterfaceName(),
774                                              SOFTAP_IFACE);
775                     setWifiApConfiguration(wifiConfig);
776                     return true;
777                 } catch(Exception e) {
778                     Slog.e(TAG, "Exception in nwService during AP restart");
779                     try {
780                         nwService.stopAccessPoint();
781                     } catch (Exception ee) {
782                         Slog.e(TAG, "Could not stop AP, :" + ee);
783                     }
784                     setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.DRIVER_UNLOAD);
785                     return false;
786                 }
787             } else {
788                 return true;
789             }
790         }
791 
792         /**
793          * Fail AP if Wifi is enabled
794          */
795         if ((mWifiStateTracker.getWifiState() == WIFI_STATE_ENABLED) && enable) {
796             setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.NO_DRIVER_UNLOAD);
797             return false;
798         }
799 
800         setWifiApEnabledState(enable ? WIFI_AP_STATE_ENABLING :
801                                        WIFI_AP_STATE_DISABLING, uid, DriverAction.NO_DRIVER_UNLOAD);
802 
803         if (enable) {
804 
805             /* Use default config if there is no existing config */
806             if (wifiConfig == null) wifiConfig = getWifiApConfiguration();
807 
808             if (!mWifiStateTracker.loadDriver()) {
809                 Slog.e(TAG, "Failed to load Wi-Fi driver for AP mode");
810                 setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.NO_DRIVER_UNLOAD);
811                 return false;
812             }
813 
814             try {
815                 nwService.startAccessPoint(wifiConfig, mWifiStateTracker.getInterfaceName(),
816                                            SOFTAP_IFACE);
817             } catch(Exception e) {
818                 Slog.e(TAG, "Exception in startAccessPoint()");
819                 setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.DRIVER_UNLOAD);
820                 return false;
821             }
822 
823             setWifiApConfiguration(wifiConfig);
824 
825         } else {
826 
827             try {
828                 nwService.stopAccessPoint();
829             } catch(Exception e) {
830                 Slog.e(TAG, "Exception in stopAccessPoint()");
831                 setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.DRIVER_UNLOAD);
832                 return false;
833             }
834 
835             if (!mWifiStateTracker.unloadDriver()) {
836                 Slog.e(TAG, "Failed to unload Wi-Fi driver for AP mode");
837                 setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.NO_DRIVER_UNLOAD);
838                 return false;
839             }
840         }
841 
842         setWifiApEnabledState(eventualWifiApState, uid, DriverAction.NO_DRIVER_UNLOAD);
843         return true;
844     }
845 
846     /**
847      * see {@link WifiManager#getWifiApState()}
848      * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
849      *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
850      *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
851      *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
852      *         {@link WifiManager#WIFI_AP_STATE_FAILED}
853      */
getWifiApEnabledState()854     public int getWifiApEnabledState() {
855         enforceAccessPermission();
856         return mWifiApState;
857     }
858 
setWifiApEnabledState(int wifiAPState, int uid, DriverAction flag)859     private void setWifiApEnabledState(int wifiAPState, int uid, DriverAction flag) {
860         final int previousWifiApState = mWifiApState;
861 
862         /**
863          * Unload the driver if going to a failed state
864          */
865         if ((mWifiApState == WIFI_AP_STATE_FAILED) && (flag == DriverAction.DRIVER_UNLOAD)) {
866             mWifiStateTracker.unloadDriver();
867         }
868 
869         long ident = Binder.clearCallingIdentity();
870         try {
871             if (wifiAPState == WIFI_AP_STATE_ENABLED) {
872                 mBatteryStats.noteWifiOn();
873             } else if (wifiAPState == WIFI_AP_STATE_DISABLED) {
874                 mBatteryStats.noteWifiOff();
875             }
876         } catch (RemoteException e) {
877         } finally {
878             Binder.restoreCallingIdentity(ident);
879         }
880 
881         // Update state
882         mWifiApState = wifiAPState;
883 
884         // Broadcast
885         final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
886         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
887         intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiAPState);
888         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
889         mContext.sendStickyBroadcast(intent);
890     }
891 
892     /**
893      * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
894      * @return the list of configured networks
895      */
getConfiguredNetworks()896     public List<WifiConfiguration> getConfiguredNetworks() {
897         enforceAccessPermission();
898         String listStr;
899 
900         /*
901          * We don't cache the list, because we want to allow
902          * for the possibility that the configuration file
903          * has been modified through some external means,
904          * such as the wpa_cli command line program.
905          */
906         listStr = mWifiStateTracker.listNetworks();
907 
908         List<WifiConfiguration> networks =
909             new ArrayList<WifiConfiguration>();
910         if (listStr == null)
911             return networks;
912 
913         String[] lines = listStr.split("\n");
914         // Skip the first line, which is a header
915        for (int i = 1; i < lines.length; i++) {
916            String[] result = lines[i].split("\t");
917            // network-id | ssid | bssid | flags
918            WifiConfiguration config = new WifiConfiguration();
919            try {
920                config.networkId = Integer.parseInt(result[0]);
921            } catch(NumberFormatException e) {
922                continue;
923            }
924            if (result.length > 3) {
925                if (result[3].indexOf("[CURRENT]") != -1)
926                    config.status = WifiConfiguration.Status.CURRENT;
927                else if (result[3].indexOf("[DISABLED]") != -1)
928                    config.status = WifiConfiguration.Status.DISABLED;
929                else
930                    config.status = WifiConfiguration.Status.ENABLED;
931            } else {
932                config.status = WifiConfiguration.Status.ENABLED;
933            }
934            readNetworkVariables(config);
935            networks.add(config);
936        }
937 
938         return networks;
939     }
940 
941     /**
942      * Read the variables from the supplicant daemon that are needed to
943      * fill in the WifiConfiguration object.
944      * <p/>
945      * The caller must hold the synchronization monitor.
946      * @param config the {@link WifiConfiguration} object to be filled in.
947      */
readNetworkVariables(WifiConfiguration config)948     private void readNetworkVariables(WifiConfiguration config) {
949 
950         int netId = config.networkId;
951         if (netId < 0)
952             return;
953 
954         /*
955          * TODO: maybe should have a native method that takes an array of
956          * variable names and returns an array of values. But we'd still
957          * be doing a round trip to the supplicant daemon for each variable.
958          */
959         String value;
960 
961         value = mWifiStateTracker.getNetworkVariable(netId, WifiConfiguration.ssidVarName);
962         if (!TextUtils.isEmpty(value)) {
963             config.SSID = value;
964         } else {
965             config.SSID = null;
966         }
967 
968         value = mWifiStateTracker.getNetworkVariable(netId, WifiConfiguration.bssidVarName);
969         if (!TextUtils.isEmpty(value)) {
970             config.BSSID = value;
971         } else {
972             config.BSSID = null;
973         }
974 
975         value = mWifiStateTracker.getNetworkVariable(netId, WifiConfiguration.priorityVarName);
976         config.priority = -1;
977         if (!TextUtils.isEmpty(value)) {
978             try {
979                 config.priority = Integer.parseInt(value);
980             } catch (NumberFormatException ignore) {
981             }
982         }
983 
984         value = mWifiStateTracker.getNetworkVariable(netId, WifiConfiguration.hiddenSSIDVarName);
985         config.hiddenSSID = false;
986         if (!TextUtils.isEmpty(value)) {
987             try {
988                 config.hiddenSSID = Integer.parseInt(value) != 0;
989             } catch (NumberFormatException ignore) {
990             }
991         }
992 
993         value = mWifiStateTracker.getNetworkVariable(netId, WifiConfiguration.wepTxKeyIdxVarName);
994         config.wepTxKeyIndex = -1;
995         if (!TextUtils.isEmpty(value)) {
996             try {
997                 config.wepTxKeyIndex = Integer.parseInt(value);
998             } catch (NumberFormatException ignore) {
999             }
1000         }
1001 
1002         /*
1003          * Get up to 4 WEP keys. Note that the actual keys are not passed back,
1004          * just a "*" if the key is set, or the null string otherwise.
1005          */
1006         for (int i = 0; i < 4; i++) {
1007             value = mWifiStateTracker.getNetworkVariable(netId, WifiConfiguration.wepKeyVarNames[i]);
1008             if (!TextUtils.isEmpty(value)) {
1009                 config.wepKeys[i] = value;
1010             } else {
1011                 config.wepKeys[i] = null;
1012             }
1013         }
1014 
1015         /*
1016          * Get the private shared key. Note that the actual keys are not passed back,
1017          * just a "*" if the key is set, or the null string otherwise.
1018          */
1019         value = mWifiStateTracker.getNetworkVariable(netId, WifiConfiguration.pskVarName);
1020         if (!TextUtils.isEmpty(value)) {
1021             config.preSharedKey = value;
1022         } else {
1023             config.preSharedKey = null;
1024         }
1025 
1026         value = mWifiStateTracker.getNetworkVariable(config.networkId,
1027                 WifiConfiguration.Protocol.varName);
1028         if (!TextUtils.isEmpty(value)) {
1029             String vals[] = value.split(" ");
1030             for (String val : vals) {
1031                 int index =
1032                     lookupString(val, WifiConfiguration.Protocol.strings);
1033                 if (0 <= index) {
1034                     config.allowedProtocols.set(index);
1035                 }
1036             }
1037         }
1038 
1039         value = mWifiStateTracker.getNetworkVariable(config.networkId,
1040                 WifiConfiguration.KeyMgmt.varName);
1041         if (!TextUtils.isEmpty(value)) {
1042             String vals[] = value.split(" ");
1043             for (String val : vals) {
1044                 int index =
1045                     lookupString(val, WifiConfiguration.KeyMgmt.strings);
1046                 if (0 <= index) {
1047                     config.allowedKeyManagement.set(index);
1048                 }
1049             }
1050         }
1051 
1052         value = mWifiStateTracker.getNetworkVariable(config.networkId,
1053                 WifiConfiguration.AuthAlgorithm.varName);
1054         if (!TextUtils.isEmpty(value)) {
1055             String vals[] = value.split(" ");
1056             for (String val : vals) {
1057                 int index =
1058                     lookupString(val, WifiConfiguration.AuthAlgorithm.strings);
1059                 if (0 <= index) {
1060                     config.allowedAuthAlgorithms.set(index);
1061                 }
1062             }
1063         }
1064 
1065         value = mWifiStateTracker.getNetworkVariable(config.networkId,
1066                 WifiConfiguration.PairwiseCipher.varName);
1067         if (!TextUtils.isEmpty(value)) {
1068             String vals[] = value.split(" ");
1069             for (String val : vals) {
1070                 int index =
1071                     lookupString(val, WifiConfiguration.PairwiseCipher.strings);
1072                 if (0 <= index) {
1073                     config.allowedPairwiseCiphers.set(index);
1074                 }
1075             }
1076         }
1077 
1078         value = mWifiStateTracker.getNetworkVariable(config.networkId,
1079                 WifiConfiguration.GroupCipher.varName);
1080         if (!TextUtils.isEmpty(value)) {
1081             String vals[] = value.split(" ");
1082             for (String val : vals) {
1083                 int index =
1084                     lookupString(val, WifiConfiguration.GroupCipher.strings);
1085                 if (0 <= index) {
1086                     config.allowedGroupCiphers.set(index);
1087                 }
1088             }
1089         }
1090 
1091         for (WifiConfiguration.EnterpriseField field :
1092                 config.enterpriseFields) {
1093             value = mWifiStateTracker.getNetworkVariable(netId,
1094                     field.varName());
1095             if (!TextUtils.isEmpty(value)) {
1096                 if (field != config.eap) value = removeDoubleQuotes(value);
1097                 field.setValue(value);
1098             }
1099         }
1100     }
1101 
removeDoubleQuotes(String string)1102     private static String removeDoubleQuotes(String string) {
1103         if (string.length() <= 2) return "";
1104         return string.substring(1, string.length() - 1);
1105     }
1106 
convertToQuotedString(String string)1107     private static String convertToQuotedString(String string) {
1108         return "\"" + string + "\"";
1109     }
1110 
1111     /**
1112      * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
1113      * @return the supplicant-assigned identifier for the new or updated
1114      * network if the operation succeeds, or {@code -1} if it fails
1115      */
addOrUpdateNetwork(WifiConfiguration config)1116     public int addOrUpdateNetwork(WifiConfiguration config) {
1117         enforceChangePermission();
1118 
1119         /*
1120          * If the supplied networkId is -1, we create a new empty
1121          * network configuration. Otherwise, the networkId should
1122          * refer to an existing configuration.
1123          */
1124         int netId = config.networkId;
1125         boolean newNetwork = netId == -1;
1126         boolean doReconfig = false;
1127         // networkId of -1 means we want to create a new network
1128         synchronized (mWifiStateTracker) {
1129             if (newNetwork) {
1130                 netId = mWifiStateTracker.addNetwork();
1131                 if (netId < 0) {
1132                     if (DBG) {
1133                         Slog.d(TAG, "Failed to add a network!");
1134                     }
1135                     return -1;
1136                 }
1137                 doReconfig = true;
1138             }
1139             mNeedReconfig = mNeedReconfig || doReconfig;
1140         }
1141 
1142         setVariables: {
1143             /*
1144              * Note that if a networkId for a non-existent network
1145              * was supplied, then the first setNetworkVariable()
1146              * will fail, so we don't bother to make a separate check
1147              * for the validity of the ID up front.
1148              */
1149             if (config.SSID != null &&
1150                     !mWifiStateTracker.setNetworkVariable(
1151                         netId,
1152                         WifiConfiguration.ssidVarName,
1153                         config.SSID)) {
1154                 if (DBG) {
1155                     Slog.d(TAG, "failed to set SSID: "+config.SSID);
1156                 }
1157                 break setVariables;
1158             }
1159 
1160             if (config.BSSID != null &&
1161                     !mWifiStateTracker.setNetworkVariable(
1162                         netId,
1163                         WifiConfiguration.bssidVarName,
1164                         config.BSSID)) {
1165                 if (DBG) {
1166                     Slog.d(TAG, "failed to set BSSID: "+config.BSSID);
1167                 }
1168                 break setVariables;
1169             }
1170 
1171             String allowedKeyManagementString =
1172                 makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings);
1173             if (config.allowedKeyManagement.cardinality() != 0 &&
1174                     !mWifiStateTracker.setNetworkVariable(
1175                         netId,
1176                         WifiConfiguration.KeyMgmt.varName,
1177                         allowedKeyManagementString)) {
1178                 if (DBG) {
1179                     Slog.d(TAG, "failed to set key_mgmt: "+
1180                             allowedKeyManagementString);
1181                 }
1182                 break setVariables;
1183             }
1184 
1185             String allowedProtocolsString =
1186                 makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings);
1187             if (config.allowedProtocols.cardinality() != 0 &&
1188                     !mWifiStateTracker.setNetworkVariable(
1189                         netId,
1190                         WifiConfiguration.Protocol.varName,
1191                         allowedProtocolsString)) {
1192                 if (DBG) {
1193                     Slog.d(TAG, "failed to set proto: "+
1194                             allowedProtocolsString);
1195                 }
1196                 break setVariables;
1197             }
1198 
1199             String allowedAuthAlgorithmsString =
1200                 makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings);
1201             if (config.allowedAuthAlgorithms.cardinality() != 0 &&
1202                     !mWifiStateTracker.setNetworkVariable(
1203                         netId,
1204                         WifiConfiguration.AuthAlgorithm.varName,
1205                         allowedAuthAlgorithmsString)) {
1206                 if (DBG) {
1207                     Slog.d(TAG, "failed to set auth_alg: "+
1208                             allowedAuthAlgorithmsString);
1209                 }
1210                 break setVariables;
1211             }
1212 
1213             String allowedPairwiseCiphersString =
1214                 makeString(config.allowedPairwiseCiphers, WifiConfiguration.PairwiseCipher.strings);
1215             if (config.allowedPairwiseCiphers.cardinality() != 0 &&
1216                     !mWifiStateTracker.setNetworkVariable(
1217                         netId,
1218                         WifiConfiguration.PairwiseCipher.varName,
1219                         allowedPairwiseCiphersString)) {
1220                 if (DBG) {
1221                     Slog.d(TAG, "failed to set pairwise: "+
1222                             allowedPairwiseCiphersString);
1223                 }
1224                 break setVariables;
1225             }
1226 
1227             String allowedGroupCiphersString =
1228                 makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings);
1229             if (config.allowedGroupCiphers.cardinality() != 0 &&
1230                     !mWifiStateTracker.setNetworkVariable(
1231                         netId,
1232                         WifiConfiguration.GroupCipher.varName,
1233                         allowedGroupCiphersString)) {
1234                 if (DBG) {
1235                     Slog.d(TAG, "failed to set group: "+
1236                             allowedGroupCiphersString);
1237                 }
1238                 break setVariables;
1239             }
1240 
1241             // Prevent client screw-up by passing in a WifiConfiguration we gave it
1242             // by preventing "*" as a key.
1243             if (config.preSharedKey != null && !config.preSharedKey.equals("*") &&
1244                     !mWifiStateTracker.setNetworkVariable(
1245                         netId,
1246                         WifiConfiguration.pskVarName,
1247                         config.preSharedKey)) {
1248                 if (DBG) {
1249                     Slog.d(TAG, "failed to set psk: "+config.preSharedKey);
1250                 }
1251                 break setVariables;
1252             }
1253 
1254             boolean hasSetKey = false;
1255             if (config.wepKeys != null) {
1256                 for (int i = 0; i < config.wepKeys.length; i++) {
1257                     // Prevent client screw-up by passing in a WifiConfiguration we gave it
1258                     // by preventing "*" as a key.
1259                     if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) {
1260                         if (!mWifiStateTracker.setNetworkVariable(
1261                                     netId,
1262                                     WifiConfiguration.wepKeyVarNames[i],
1263                                     config.wepKeys[i])) {
1264                             if (DBG) {
1265                                 Slog.d(TAG,
1266                                         "failed to set wep_key"+i+": " +
1267                                         config.wepKeys[i]);
1268                             }
1269                             break setVariables;
1270                         }
1271                         hasSetKey = true;
1272                     }
1273                 }
1274             }
1275 
1276             if (hasSetKey) {
1277                 if (!mWifiStateTracker.setNetworkVariable(
1278                             netId,
1279                             WifiConfiguration.wepTxKeyIdxVarName,
1280                             Integer.toString(config.wepTxKeyIndex))) {
1281                     if (DBG) {
1282                         Slog.d(TAG,
1283                                 "failed to set wep_tx_keyidx: "+
1284                                 config.wepTxKeyIndex);
1285                     }
1286                     break setVariables;
1287                 }
1288             }
1289 
1290             if (!mWifiStateTracker.setNetworkVariable(
1291                         netId,
1292                         WifiConfiguration.priorityVarName,
1293                         Integer.toString(config.priority))) {
1294                 if (DBG) {
1295                     Slog.d(TAG, config.SSID + ": failed to set priority: "
1296                             +config.priority);
1297                 }
1298                 break setVariables;
1299             }
1300 
1301             if (config.hiddenSSID && !mWifiStateTracker.setNetworkVariable(
1302                         netId,
1303                         WifiConfiguration.hiddenSSIDVarName,
1304                         Integer.toString(config.hiddenSSID ? 1 : 0))) {
1305                 if (DBG) {
1306                     Slog.d(TAG, config.SSID + ": failed to set hiddenSSID: "+
1307                             config.hiddenSSID);
1308                 }
1309                 break setVariables;
1310             }
1311 
1312             for (WifiConfiguration.EnterpriseField field
1313                     : config.enterpriseFields) {
1314                 String varName = field.varName();
1315                 String value = field.value();
1316                 if (value != null) {
1317                     if (field != config.eap) {
1318                         value = (value.length() == 0) ? "NULL" : convertToQuotedString(value);
1319                     }
1320                     if (!mWifiStateTracker.setNetworkVariable(
1321                                 netId,
1322                                 varName,
1323                                 value)) {
1324                         if (DBG) {
1325                             Slog.d(TAG, config.SSID + ": failed to set " + varName +
1326                                     ": " + value);
1327                         }
1328                         break setVariables;
1329                     }
1330                 }
1331             }
1332             return netId;
1333         }
1334 
1335         /*
1336          * For an update, if one of the setNetworkVariable operations fails,
1337          * we might want to roll back all the changes already made. But the
1338          * chances are that if anything is going to go wrong, it'll happen
1339          * the first time we try to set one of the variables.
1340          */
1341         if (newNetwork) {
1342             removeNetwork(netId);
1343             if (DBG) {
1344                 Slog.d(TAG,
1345                         "Failed to set a network variable, removed network: "
1346                         + netId);
1347             }
1348         }
1349         return -1;
1350     }
1351 
makeString(BitSet set, String[] strings)1352     private static String makeString(BitSet set, String[] strings) {
1353         StringBuffer buf = new StringBuffer();
1354         int nextSetBit = -1;
1355 
1356         /* Make sure all set bits are in [0, strings.length) to avoid
1357          * going out of bounds on strings.  (Shouldn't happen, but...) */
1358         set = set.get(0, strings.length);
1359 
1360         while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
1361             buf.append(strings[nextSetBit].replace('_', '-')).append(' ');
1362         }
1363 
1364         // remove trailing space
1365         if (set.cardinality() > 0) {
1366             buf.setLength(buf.length() - 1);
1367         }
1368 
1369         return buf.toString();
1370     }
1371 
lookupString(String string, String[] strings)1372     private static int lookupString(String string, String[] strings) {
1373         int size = strings.length;
1374 
1375         string = string.replace('-', '_');
1376 
1377         for (int i = 0; i < size; i++)
1378             if (string.equals(strings[i]))
1379                 return i;
1380 
1381         if (DBG) {
1382             // if we ever get here, we should probably add the
1383             // value to WifiConfiguration to reflect that it's
1384             // supported by the WPA supplicant
1385             Slog.w(TAG, "Failed to look-up a string: " + string);
1386         }
1387 
1388         return -1;
1389     }
1390 
1391     /**
1392      * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
1393      * @param netId the integer that identifies the network configuration
1394      * to the supplicant
1395      * @return {@code true} if the operation succeeded
1396      */
removeNetwork(int netId)1397     public boolean removeNetwork(int netId) {
1398         enforceChangePermission();
1399 
1400         return mWifiStateTracker.removeNetwork(netId);
1401     }
1402 
1403     /**
1404      * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
1405      * @param netId the integer that identifies the network configuration
1406      * to the supplicant
1407      * @param disableOthers if true, disable all other networks.
1408      * @return {@code true} if the operation succeeded
1409      */
enableNetwork(int netId, boolean disableOthers)1410     public boolean enableNetwork(int netId, boolean disableOthers) {
1411         enforceChangePermission();
1412 
1413         String ifname = mWifiStateTracker.getInterfaceName();
1414         NetworkUtils.enableInterface(ifname);
1415         boolean result = mWifiStateTracker.enableNetwork(netId, disableOthers);
1416         if (!result) {
1417             NetworkUtils.disableInterface(ifname);
1418         }
1419         return result;
1420     }
1421 
1422     /**
1423      * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
1424      * @param netId the integer that identifies the network configuration
1425      * to the supplicant
1426      * @return {@code true} if the operation succeeded
1427      */
disableNetwork(int netId)1428     public boolean disableNetwork(int netId) {
1429         enforceChangePermission();
1430 
1431         return mWifiStateTracker.disableNetwork(netId);
1432     }
1433 
1434     /**
1435      * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
1436      * @return the Wi-Fi information, contained in {@link WifiInfo}.
1437      */
getConnectionInfo()1438     public WifiInfo getConnectionInfo() {
1439         enforceAccessPermission();
1440         /*
1441          * Make sure we have the latest information, by sending
1442          * a status request to the supplicant.
1443          */
1444         return mWifiStateTracker.requestConnectionInfo();
1445     }
1446 
1447     /**
1448      * Return the results of the most recent access point scan, in the form of
1449      * a list of {@link ScanResult} objects.
1450      * @return the list of results
1451      */
getScanResults()1452     public List<ScanResult> getScanResults() {
1453         enforceAccessPermission();
1454         String reply;
1455 
1456         reply = mWifiStateTracker.scanResults();
1457         if (reply == null) {
1458             return null;
1459         }
1460 
1461         List<ScanResult> scanList = new ArrayList<ScanResult>();
1462 
1463         int lineCount = 0;
1464 
1465         int replyLen = reply.length();
1466         // Parse the result string, keeping in mind that the last line does
1467         // not end with a newline.
1468         for (int lineBeg = 0, lineEnd = 0; lineEnd <= replyLen; ++lineEnd) {
1469             if (lineEnd == replyLen || reply.charAt(lineEnd) == '\n') {
1470                 ++lineCount;
1471                 /*
1472                  * Skip the first line, which is a header
1473                  */
1474                 if (lineCount == 1) {
1475                     lineBeg = lineEnd + 1;
1476                     continue;
1477                 }
1478                 if (lineEnd > lineBeg) {
1479                     String line = reply.substring(lineBeg, lineEnd);
1480                     ScanResult scanResult = parseScanResult(line);
1481                     if (scanResult != null) {
1482                         scanList.add(scanResult);
1483                     } else if (DBG) {
1484                         Slog.w(TAG, "misformatted scan result for: " + line);
1485                     }
1486                 }
1487                 lineBeg = lineEnd + 1;
1488             }
1489         }
1490         mWifiStateTracker.setScanResultsList(scanList);
1491         return scanList;
1492     }
1493 
1494     /**
1495      * Parse the scan result line passed to us by wpa_supplicant (helper).
1496      * @param line the line to parse
1497      * @return the {@link ScanResult} object
1498      */
parseScanResult(String line)1499     private ScanResult parseScanResult(String line) {
1500         ScanResult scanResult = null;
1501         if (line != null) {
1502             /*
1503              * Cache implementation (LinkedHashMap) is not synchronized, thus,
1504              * must synchronized here!
1505              */
1506             synchronized (mScanResultCache) {
1507                 String[] result = scanResultPattern.split(line);
1508                 if (3 <= result.length && result.length <= 5) {
1509                     String bssid = result[0];
1510                     // bssid | frequency | level | flags | ssid
1511                     int frequency;
1512                     int level;
1513                     try {
1514                         frequency = Integer.parseInt(result[1]);
1515                         level = Integer.parseInt(result[2]);
1516                         /* some implementations avoid negative values by adding 256
1517                          * so we need to adjust for that here.
1518                          */
1519                         if (level > 0) level -= 256;
1520                     } catch (NumberFormatException e) {
1521                         frequency = 0;
1522                         level = 0;
1523                     }
1524 
1525                     /*
1526                      * The formatting of the results returned by
1527                      * wpa_supplicant is intended to make the fields
1528                      * line up nicely when printed,
1529                      * not to make them easy to parse. So we have to
1530                      * apply some heuristics to figure out which field
1531                      * is the SSID and which field is the flags.
1532                      */
1533                     String ssid;
1534                     String flags;
1535                     if (result.length == 4) {
1536                         if (result[3].charAt(0) == '[') {
1537                             flags = result[3];
1538                             ssid = "";
1539                         } else {
1540                             flags = "";
1541                             ssid = result[3];
1542                         }
1543                     } else if (result.length == 5) {
1544                         flags = result[3];
1545                         ssid = result[4];
1546                     } else {
1547                         // Here, we must have 3 fields: no flags and ssid
1548                         // set
1549                         flags = "";
1550                         ssid = "";
1551                     }
1552 
1553                     // bssid + ssid is the hash key
1554                     String key = bssid + ssid;
1555                     scanResult = mScanResultCache.get(key);
1556                     if (scanResult != null) {
1557                         scanResult.level = level;
1558                         scanResult.SSID = ssid;
1559                         scanResult.capabilities = flags;
1560                         scanResult.frequency = frequency;
1561                     } else {
1562                         // Do not add scan results that have no SSID set
1563                         if (0 < ssid.trim().length()) {
1564                             scanResult =
1565                                 new ScanResult(
1566                                     ssid, bssid, flags, level, frequency);
1567                             mScanResultCache.put(key, scanResult);
1568                         }
1569                     }
1570                 } else {
1571                     Slog.w(TAG, "Misformatted scan result text with " +
1572                           result.length + " fields: " + line);
1573                 }
1574             }
1575         }
1576 
1577         return scanResult;
1578     }
1579 
1580     /**
1581      * Parse the "flags" field passed back in a scan result by wpa_supplicant,
1582      * and construct a {@code WifiConfiguration} that describes the encryption,
1583      * key management, and authenticaion capabilities of the access point.
1584      * @param flags the string returned by wpa_supplicant
1585      * @return the {@link WifiConfiguration} object, filled in
1586      */
parseScanFlags(String flags)1587     WifiConfiguration parseScanFlags(String flags) {
1588         WifiConfiguration config = new WifiConfiguration();
1589 
1590         if (flags.length() == 0) {
1591             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
1592         }
1593         // ... to be implemented
1594         return config;
1595     }
1596 
1597     /**
1598      * Tell the supplicant to persist the current list of configured networks.
1599      * @return {@code true} if the operation succeeded
1600      */
saveConfiguration()1601     public boolean saveConfiguration() {
1602         boolean result;
1603         enforceChangePermission();
1604 
1605         synchronized (mWifiStateTracker) {
1606             result = mWifiStateTracker.saveConfig();
1607             if (result && mNeedReconfig) {
1608                 mNeedReconfig = false;
1609                 result = mWifiStateTracker.reloadConfig();
1610 
1611                 if (result) {
1612                     Intent intent = new Intent(WifiManager.NETWORK_IDS_CHANGED_ACTION);
1613                     mContext.sendBroadcast(intent);
1614                 }
1615             }
1616         }
1617         // Inform the backup manager about a data change
1618         IBackupManager ibm = IBackupManager.Stub.asInterface(
1619                 ServiceManager.getService(Context.BACKUP_SERVICE));
1620         if (ibm != null) {
1621             try {
1622                 ibm.dataChanged("com.android.providers.settings");
1623             } catch (Exception e) {
1624                 // Try again later
1625             }
1626         }
1627         return result;
1628     }
1629 
1630     /**
1631      * Set the number of radio frequency channels that are allowed to be used
1632      * in the current regulatory domain. This method should be used only
1633      * if the correct number of channels cannot be determined automatically
1634      * for some reason. If the operation is successful, the new value may be
1635      * persisted as a Secure setting.
1636      * @param numChannels the number of allowed channels. Must be greater than 0
1637      * and less than or equal to 16.
1638      * @param persist {@code true} if the setting should be remembered.
1639      * @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
1640      * {@code numChannels} is outside the valid range.
1641      */
setNumAllowedChannels(int numChannels, boolean persist)1642     public boolean setNumAllowedChannels(int numChannels, boolean persist) {
1643         Slog.i(TAG, "WifiService trying to setNumAllowed to "+numChannels+
1644                 " with persist set to "+persist);
1645         enforceChangePermission();
1646 
1647         /*
1648          * Validate the argument. We'd like to let the Wi-Fi driver do this,
1649          * but if Wi-Fi isn't currently enabled, that's not possible, and
1650          * we want to persist the setting anyway,so that it will take
1651          * effect when Wi-Fi does become enabled.
1652          */
1653         boolean found = false;
1654         for (int validChan : sValidRegulatoryChannelCounts) {
1655             if (validChan == numChannels) {
1656                 found = true;
1657                 break;
1658             }
1659         }
1660         if (!found) {
1661             return false;
1662         }
1663 
1664         if (mWifiHandler == null) return false;
1665 
1666         Message.obtain(mWifiHandler,
1667                 MESSAGE_SET_CHANNELS, numChannels, (persist ? 1 : 0)).sendToTarget();
1668 
1669         return true;
1670     }
1671 
1672     /**
1673      * sets the number of allowed radio frequency channels synchronously
1674      * @param numChannels the number of allowed channels. Must be greater than 0
1675      * and less than or equal to 16.
1676      * @param persist {@code true} if the setting should be remembered.
1677      * @return {@code true} if the operation succeeds, {@code false} otherwise
1678      */
setNumAllowedChannelsBlocking(int numChannels, boolean persist)1679     private boolean setNumAllowedChannelsBlocking(int numChannels, boolean persist) {
1680         if (persist) {
1681             Settings.Secure.putInt(mContext.getContentResolver(),
1682                     Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
1683                     numChannels);
1684         }
1685         return mWifiStateTracker.setNumAllowedChannels(numChannels);
1686     }
1687 
1688     /**
1689      * Return the number of frequency channels that are allowed
1690      * to be used in the current regulatory domain.
1691      * @return the number of allowed channels, or {@code -1} if an error occurs
1692      */
getNumAllowedChannels()1693     public int getNumAllowedChannels() {
1694         int numChannels;
1695 
1696         enforceAccessPermission();
1697 
1698         /*
1699          * If we can't get the value from the driver (e.g., because
1700          * Wi-Fi is not currently enabled), get the value from
1701          * Settings.
1702          */
1703         numChannels = mWifiStateTracker.getNumAllowedChannels();
1704         if (numChannels < 0) {
1705             numChannels = Settings.Secure.getInt(mContext.getContentResolver(),
1706                     Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
1707                     -1);
1708         }
1709         return numChannels;
1710     }
1711 
1712     /**
1713      * Return the list of valid values for the number of allowed radio channels
1714      * for various regulatory domains.
1715      * @return the list of channel counts
1716      */
getValidChannelCounts()1717     public int[] getValidChannelCounts() {
1718         enforceAccessPermission();
1719         return sValidRegulatoryChannelCounts;
1720     }
1721 
1722     /**
1723      * Return the DHCP-assigned addresses from the last successful DHCP request,
1724      * if any.
1725      * @return the DHCP information
1726      */
getDhcpInfo()1727     public DhcpInfo getDhcpInfo() {
1728         enforceAccessPermission();
1729         return mWifiStateTracker.getDhcpInfo();
1730     }
1731 
1732     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1733         @Override
1734         public void onReceive(Context context, Intent intent) {
1735             String action = intent.getAction();
1736 
1737             long idleMillis =
1738                 Settings.Secure.getLong(mContext.getContentResolver(),
1739                                         Settings.Secure.WIFI_IDLE_MS, DEFAULT_IDLE_MILLIS);
1740             int stayAwakeConditions =
1741                 Settings.System.getInt(mContext.getContentResolver(),
1742                                        Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
1743             if (action.equals(Intent.ACTION_SCREEN_ON)) {
1744                 if (DBG) {
1745                     Slog.d(TAG, "ACTION_SCREEN_ON");
1746                 }
1747                 mAlarmManager.cancel(mIdleIntent);
1748                 mDeviceIdle = false;
1749                 mScreenOff = false;
1750                 // Once the screen is on, we are not keeping WIFI running
1751                 // because of any locks so clear that tracking immediately.
1752                 sendReportWorkSourceMessage();
1753                 sendEnableRssiPollingMessage(true);
1754                 /* DHCP or other temporary failures in the past can prevent
1755                  * a disabled network from being connected to, enable on screen on
1756                  */
1757                 if (mWifiStateTracker.isAnyNetworkDisabled()) {
1758                     sendEnableNetworksMessage();
1759                 }
1760             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1761                 if (DBG) {
1762                     Slog.d(TAG, "ACTION_SCREEN_OFF");
1763                 }
1764                 mScreenOff = true;
1765                 sendEnableRssiPollingMessage(false);
1766                 /*
1767                  * Set a timer to put Wi-Fi to sleep, but only if the screen is off
1768                  * AND the "stay on while plugged in" setting doesn't match the
1769                  * current power conditions (i.e, not plugged in, plugged in to USB,
1770                  * or plugged in to AC).
1771                  */
1772                 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
1773                     WifiInfo info = mWifiStateTracker.requestConnectionInfo();
1774                     if (info.getSupplicantState() != SupplicantState.COMPLETED) {
1775                         // we used to go to sleep immediately, but this caused some race conditions
1776                         // we don't have time to track down for this release.  Delay instead, but not
1777                         // as long as we would if connected (below)
1778                         // TODO - fix the race conditions and switch back to the immediate turn-off
1779                         long triggerTime = System.currentTimeMillis() + (2*60*1000); // 2 min
1780                         if (DBG) {
1781                             Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for 120,000 ms");
1782                         }
1783                         mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
1784                         //  // do not keep Wifi awake when screen is off if Wifi is not associated
1785                         //  mDeviceIdle = true;
1786                         //  updateWifiState();
1787                     } else {
1788                         long triggerTime = System.currentTimeMillis() + idleMillis;
1789                         if (DBG) {
1790                             Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis
1791                                     + "ms");
1792                         }
1793                         mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
1794                     }
1795                 }
1796                 /* we can return now -- there's nothing to do until we get the idle intent back */
1797                 return;
1798             } else if (action.equals(ACTION_DEVICE_IDLE)) {
1799                 if (DBG) {
1800                     Slog.d(TAG, "got ACTION_DEVICE_IDLE");
1801                 }
1802                 mDeviceIdle = true;
1803                 sendReportWorkSourceMessage();
1804             } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
1805                 /*
1806                  * Set a timer to put Wi-Fi to sleep, but only if the screen is off
1807                  * AND we are transitioning from a state in which the device was supposed
1808                  * to stay awake to a state in which it is not supposed to stay awake.
1809                  * If "stay awake" state is not changing, we do nothing, to avoid resetting
1810                  * the already-set timer.
1811                  */
1812                 int pluggedType = intent.getIntExtra("plugged", 0);
1813                 if (DBG) {
1814                     Slog.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType);
1815                 }
1816                 if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) &&
1817                         !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) {
1818                     long triggerTime = System.currentTimeMillis() + idleMillis;
1819                     if (DBG) {
1820                         Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
1821                     }
1822                     mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
1823                     mPluggedType = pluggedType;
1824                     return;
1825                 }
1826                 mPluggedType = pluggedType;
1827             } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
1828                 BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
1829                 Set<BluetoothDevice> sinks = a2dp.getConnectedSinks();
1830                 boolean isBluetoothPlaying = false;
1831                 for (BluetoothDevice sink : sinks) {
1832                     if (a2dp.getSinkState(sink) == BluetoothA2dp.STATE_PLAYING) {
1833                         isBluetoothPlaying = true;
1834                     }
1835                 }
1836                 mWifiStateTracker.setBluetoothScanMode(isBluetoothPlaying);
1837 
1838             } else {
1839                 return;
1840             }
1841 
1842             updateWifiState();
1843         }
1844 
1845         /**
1846          * Determines whether the Wi-Fi chipset should stay awake or be put to
1847          * sleep. Looks at the setting for the sleep policy and the current
1848          * conditions.
1849          *
1850          * @see #shouldDeviceStayAwake(int, int)
1851          */
1852         private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) {
1853             int wifiSleepPolicy = Settings.System.getInt(mContext.getContentResolver(),
1854                     Settings.System.WIFI_SLEEP_POLICY, Settings.System.WIFI_SLEEP_POLICY_DEFAULT);
1855 
1856             if (wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER) {
1857                 // Never sleep
1858                 return true;
1859             } else if ((wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) &&
1860                     (pluggedType != 0)) {
1861                 // Never sleep while plugged, and we're plugged
1862                 return true;
1863             } else {
1864                 // Default
1865                 return shouldDeviceStayAwake(stayAwakeConditions, pluggedType);
1866             }
1867         }
1868 
1869         /**
1870          * Determine whether the bit value corresponding to {@code pluggedType} is set in
1871          * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value
1872          * of {@code 0} isn't really a plugged type, but rather an indication that the
1873          * device isn't plugged in at all, there is no bit value corresponding to a
1874          * {@code pluggedType} value of {@code 0}. That is why we shift by
1875          * {@code pluggedType&nbsp;&#8212;&nbsp;1} instead of by {@code pluggedType}.
1876          * @param stayAwakeConditions a bit string specifying which "plugged types" should
1877          * keep the device (and hence Wi-Fi) awake.
1878          * @param pluggedType the type of plug (USB, AC, or none) for which the check is
1879          * being made
1880          * @return {@code true} if {@code pluggedType} indicates that the device is
1881          * supposed to stay awake, {@code false} otherwise.
1882          */
1883         private boolean shouldDeviceStayAwake(int stayAwakeConditions, int pluggedType) {
1884             return (stayAwakeConditions & pluggedType) != 0;
1885         }
1886     };
1887 
sendEnableMessage(boolean enable, boolean persist, int uid)1888     private void sendEnableMessage(boolean enable, boolean persist, int uid) {
1889         Message msg = Message.obtain(mWifiHandler,
1890                                      (enable ? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI),
1891                                      (persist ? 1 : 0), uid);
1892         msg.sendToTarget();
1893     }
1894 
sendStartMessage(int lockMode)1895     private void sendStartMessage(int lockMode) {
1896         Message.obtain(mWifiHandler, MESSAGE_START_WIFI, lockMode, 0).sendToTarget();
1897     }
1898 
sendAccessPointMessage(boolean enable, WifiConfiguration wifiConfig, int uid)1899     private void sendAccessPointMessage(boolean enable, WifiConfiguration wifiConfig, int uid) {
1900         Message.obtain(mWifiHandler,
1901                 (enable ? MESSAGE_START_ACCESS_POINT : MESSAGE_STOP_ACCESS_POINT),
1902                 uid, 0, wifiConfig).sendToTarget();
1903     }
1904 
sendEnableNetworksMessage()1905     private void sendEnableNetworksMessage() {
1906         Message.obtain(mWifiHandler, MESSAGE_ENABLE_NETWORKS).sendToTarget();
1907     }
1908 
sendReportWorkSourceMessage()1909     private void sendReportWorkSourceMessage() {
1910         Message.obtain(mWifiHandler, MESSAGE_REPORT_WORKSOURCE).sendToTarget();
1911     }
1912 
sendEnableRssiPollingMessage(boolean enable)1913     private void sendEnableRssiPollingMessage(boolean enable) {
1914         Message.obtain(mWifiHandler, MESSAGE_ENABLE_RSSI_POLLING, enable ? 1 : 0, 0).sendToTarget();
1915     }
1916 
1917 
reportStartWorkSource()1918     private void reportStartWorkSource() {
1919         synchronized (mWifiStateTracker) {
1920             mTmpWorkSource.clear();
1921             if (mDeviceIdle) {
1922                 for (int i=0; i<mLocks.mList.size(); i++) {
1923                     mTmpWorkSource.add(mLocks.mList.get(i).mWorkSource);
1924                 }
1925             }
1926             mWifiStateTracker.updateBatteryWorkSourceLocked(mTmpWorkSource);
1927             sWakeLock.setWorkSource(mTmpWorkSource);
1928         }
1929     }
1930 
updateWifiState()1931     private void updateWifiState() {
1932         // send a message so it's all serialized
1933         Message.obtain(mWifiHandler, MESSAGE_UPDATE_STATE, 0, 0).sendToTarget();
1934     }
1935 
doUpdateWifiState()1936     private void doUpdateWifiState() {
1937         boolean wifiEnabled = getPersistedWifiEnabled();
1938         boolean airplaneMode = isAirplaneModeOn() && !mAirplaneModeOverwridden;
1939 
1940         boolean lockHeld;
1941         synchronized (mLocks) {
1942             lockHeld = mLocks.hasLocks();
1943         }
1944 
1945         int strongestLockMode = WifiManager.WIFI_MODE_FULL;
1946         boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;
1947         boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
1948 
1949         if (lockHeld) {
1950             strongestLockMode = mLocks.getStrongestLockMode();
1951         }
1952         /* If device is not idle, lockmode cannot be scan only */
1953         if (!mDeviceIdle && strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY) {
1954             strongestLockMode = WifiManager.WIFI_MODE_FULL;
1955         }
1956 
1957         synchronized (mWifiHandler) {
1958             if ((mWifiStateTracker.getWifiState() == WIFI_STATE_ENABLING) && !airplaneMode) {
1959                 return;
1960             }
1961 
1962             /* Disable tethering when airplane mode is enabled */
1963             if (airplaneMode &&
1964                 (mWifiApState == WIFI_AP_STATE_ENABLING || mWifiApState == WIFI_AP_STATE_ENABLED)) {
1965                 sWakeLock.acquire();
1966                 sendAccessPointMessage(false, null, mLastApEnableUid);
1967             }
1968 
1969             if (wifiShouldBeEnabled) {
1970                 if (wifiShouldBeStarted) {
1971                     sWakeLock.acquire();
1972                     sendEnableMessage(true, false, mLastEnableUid);
1973                     sWakeLock.acquire();
1974                     sendStartMessage(strongestLockMode);
1975                 } else if (!mWifiStateTracker.isDriverStopped()) {
1976                     int wakeLockTimeout =
1977                             Settings.Secure.getInt(
1978                                     mContext.getContentResolver(),
1979                                     Settings.Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
1980                                     DEFAULT_WAKELOCK_TIMEOUT);
1981                     /*
1982                      * We are assuming that ConnectivityService can make
1983                      * a transition to cellular data within wakeLockTimeout time.
1984                      * The wakelock is released by the delayed message.
1985                      */
1986                     sDriverStopWakeLock.acquire();
1987                     mWifiHandler.sendEmptyMessage(MESSAGE_STOP_WIFI);
1988                     mWifiHandler.sendEmptyMessageDelayed(MESSAGE_RELEASE_WAKELOCK, wakeLockTimeout);
1989                 }
1990             } else {
1991                 sWakeLock.acquire();
1992                 sendEnableMessage(false, false, mLastEnableUid);
1993             }
1994         }
1995     }
1996 
registerForBroadcasts()1997     private void registerForBroadcasts() {
1998         IntentFilter intentFilter = new IntentFilter();
1999         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
2000         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
2001         intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
2002         intentFilter.addAction(ACTION_DEVICE_IDLE);
2003         intentFilter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
2004         mContext.registerReceiver(mReceiver, intentFilter);
2005     }
2006 
isAirplaneSensitive()2007     private boolean isAirplaneSensitive() {
2008         String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
2009                 Settings.System.AIRPLANE_MODE_RADIOS);
2010         return airplaneModeRadios == null
2011             || airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
2012     }
2013 
isAirplaneToggleable()2014     private boolean isAirplaneToggleable() {
2015         String toggleableRadios = Settings.System.getString(mContext.getContentResolver(),
2016                 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
2017         return toggleableRadios != null
2018             && toggleableRadios.contains(Settings.System.RADIO_WIFI);
2019     }
2020 
2021     /**
2022      * Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is
2023      * currently on.
2024      * @return {@code true} if airplane mode is on.
2025      */
isAirplaneModeOn()2026     private boolean isAirplaneModeOn() {
2027         return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(),
2028                 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
2029     }
2030 
2031     /**
2032      * Handler that allows posting to the WifiThread.
2033      */
2034     private class WifiHandler extends Handler {
WifiHandler(Looper looper)2035         public WifiHandler(Looper looper) {
2036             super(looper);
2037         }
2038 
2039         @Override
handleMessage(Message msg)2040         public void handleMessage(Message msg) {
2041             switch (msg.what) {
2042 
2043                 case MESSAGE_ENABLE_WIFI:
2044                     setWifiEnabledBlocking(true, msg.arg1 == 1, msg.arg2);
2045                     if (mWifiWatchdogService == null) {
2046                         mWifiWatchdogService = new WifiWatchdogService(mContext, mWifiStateTracker);
2047                     }
2048                     sWakeLock.release();
2049                     break;
2050 
2051                 case MESSAGE_START_WIFI:
2052                     reportStartWorkSource();
2053                     mWifiStateTracker.setScanOnlyMode(msg.arg1 == WifiManager.WIFI_MODE_SCAN_ONLY);
2054                     mWifiStateTracker.restart();
2055                     mWifiStateTracker.setHighPerfMode(msg.arg1 ==
2056                             WifiManager.WIFI_MODE_FULL_HIGH_PERF);
2057                     sWakeLock.release();
2058                     break;
2059 
2060                 case MESSAGE_UPDATE_STATE:
2061                     doUpdateWifiState();
2062                     break;
2063 
2064                 case MESSAGE_DISABLE_WIFI:
2065                     // a non-zero msg.arg1 value means the "enabled" setting
2066                     // should be persisted
2067                     setWifiEnabledBlocking(false, msg.arg1 == 1, msg.arg2);
2068                     mWifiWatchdogService = null;
2069                     sWakeLock.release();
2070                     break;
2071 
2072                 case MESSAGE_STOP_WIFI:
2073                     mWifiStateTracker.disconnectAndStop();
2074                     // don't release wakelock
2075                     break;
2076 
2077                 case MESSAGE_RELEASE_WAKELOCK:
2078                     sDriverStopWakeLock.release();
2079                     break;
2080 
2081                 case MESSAGE_START_ACCESS_POINT:
2082                     setWifiApEnabledBlocking(true,
2083                                              msg.arg1,
2084                                              (WifiConfiguration) msg.obj);
2085                     sWakeLock.release();
2086                     break;
2087 
2088                 case MESSAGE_STOP_ACCESS_POINT:
2089                     setWifiApEnabledBlocking(false,
2090                                              msg.arg1,
2091                                              (WifiConfiguration) msg.obj);
2092                     sWakeLock.release();
2093                     break;
2094 
2095                 case MESSAGE_SET_CHANNELS:
2096                     setNumAllowedChannelsBlocking(msg.arg1, msg.arg2 == 1);
2097                     break;
2098 
2099                 case MESSAGE_ENABLE_NETWORKS:
2100                     mWifiStateTracker.enableAllNetworks(getConfiguredNetworks());
2101                     break;
2102 
2103                 case MESSAGE_START_SCAN:
2104                     boolean forceActive = (msg.arg1 == 1);
2105                     switch (mWifiStateTracker.getSupplicantState()) {
2106                         case DISCONNECTED:
2107                         case INACTIVE:
2108                         case SCANNING:
2109                         case DORMANT:
2110                             break;
2111                         default:
2112                             mWifiStateTracker.setScanResultHandling(
2113                                     WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY);
2114                             break;
2115                     }
2116                     mWifiStateTracker.scan(forceActive);
2117                     break;
2118                 case MESSAGE_REPORT_WORKSOURCE:
2119                     reportStartWorkSource();
2120                     break;
2121                 case MESSAGE_ENABLE_RSSI_POLLING:
2122                     mWifiStateTracker.enableRssiPolling(msg.arg1 == 1);
2123                     break;
2124                 case MESSAGE_WRITE_WIFI_AP_CONFIG:
2125                     writeWifiApConfigBlocked((WifiConfiguration) msg.obj);
2126                     break;
2127                 case MESSAGE_READ_WIFI_AP_CONFIG:
2128                     readWifiApConfigBlocked();
2129                     break;
2130             }
2131         }
2132     }
2133 
2134     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)2135     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2136         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2137                 != PackageManager.PERMISSION_GRANTED) {
2138             pw.println("Permission Denial: can't dump WifiService from from pid="
2139                     + Binder.getCallingPid()
2140                     + ", uid=" + Binder.getCallingUid());
2141             return;
2142         }
2143         pw.println("Wi-Fi is " + stateName(mWifiStateTracker.getWifiState()));
2144         pw.println("Stay-awake conditions: " +
2145                 Settings.System.getInt(mContext.getContentResolver(),
2146                                        Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
2147         pw.println();
2148 
2149         pw.println("Internal state:");
2150         pw.println(mWifiStateTracker);
2151         pw.println();
2152         pw.println("Latest scan results:");
2153         List<ScanResult> scanResults = mWifiStateTracker.getScanResultsList();
2154         if (scanResults != null && scanResults.size() != 0) {
2155             pw.println("  BSSID              Frequency   RSSI  Flags             SSID");
2156             for (ScanResult r : scanResults) {
2157                 pw.printf("  %17s  %9d  %5d  %-16s  %s%n",
2158                                          r.BSSID,
2159                                          r.frequency,
2160                                          r.level,
2161                                          r.capabilities,
2162                                          r.SSID == null ? "" : r.SSID);
2163             }
2164         }
2165         pw.println();
2166         pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
2167                 mFullHighPerfLocksAcquired + " full high perf, " +
2168                 mScanLocksAcquired + " scan");
2169         pw.println("Locks released: " + mFullLocksReleased + " full, " +
2170                 mFullHighPerfLocksReleased + " full high perf, " +
2171                 mScanLocksReleased + " scan");
2172         pw.println();
2173         pw.println("Locks held:");
2174         mLocks.dump(pw);
2175     }
2176 
stateName(int wifiState)2177     private static String stateName(int wifiState) {
2178         switch (wifiState) {
2179             case WIFI_STATE_DISABLING:
2180                 return "disabling";
2181             case WIFI_STATE_DISABLED:
2182                 return "disabled";
2183             case WIFI_STATE_ENABLING:
2184                 return "enabling";
2185             case WIFI_STATE_ENABLED:
2186                 return "enabled";
2187             case WIFI_STATE_UNKNOWN:
2188                 return "unknown state";
2189             default:
2190                 return "[invalid state]";
2191         }
2192     }
2193 
2194     private class WifiLock extends DeathRecipient {
WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws)2195         WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
2196             super(lockMode, tag, binder, ws);
2197         }
2198 
binderDied()2199         public void binderDied() {
2200             synchronized (mLocks) {
2201                 releaseWifiLockLocked(mBinder);
2202             }
2203         }
2204 
toString()2205         public String toString() {
2206             return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
2207         }
2208     }
2209 
2210     private class LockList {
2211         private List<WifiLock> mList;
2212 
LockList()2213         private LockList() {
2214             mList = new ArrayList<WifiLock>();
2215         }
2216 
hasLocks()2217         private synchronized boolean hasLocks() {
2218             return !mList.isEmpty();
2219         }
2220 
getStrongestLockMode()2221         private synchronized int getStrongestLockMode() {
2222             if (mList.isEmpty()) {
2223                 return WifiManager.WIFI_MODE_FULL;
2224             }
2225 
2226             if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
2227                 return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
2228             }
2229 
2230             if (mFullLocksAcquired > mFullLocksReleased) {
2231                 return WifiManager.WIFI_MODE_FULL;
2232             }
2233 
2234             return WifiManager.WIFI_MODE_SCAN_ONLY;
2235         }
2236 
addLock(WifiLock lock)2237         private void addLock(WifiLock lock) {
2238             if (findLockByBinder(lock.mBinder) < 0) {
2239                 mList.add(lock);
2240             }
2241         }
2242 
removeLock(IBinder binder)2243         private WifiLock removeLock(IBinder binder) {
2244             int index = findLockByBinder(binder);
2245             if (index >= 0) {
2246                 WifiLock ret = mList.remove(index);
2247                 ret.unlinkDeathRecipient();
2248                 return ret;
2249             } else {
2250                 return null;
2251             }
2252         }
2253 
findLockByBinder(IBinder binder)2254         private int findLockByBinder(IBinder binder) {
2255             int size = mList.size();
2256             for (int i = size - 1; i >= 0; i--)
2257                 if (mList.get(i).mBinder == binder)
2258                     return i;
2259             return -1;
2260         }
2261 
dump(PrintWriter pw)2262         private void dump(PrintWriter pw) {
2263             for (WifiLock l : mList) {
2264                 pw.print("    ");
2265                 pw.println(l);
2266             }
2267         }
2268     }
2269 
enforceWakeSourcePermission(int uid, int pid)2270     void enforceWakeSourcePermission(int uid, int pid) {
2271         if (uid == Process.myUid()) {
2272             return;
2273         }
2274         mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
2275                 pid, uid, null);
2276     }
2277 
acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws)2278     public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
2279         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
2280         if (lockMode != WifiManager.WIFI_MODE_FULL &&
2281                 lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
2282                 lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
2283             Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
2284             if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
2285             return false;
2286         }
2287         if (ws != null && ws.size() == 0) {
2288             ws = null;
2289         }
2290         if (ws != null) {
2291             enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
2292         }
2293         if (ws == null) {
2294             ws = new WorkSource(Binder.getCallingUid());
2295         }
2296         WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
2297         synchronized (mLocks) {
2298             return acquireWifiLockLocked(wifiLock);
2299         }
2300     }
2301 
noteAcquireWifiLock(WifiLock wifiLock)2302     private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
2303         switch(wifiLock.mMode) {
2304             case WifiManager.WIFI_MODE_FULL:
2305                 mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
2306                 break;
2307             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
2308                 /* Treat high power as a full lock for battery stats */
2309                 mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
2310                 break;
2311             case WifiManager.WIFI_MODE_SCAN_ONLY:
2312                 mBatteryStats.noteScanWifiLockAcquiredFromSource(wifiLock.mWorkSource);
2313                 break;
2314         }
2315     }
2316 
noteReleaseWifiLock(WifiLock wifiLock)2317     private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
2318         switch(wifiLock.mMode) {
2319             case WifiManager.WIFI_MODE_FULL:
2320                 mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
2321                 break;
2322             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
2323                 /* Treat high power as a full lock for battery stats */
2324                 mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
2325                 break;
2326             case WifiManager.WIFI_MODE_SCAN_ONLY:
2327                 mBatteryStats.noteScanWifiLockReleasedFromSource(wifiLock.mWorkSource);
2328                 break;
2329         }
2330     }
2331 
acquireWifiLockLocked(WifiLock wifiLock)2332     private boolean acquireWifiLockLocked(WifiLock wifiLock) {
2333         if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
2334 
2335         mLocks.addLock(wifiLock);
2336 
2337         long ident = Binder.clearCallingIdentity();
2338         try {
2339             noteAcquireWifiLock(wifiLock);
2340             switch(wifiLock.mMode) {
2341             case WifiManager.WIFI_MODE_FULL:
2342                 ++mFullLocksAcquired;
2343                 break;
2344             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
2345                 ++mFullHighPerfLocksAcquired;
2346                 break;
2347             case WifiManager.WIFI_MODE_SCAN_ONLY:
2348                 ++mScanLocksAcquired;
2349                 break;
2350             }
2351 
2352             // Be aggressive about adding new locks into the accounted state...
2353             // we want to over-report rather than under-report.
2354             sendReportWorkSourceMessage();
2355 
2356             updateWifiState();
2357             return true;
2358         } catch (RemoteException e) {
2359             return false;
2360         } finally {
2361             Binder.restoreCallingIdentity(ident);
2362         }
2363     }
2364 
updateWifiLockWorkSource(IBinder lock, WorkSource ws)2365     public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
2366         int uid = Binder.getCallingUid();
2367         int pid = Binder.getCallingPid();
2368         if (ws != null && ws.size() == 0) {
2369             ws = null;
2370         }
2371         if (ws != null) {
2372             enforceWakeSourcePermission(uid, pid);
2373         }
2374         long ident = Binder.clearCallingIdentity();
2375         try {
2376             synchronized (mLocks) {
2377                 int index = mLocks.findLockByBinder(lock);
2378                 if (index < 0) {
2379                     throw new IllegalArgumentException("Wifi lock not active");
2380                 }
2381                 WifiLock wl = mLocks.mList.get(index);
2382                 noteReleaseWifiLock(wl);
2383                 wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
2384                 noteAcquireWifiLock(wl);
2385             }
2386         } catch (RemoteException e) {
2387         } finally {
2388             Binder.restoreCallingIdentity(ident);
2389         }
2390     }
2391 
releaseWifiLock(IBinder lock)2392     public boolean releaseWifiLock(IBinder lock) {
2393         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
2394         synchronized (mLocks) {
2395             return releaseWifiLockLocked(lock);
2396         }
2397     }
2398 
releaseWifiLockLocked(IBinder lock)2399     private boolean releaseWifiLockLocked(IBinder lock) {
2400         boolean hadLock;
2401 
2402         WifiLock wifiLock = mLocks.removeLock(lock);
2403 
2404         if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
2405 
2406         hadLock = (wifiLock != null);
2407 
2408         long ident = Binder.clearCallingIdentity();
2409         try {
2410             if (hadLock) {
2411                 noteAcquireWifiLock(wifiLock);
2412                 switch(wifiLock.mMode) {
2413                     case WifiManager.WIFI_MODE_FULL:
2414                         ++mFullLocksReleased;
2415                         break;
2416                     case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
2417                         ++mFullHighPerfLocksReleased;
2418                         break;
2419                     case WifiManager.WIFI_MODE_SCAN_ONLY:
2420                         ++mScanLocksReleased;
2421                         break;
2422                 }
2423             }
2424 
2425             // TODO - should this only happen if you hadLock?
2426             updateWifiState();
2427 
2428         } catch (RemoteException e) {
2429         } finally {
2430             Binder.restoreCallingIdentity(ident);
2431         }
2432 
2433         return hadLock;
2434     }
2435 
2436     private abstract class DeathRecipient
2437             implements IBinder.DeathRecipient {
2438         String mTag;
2439         int mMode;
2440         IBinder mBinder;
2441         WorkSource mWorkSource;
2442 
DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws)2443         DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) {
2444             super();
2445             mTag = tag;
2446             mMode = mode;
2447             mBinder = binder;
2448             mWorkSource = ws;
2449             try {
2450                 mBinder.linkToDeath(this, 0);
2451             } catch (RemoteException e) {
2452                 binderDied();
2453             }
2454         }
2455 
unlinkDeathRecipient()2456         void unlinkDeathRecipient() {
2457             mBinder.unlinkToDeath(this, 0);
2458         }
2459     }
2460 
2461     private class Multicaster extends DeathRecipient {
Multicaster(String tag, IBinder binder)2462         Multicaster(String tag, IBinder binder) {
2463             super(Binder.getCallingUid(), tag, binder, null);
2464         }
2465 
binderDied()2466         public void binderDied() {
2467             Slog.e(TAG, "Multicaster binderDied");
2468             synchronized (mMulticasters) {
2469                 int i = mMulticasters.indexOf(this);
2470                 if (i != -1) {
2471                     removeMulticasterLocked(i, mMode);
2472                 }
2473             }
2474         }
2475 
toString()2476         public String toString() {
2477             return "Multicaster{" + mTag + " binder=" + mBinder + "}";
2478         }
2479 
getUid()2480         public int getUid() {
2481             return mMode;
2482         }
2483     }
2484 
initializeMulticastFiltering()2485     public void initializeMulticastFiltering() {
2486         enforceMulticastChangePermission();
2487 
2488         synchronized (mMulticasters) {
2489             // if anybody had requested filters be off, leave off
2490             if (mMulticasters.size() != 0) {
2491                 return;
2492             } else {
2493                 mWifiStateTracker.startPacketFiltering();
2494             }
2495         }
2496     }
2497 
acquireMulticastLock(IBinder binder, String tag)2498     public void acquireMulticastLock(IBinder binder, String tag) {
2499         enforceMulticastChangePermission();
2500 
2501         synchronized (mMulticasters) {
2502             mMulticastEnabled++;
2503             mMulticasters.add(new Multicaster(tag, binder));
2504             // Note that we could call stopPacketFiltering only when
2505             // our new size == 1 (first call), but this function won't
2506             // be called often and by making the stopPacket call each
2507             // time we're less fragile and self-healing.
2508             mWifiStateTracker.stopPacketFiltering();
2509         }
2510 
2511         int uid = Binder.getCallingUid();
2512         Long ident = Binder.clearCallingIdentity();
2513         try {
2514             mBatteryStats.noteWifiMulticastEnabled(uid);
2515         } catch (RemoteException e) {
2516         } finally {
2517             Binder.restoreCallingIdentity(ident);
2518         }
2519     }
2520 
releaseMulticastLock()2521     public void releaseMulticastLock() {
2522         enforceMulticastChangePermission();
2523 
2524         int uid = Binder.getCallingUid();
2525         synchronized (mMulticasters) {
2526             mMulticastDisabled++;
2527             int size = mMulticasters.size();
2528             for (int i = size - 1; i >= 0; i--) {
2529                 Multicaster m = mMulticasters.get(i);
2530                 if ((m != null) && (m.getUid() == uid)) {
2531                     removeMulticasterLocked(i, uid);
2532                 }
2533             }
2534         }
2535     }
2536 
removeMulticasterLocked(int i, int uid)2537     private void removeMulticasterLocked(int i, int uid)
2538     {
2539         Multicaster removed = mMulticasters.remove(i);
2540 
2541         if (removed != null) {
2542             removed.unlinkDeathRecipient();
2543         }
2544         if (mMulticasters.size() == 0) {
2545             mWifiStateTracker.startPacketFiltering();
2546         }
2547 
2548         Long ident = Binder.clearCallingIdentity();
2549         try {
2550             mBatteryStats.noteWifiMulticastDisabled(uid);
2551         } catch (RemoteException e) {
2552         } finally {
2553             Binder.restoreCallingIdentity(ident);
2554         }
2555     }
2556 
isMulticastEnabled()2557     public boolean isMulticastEnabled() {
2558         enforceAccessPermission();
2559 
2560         synchronized (mMulticasters) {
2561             return (mMulticasters.size() > 0);
2562         }
2563     }
2564 }
2565