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