Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (C) 2010 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 android.app.AlarmManager;
     20 import android.app.Notification;
     21 import android.app.NotificationManager;
     22 import android.app.PendingIntent;
     23 import android.bluetooth.BluetoothAdapter;
     24 import android.content.BroadcastReceiver;
     25 import android.content.ContentResolver;
     26 import android.content.Context;
     27 import android.content.Intent;
     28 import android.content.IntentFilter;
     29 import android.content.pm.PackageManager;
     30 import android.database.ContentObserver;
     31 import android.net.wifi.IWifiManager;
     32 import android.net.wifi.ScanResult;
     33 import android.net.wifi.SupplicantState;
     34 import android.net.wifi.WifiInfo;
     35 import android.net.wifi.WifiManager;
     36 import android.net.wifi.WifiStateMachine;
     37 import android.net.wifi.WifiConfiguration;
     38 import android.net.wifi.WifiWatchdogStateMachine;
     39 import android.net.wifi.WifiConfiguration.KeyMgmt;
     40 import android.net.wifi.WpsInfo;
     41 import android.net.wifi.WpsResult;
     42 import android.net.ConnectivityManager;
     43 import android.net.DhcpInfo;
     44 import android.net.NetworkInfo;
     45 import android.net.NetworkInfo.State;
     46 import android.net.NetworkInfo.DetailedState;
     47 import android.net.TrafficStats;
     48 import android.os.Binder;
     49 import android.os.Handler;
     50 import android.os.Messenger;
     51 import android.os.HandlerThread;
     52 import android.os.IBinder;
     53 import android.os.INetworkManagementService;
     54 import android.os.Message;
     55 import android.os.RemoteException;
     56 import android.os.ServiceManager;
     57 import android.os.SystemProperties;
     58 import android.os.WorkSource;
     59 import android.provider.Settings;
     60 import android.text.TextUtils;
     61 import android.util.Slog;
     62 
     63 import java.util.ArrayList;
     64 import java.util.List;
     65 import java.util.Set;
     66 import java.util.concurrent.atomic.AtomicInteger;
     67 import java.util.concurrent.atomic.AtomicBoolean;
     68 import java.io.FileDescriptor;
     69 import java.io.PrintWriter;
     70 
     71 import com.android.internal.app.IBatteryStats;
     72 import com.android.internal.telephony.TelephonyIntents;
     73 import com.android.internal.util.AsyncChannel;
     74 import com.android.server.am.BatteryStatsService;
     75 import com.android.internal.R;
     76 
     77 /**
     78  * WifiService handles remote WiFi operation requests by implementing
     79  * the IWifiManager interface.
     80  *
     81  * @hide
     82  */
     83 //TODO: Clean up multiple locks and implement WifiService
     84 // as a SM to track soft AP/client/adhoc bring up based
     85 // on device idle state, airplane mode and boot.
     86 
     87 public class WifiService extends IWifiManager.Stub {
     88     private static final String TAG = "WifiService";
     89     private static final boolean DBG = false;
     90 
     91     private final WifiStateMachine mWifiStateMachine;
     92 
     93     private Context mContext;
     94 
     95     private AlarmManager mAlarmManager;
     96     private PendingIntent mIdleIntent;
     97     private static final int IDLE_REQUEST = 0;
     98     private boolean mScreenOff;
     99     private boolean mDeviceIdle;
    100     private boolean mEmergencyCallbackMode = false;
    101     private int mPluggedType;
    102 
    103     /* Chipset supports background scan */
    104     private final boolean mBackgroundScanSupported;
    105 
    106     private final LockList mLocks = new LockList();
    107     // some wifi lock statistics
    108     private int mFullHighPerfLocksAcquired;
    109     private int mFullHighPerfLocksReleased;
    110     private int mFullLocksAcquired;
    111     private int mFullLocksReleased;
    112     private int mScanLocksAcquired;
    113     private int mScanLocksReleased;
    114 
    115     private final List<Multicaster> mMulticasters =
    116             new ArrayList<Multicaster>();
    117     private int mMulticastEnabled;
    118     private int mMulticastDisabled;
    119 
    120     private final IBatteryStats mBatteryStats;
    121 
    122     private boolean mEnableTrafficStatsPoll = false;
    123     private int mTrafficStatsPollToken = 0;
    124     private long mTxPkts;
    125     private long mRxPkts;
    126     /* Tracks last reported data activity */
    127     private int mDataActivity;
    128     private String mInterfaceName;
    129 
    130     /**
    131      * Interval in milliseconds between polling for traffic
    132      * statistics
    133      */
    134     private static final int POLL_TRAFFIC_STATS_INTERVAL_MSECS = 1000;
    135 
    136     /**
    137      * See {@link Settings.Secure#WIFI_IDLE_MS}. This is the default value if a
    138      * Settings.Secure value is not present. This timeout value is chosen as
    139      * the approximate point at which the battery drain caused by Wi-Fi
    140      * being enabled but not active exceeds the battery drain caused by
    141      * re-establishing a connection to the mobile data network.
    142      */
    143     private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */
    144 
    145     private static final String ACTION_DEVICE_IDLE =
    146             "com.android.server.WifiManager.action.DEVICE_IDLE";
    147 
    148     private static final int WIFI_DISABLED                  = 0;
    149     private static final int WIFI_ENABLED                   = 1;
    150     /* Wifi enabled while in airplane mode */
    151     private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2;
    152     /* Wifi disabled due to airplane mode on */
    153     private static final int WIFI_DISABLED_AIRPLANE_ON      = 3;
    154 
    155     /* Persisted state that tracks the wifi & airplane interaction from settings */
    156     private AtomicInteger mPersistWifiState = new AtomicInteger(WIFI_DISABLED);
    157     /* Tracks current airplane mode state */
    158     private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false);
    159     /* Tracks whether wifi is enabled from WifiStateMachine's perspective */
    160     private boolean mWifiEnabled;
    161 
    162     private boolean mIsReceiverRegistered = false;
    163 
    164 
    165     NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
    166 
    167     // Variables relating to the 'available networks' notification
    168     /**
    169      * The icon to show in the 'available networks' notification. This will also
    170      * be the ID of the Notification given to the NotificationManager.
    171      */
    172     private static final int ICON_NETWORKS_AVAILABLE =
    173             com.android.internal.R.drawable.stat_notify_wifi_in_range;
    174     /**
    175      * When a notification is shown, we wait this amount before possibly showing it again.
    176      */
    177     private final long NOTIFICATION_REPEAT_DELAY_MS;
    178     /**
    179      * Whether the user has set the setting to show the 'available networks' notification.
    180      */
    181     private boolean mNotificationEnabled;
    182     /**
    183      * Observes the user setting to keep {@link #mNotificationEnabled} in sync.
    184      */
    185     private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
    186     /**
    187      * The {@link System#currentTimeMillis()} must be at least this value for us
    188      * to show the notification again.
    189      */
    190     private long mNotificationRepeatTime;
    191     /**
    192      * The Notification object given to the NotificationManager.
    193      */
    194     private Notification mNotification;
    195     /**
    196      * Whether the notification is being shown, as set by us. That is, if the
    197      * user cancels the notification, we will not receive the callback so this
    198      * will still be true. We only guarantee if this is false, then the
    199      * notification is not showing.
    200      */
    201     private boolean mNotificationShown;
    202     /**
    203      * The number of continuous scans that must occur before consider the
    204      * supplicant in a scanning state. This allows supplicant to associate with
    205      * remembered networks that are in the scan results.
    206      */
    207     private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3;
    208     /**
    209      * The number of scans since the last network state change. When this
    210      * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the
    211      * supplicant to actually be scanning. When the network state changes to
    212      * something other than scanning, we reset this to 0.
    213      */
    214     private int mNumScansSinceNetworkStateChange;
    215 
    216     /**
    217      * Asynchronous channel to WifiStateMachine
    218      */
    219     private AsyncChannel mWifiStateMachineChannel;
    220 
    221     /**
    222      * Clients receiving asynchronous messages
    223      */
    224     private List<AsyncChannel> mClients = new ArrayList<AsyncChannel>();
    225 
    226     /**
    227      * Handles client connections
    228      */
    229     private class AsyncServiceHandler extends Handler {
    230 
    231         AsyncServiceHandler(android.os.Looper looper) {
    232             super(looper);
    233         }
    234 
    235         @Override
    236         public void handleMessage(Message msg) {
    237             switch (msg.what) {
    238                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
    239                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
    240                         Slog.d(TAG, "New client listening to asynchronous messages");
    241                         mClients.add((AsyncChannel) msg.obj);
    242                     } else {
    243                         Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
    244                     }
    245                     break;
    246                 }
    247                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
    248                     if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
    249                         Slog.d(TAG, "Send failed, client connection lost");
    250                     } else {
    251                         Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
    252                     }
    253                     mClients.remove((AsyncChannel) msg.obj);
    254                     break;
    255                 }
    256                 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
    257                     AsyncChannel ac = new AsyncChannel();
    258                     ac.connect(mContext, this, msg.replyTo);
    259                     break;
    260                 }
    261                 case WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL: {
    262                     mEnableTrafficStatsPoll = (msg.arg1 == 1);
    263                     mTrafficStatsPollToken++;
    264                     if (mEnableTrafficStatsPoll) {
    265                         notifyOnDataActivity();
    266                         sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL,
    267                                 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
    268                     }
    269                     break;
    270                 }
    271                 case WifiManager.CMD_TRAFFIC_STATS_POLL: {
    272                     if (msg.arg1 == mTrafficStatsPollToken) {
    273                         notifyOnDataActivity();
    274                         sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL,
    275                                 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
    276                     }
    277                     break;
    278                 }
    279                 case WifiManager.CMD_CONNECT_NETWORK: {
    280                     if (msg.obj != null) {
    281                         mWifiStateMachine.connectNetwork((WifiConfiguration)msg.obj);
    282                     } else {
    283                         mWifiStateMachine.connectNetwork(msg.arg1);
    284                     }
    285                     break;
    286                 }
    287                 case WifiManager.CMD_SAVE_NETWORK: {
    288                     mWifiStateMachine.saveNetwork((WifiConfiguration)msg.obj);
    289                     break;
    290                 }
    291                 case WifiManager.CMD_FORGET_NETWORK: {
    292                     mWifiStateMachine.forgetNetwork(msg.arg1);
    293                     break;
    294                 }
    295                 case WifiManager.CMD_START_WPS: {
    296                     //replyTo has the original source
    297                     mWifiStateMachine.startWps(msg.replyTo, (WpsInfo)msg.obj);
    298                     break;
    299                 }
    300                 case WifiManager.CMD_DISABLE_NETWORK: {
    301                     mWifiStateMachine.disableNetwork(msg.replyTo, msg.arg1, msg.arg2);
    302                     break;
    303                 }
    304                 default: {
    305                     Slog.d(TAG, "WifiServicehandler.handleMessage ignoring msg=" + msg);
    306                     break;
    307                 }
    308             }
    309         }
    310     }
    311     private AsyncServiceHandler mAsyncServiceHandler;
    312 
    313     /**
    314      * Handles interaction with WifiStateMachine
    315      */
    316     private class WifiStateMachineHandler extends Handler {
    317         private AsyncChannel mWsmChannel;
    318 
    319         WifiStateMachineHandler(android.os.Looper looper) {
    320             super(looper);
    321             mWsmChannel = new AsyncChannel();
    322             mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
    323         }
    324 
    325         @Override
    326         public void handleMessage(Message msg) {
    327             switch (msg.what) {
    328                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
    329                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
    330                         mWifiStateMachineChannel = mWsmChannel;
    331                     } else {
    332                         Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1);
    333                         mWifiStateMachineChannel = null;
    334                     }
    335                     break;
    336                 }
    337                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
    338                     Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1);
    339                     mWifiStateMachineChannel = null;
    340                     //Re-establish connection to state machine
    341                     mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
    342                     break;
    343                 }
    344                 default: {
    345                     Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg);
    346                     break;
    347                 }
    348             }
    349         }
    350     }
    351     WifiStateMachineHandler mWifiStateMachineHandler;
    352 
    353     /**
    354      * Temporary for computing UIDS that are responsible for starting WIFI.
    355      * Protected by mWifiStateTracker lock.
    356      */
    357     private final WorkSource mTmpWorkSource = new WorkSource();
    358     private WifiWatchdogStateMachine mWifiWatchdogStateMachine;
    359 
    360     WifiService(Context context) {
    361         mContext = context;
    362 
    363         mInterfaceName =  SystemProperties.get("wifi.interface", "wlan0");
    364 
    365         mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName);
    366         mWifiStateMachine.enableRssiPolling(true);
    367         mBatteryStats = BatteryStatsService.getService();
    368 
    369         mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
    370         Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
    371         mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
    372 
    373         mContext.registerReceiver(
    374                 new BroadcastReceiver() {
    375                     @Override
    376                     public void onReceive(Context context, Intent intent) {
    377                         mAirplaneModeOn.set(isAirplaneModeOn());
    378                         /* On airplane mode disable, restore wifi state if necessary */
    379                         if (!mAirplaneModeOn.get() && (testAndClearWifiSavedState() ||
    380                             mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) {
    381                                 persistWifiState(true);
    382                         }
    383                         updateWifiState();
    384                     }
    385                 },
    386                 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
    387 
    388         IntentFilter filter = new IntentFilter();
    389         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
    390         filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
    391         filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
    392 
    393         mContext.registerReceiver(
    394                 new BroadcastReceiver() {
    395                     @Override
    396                     public void onReceive(Context context, Intent intent) {
    397                         if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
    398                             int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
    399                                     WifiManager.WIFI_STATE_DISABLED);
    400 
    401                             mWifiEnabled = (wifiState == WifiManager.WIFI_STATE_ENABLED);
    402 
    403                            // reset & clear notification on any wifi state change
    404                             resetNotification();
    405                         } else if (intent.getAction().equals(
    406                                 WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
    407                             mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
    408                                     WifiManager.EXTRA_NETWORK_INFO);
    409                             // reset & clear notification on a network connect & disconnect
    410                             switch(mNetworkInfo.getDetailedState()) {
    411                                 case CONNECTED:
    412                                 case DISCONNECTED:
    413                                     evaluateTrafficStatsPolling();
    414                                     resetNotification();
    415                                     break;
    416                             }
    417                         } else if (intent.getAction().equals(
    418                                 WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
    419                             checkAndSetNotification();
    420                         }
    421                     }
    422                 }, filter);
    423 
    424         HandlerThread wifiThread = new HandlerThread("WifiService");
    425         wifiThread.start();
    426         mAsyncServiceHandler = new AsyncServiceHandler(wifiThread.getLooper());
    427         mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
    428 
    429         // Setting is in seconds
    430         NOTIFICATION_REPEAT_DELAY_MS = Settings.Secure.getInt(context.getContentResolver(),
    431                 Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
    432         mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler());
    433         mNotificationEnabledSettingObserver.register();
    434 
    435         mBackgroundScanSupported = mContext.getResources().getBoolean(
    436                 com.android.internal.R.bool.config_wifi_background_scan_support);
    437     }
    438 
    439     /**
    440      * Check if Wi-Fi needs to be enabled and start
    441      * if needed
    442      *
    443      * This function is used only at boot time
    444      */
    445     public void checkAndStartWifi() {
    446         mAirplaneModeOn.set(isAirplaneModeOn());
    447         mPersistWifiState.set(getPersistedWifiState());
    448         /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
    449         boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
    450         Slog.i(TAG, "WifiService starting up with Wi-Fi " +
    451                 (wifiEnabled ? "enabled" : "disabled"));
    452         setWifiEnabled(wifiEnabled);
    453 
    454         mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
    455                makeWifiWatchdogStateMachine(mContext);
    456 
    457     }
    458 
    459     private boolean testAndClearWifiSavedState() {
    460         final ContentResolver cr = mContext.getContentResolver();
    461         int wifiSavedState = 0;
    462         try {
    463             wifiSavedState = Settings.Secure.getInt(cr, Settings.Secure.WIFI_SAVED_STATE);
    464             if(wifiSavedState == 1)
    465                 Settings.Secure.putInt(cr, Settings.Secure.WIFI_SAVED_STATE, 0);
    466         } catch (Settings.SettingNotFoundException e) {
    467             ;
    468         }
    469         return (wifiSavedState == 1);
    470     }
    471 
    472     private int getPersistedWifiState() {
    473         final ContentResolver cr = mContext.getContentResolver();
    474         try {
    475             return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON);
    476         } catch (Settings.SettingNotFoundException e) {
    477             Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, WIFI_DISABLED);
    478             return WIFI_DISABLED;
    479         }
    480     }
    481 
    482     private boolean shouldWifiBeEnabled() {
    483         if (mAirplaneModeOn.get()) {
    484             return mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
    485         } else {
    486             return mPersistWifiState.get() != WIFI_DISABLED;
    487         }
    488     }
    489 
    490     private void persistWifiState(boolean enabled) {
    491         final ContentResolver cr = mContext.getContentResolver();
    492         boolean airplane = mAirplaneModeOn.get() && isAirplaneToggleable();
    493         if (enabled) {
    494             if (airplane) {
    495                 mPersistWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
    496             } else {
    497                 mPersistWifiState.set(WIFI_ENABLED);
    498             }
    499         } else {
    500             if (airplane) {
    501                 mPersistWifiState.set(WIFI_DISABLED_AIRPLANE_ON);
    502             } else {
    503                 mPersistWifiState.set(WIFI_DISABLED);
    504             }
    505         }
    506 
    507         Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mPersistWifiState.get());
    508     }
    509 
    510 
    511     /**
    512      * see {@link android.net.wifi.WifiManager#pingSupplicant()}
    513      * @return {@code true} if the operation succeeds, {@code false} otherwise
    514      */
    515     public boolean pingSupplicant() {
    516         enforceAccessPermission();
    517         if (mWifiStateMachineChannel != null) {
    518             return mWifiStateMachine.syncPingSupplicant(mWifiStateMachineChannel);
    519         } else {
    520             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    521             return false;
    522         }
    523     }
    524 
    525     /**
    526      * see {@link android.net.wifi.WifiManager#startScan()}
    527      */
    528     public void startScan(boolean forceActive) {
    529         enforceChangePermission();
    530         mWifiStateMachine.startScan(forceActive);
    531     }
    532 
    533     private void enforceAccessPermission() {
    534         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
    535                                                 "WifiService");
    536     }
    537 
    538     private void enforceChangePermission() {
    539         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
    540                                                 "WifiService");
    541 
    542     }
    543 
    544     private void enforceMulticastChangePermission() {
    545         mContext.enforceCallingOrSelfPermission(
    546                 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
    547                 "WifiService");
    548     }
    549 
    550     /**
    551      * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
    552      * @param enable {@code true} to enable, {@code false} to disable.
    553      * @return {@code true} if the enable/disable operation was
    554      *         started or is already in the queue.
    555      */
    556     public synchronized boolean setWifiEnabled(boolean enable) {
    557         enforceChangePermission();
    558         if (DBG) {
    559             Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
    560         }
    561 
    562         if (enable) {
    563             reportStartWorkSource();
    564         }
    565         mWifiStateMachine.setWifiEnabled(enable);
    566 
    567         /*
    568          * Caller might not have WRITE_SECURE_SETTINGS,
    569          * only CHANGE_WIFI_STATE is enforced
    570          */
    571 
    572         /* Avoids overriding of airplane state when wifi is already in the expected state */
    573         if (enable != mWifiEnabled) {
    574             long ident = Binder.clearCallingIdentity();
    575             persistWifiState(enable);
    576             Binder.restoreCallingIdentity(ident);
    577         }
    578 
    579         if (enable) {
    580             if (!mIsReceiverRegistered) {
    581                 registerForBroadcasts();
    582                 mIsReceiverRegistered = true;
    583             }
    584         } else if (mIsReceiverRegistered) {
    585             mContext.unregisterReceiver(mReceiver);
    586             mIsReceiverRegistered = false;
    587         }
    588 
    589         return true;
    590     }
    591 
    592     /**
    593      * see {@link WifiManager#getWifiState()}
    594      * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
    595      *         {@link WifiManager#WIFI_STATE_DISABLING},
    596      *         {@link WifiManager#WIFI_STATE_ENABLED},
    597      *         {@link WifiManager#WIFI_STATE_ENABLING},
    598      *         {@link WifiManager#WIFI_STATE_UNKNOWN}
    599      */
    600     public int getWifiEnabledState() {
    601         enforceAccessPermission();
    602         return mWifiStateMachine.syncGetWifiState();
    603     }
    604 
    605     /**
    606      * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
    607      * @param wifiConfig SSID, security and channel details as
    608      *        part of WifiConfiguration
    609      * @param enabled true to enable and false to disable
    610      */
    611     public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
    612         enforceChangePermission();
    613         mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);
    614     }
    615 
    616     /**
    617      * see {@link WifiManager#getWifiApState()}
    618      * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
    619      *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
    620      *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
    621      *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
    622      *         {@link WifiManager#WIFI_AP_STATE_FAILED}
    623      */
    624     public int getWifiApEnabledState() {
    625         enforceAccessPermission();
    626         return mWifiStateMachine.syncGetWifiApState();
    627     }
    628 
    629     /**
    630      * see {@link WifiManager#getWifiApConfiguration()}
    631      * @return soft access point configuration
    632      */
    633     public WifiConfiguration getWifiApConfiguration() {
    634         enforceAccessPermission();
    635         return mWifiStateMachine.syncGetWifiApConfiguration();
    636     }
    637 
    638     /**
    639      * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
    640      * @param wifiConfig WifiConfiguration details for soft access point
    641      */
    642     public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
    643         enforceChangePermission();
    644         if (wifiConfig == null)
    645             return;
    646         mWifiStateMachine.setWifiApConfiguration(wifiConfig);
    647     }
    648 
    649     /**
    650      * see {@link android.net.wifi.WifiManager#disconnect()}
    651      */
    652     public void disconnect() {
    653         enforceChangePermission();
    654         mWifiStateMachine.disconnectCommand();
    655     }
    656 
    657     /**
    658      * see {@link android.net.wifi.WifiManager#reconnect()}
    659      */
    660     public void reconnect() {
    661         enforceChangePermission();
    662         mWifiStateMachine.reconnectCommand();
    663     }
    664 
    665     /**
    666      * see {@link android.net.wifi.WifiManager#reassociate()}
    667      */
    668     public void reassociate() {
    669         enforceChangePermission();
    670         mWifiStateMachine.reassociateCommand();
    671     }
    672 
    673     /**
    674      * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
    675      * @return the list of configured networks
    676      */
    677     public List<WifiConfiguration> getConfiguredNetworks() {
    678         enforceAccessPermission();
    679         return mWifiStateMachine.syncGetConfiguredNetworks();
    680     }
    681 
    682     /**
    683      * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
    684      * @return the supplicant-assigned identifier for the new or updated
    685      * network if the operation succeeds, or {@code -1} if it fails
    686      */
    687     public int addOrUpdateNetwork(WifiConfiguration config) {
    688         enforceChangePermission();
    689         if (mWifiStateMachineChannel != null) {
    690             return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
    691         } else {
    692             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    693             return -1;
    694         }
    695     }
    696 
    697      /**
    698      * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
    699      * @param netId the integer that identifies the network configuration
    700      * to the supplicant
    701      * @return {@code true} if the operation succeeded
    702      */
    703     public boolean removeNetwork(int netId) {
    704         enforceChangePermission();
    705         if (mWifiStateMachineChannel != null) {
    706             return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
    707         } else {
    708             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    709             return false;
    710         }
    711     }
    712 
    713     /**
    714      * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
    715      * @param netId the integer that identifies the network configuration
    716      * to the supplicant
    717      * @param disableOthers if true, disable all other networks.
    718      * @return {@code true} if the operation succeeded
    719      */
    720     public boolean enableNetwork(int netId, boolean disableOthers) {
    721         enforceChangePermission();
    722         if (mWifiStateMachineChannel != null) {
    723             return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
    724                     disableOthers);
    725         } else {
    726             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    727             return false;
    728         }
    729     }
    730 
    731     /**
    732      * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
    733      * @param netId the integer that identifies the network configuration
    734      * to the supplicant
    735      * @return {@code true} if the operation succeeded
    736      */
    737     public boolean disableNetwork(int netId) {
    738         enforceChangePermission();
    739         if (mWifiStateMachineChannel != null) {
    740             return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
    741         } else {
    742             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    743             return false;
    744         }
    745     }
    746 
    747     /**
    748      * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
    749      * @return the Wi-Fi information, contained in {@link WifiInfo}.
    750      */
    751     public WifiInfo getConnectionInfo() {
    752         enforceAccessPermission();
    753         /*
    754          * Make sure we have the latest information, by sending
    755          * a status request to the supplicant.
    756          */
    757         return mWifiStateMachine.syncRequestConnectionInfo();
    758     }
    759 
    760     /**
    761      * Return the results of the most recent access point scan, in the form of
    762      * a list of {@link ScanResult} objects.
    763      * @return the list of results
    764      */
    765     public List<ScanResult> getScanResults() {
    766         enforceAccessPermission();
    767         return mWifiStateMachine.syncGetScanResultsList();
    768     }
    769 
    770     /**
    771      * Tell the supplicant to persist the current list of configured networks.
    772      * @return {@code true} if the operation succeeded
    773      *
    774      * TODO: deprecate this
    775      */
    776     public boolean saveConfiguration() {
    777         boolean result = true;
    778         enforceChangePermission();
    779         if (mWifiStateMachineChannel != null) {
    780             return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
    781         } else {
    782             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    783             return false;
    784         }
    785     }
    786 
    787     /**
    788      * Set the country code
    789      * @param countryCode ISO 3166 country code.
    790      * @param persist {@code true} if the setting should be remembered.
    791      *
    792      * The persist behavior exists so that wifi can fall back to the last
    793      * persisted country code on a restart, when the locale information is
    794      * not available from telephony.
    795      */
    796     public void setCountryCode(String countryCode, boolean persist) {
    797         Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
    798                 " with persist set to " + persist);
    799         enforceChangePermission();
    800         mWifiStateMachine.setCountryCode(countryCode, persist);
    801     }
    802 
    803     /**
    804      * Set the operational frequency band
    805      * @param band One of
    806      *     {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
    807      *     {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
    808      *     {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
    809      * @param persist {@code true} if the setting should be remembered.
    810      *
    811      */
    812     public void setFrequencyBand(int band, boolean persist) {
    813         enforceChangePermission();
    814         if (!isDualBandSupported()) return;
    815         Slog.i(TAG, "WifiService trying to set frequency band to " + band +
    816                 " with persist set to " + persist);
    817         mWifiStateMachine.setFrequencyBand(band, persist);
    818     }
    819 
    820 
    821     /**
    822      * Get the operational frequency band
    823      */
    824     public int getFrequencyBand() {
    825         enforceAccessPermission();
    826         return mWifiStateMachine.getFrequencyBand();
    827     }
    828 
    829     public boolean isDualBandSupported() {
    830         //TODO: Should move towards adding a driver API that checks at runtime
    831         return mContext.getResources().getBoolean(
    832                 com.android.internal.R.bool.config_wifi_dual_band_support);
    833     }
    834 
    835     /**
    836      * Return the DHCP-assigned addresses from the last successful DHCP request,
    837      * if any.
    838      * @return the DHCP information
    839      */
    840     public DhcpInfo getDhcpInfo() {
    841         enforceAccessPermission();
    842         return mWifiStateMachine.syncGetDhcpInfo();
    843     }
    844 
    845     /**
    846      * see {@link android.net.wifi.WifiManager#startWifi}
    847      *
    848      */
    849     public void startWifi() {
    850         enforceChangePermission();
    851         /* TODO: may be add permissions for access only to connectivity service
    852          * TODO: if a start issued, keep wifi alive until a stop issued irrespective
    853          * of WifiLock & device idle status unless wifi enabled status is toggled
    854          */
    855 
    856         mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode);
    857         mWifiStateMachine.reconnectCommand();
    858     }
    859 
    860     /**
    861      * see {@link android.net.wifi.WifiManager#stopWifi}
    862      *
    863      */
    864     public void stopWifi() {
    865         enforceChangePermission();
    866         /* TODO: may be add permissions for access only to connectivity service
    867          * TODO: if a stop is issued, wifi is brought up only by startWifi
    868          * unless wifi enabled status is toggled
    869          */
    870         mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode);
    871     }
    872 
    873 
    874     /**
    875      * see {@link android.net.wifi.WifiManager#addToBlacklist}
    876      *
    877      */
    878     public void addToBlacklist(String bssid) {
    879         enforceChangePermission();
    880 
    881         mWifiStateMachine.addToBlacklist(bssid);
    882     }
    883 
    884     /**
    885      * see {@link android.net.wifi.WifiManager#clearBlacklist}
    886      *
    887      */
    888     public void clearBlacklist() {
    889         enforceChangePermission();
    890 
    891         mWifiStateMachine.clearBlacklist();
    892     }
    893 
    894     /**
    895      * Get a reference to handler. This is used by a client to establish
    896      * an AsyncChannel communication with WifiService
    897      */
    898     public Messenger getMessenger() {
    899         /* Enforce the highest permissions
    900            TODO: when we consider exposing the asynchronous API, think about
    901                  how to provide both access and change permissions seperately
    902          */
    903         enforceAccessPermission();
    904         enforceChangePermission();
    905         return new Messenger(mAsyncServiceHandler);
    906     }
    907 
    908     /**
    909      * Get the IP and proxy configuration file
    910      */
    911     public String getConfigFile() {
    912         enforceAccessPermission();
    913         return mWifiStateMachine.getConfigFile();
    914     }
    915 
    916     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    917         @Override
    918         public void onReceive(Context context, Intent intent) {
    919             String action = intent.getAction();
    920 
    921             long idleMillis =
    922                 Settings.Secure.getLong(mContext.getContentResolver(),
    923                                         Settings.Secure.WIFI_IDLE_MS, DEFAULT_IDLE_MS);
    924             int stayAwakeConditions =
    925                 Settings.System.getInt(mContext.getContentResolver(),
    926                                        Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
    927             if (action.equals(Intent.ACTION_SCREEN_ON)) {
    928                 if (DBG) {
    929                     Slog.d(TAG, "ACTION_SCREEN_ON");
    930                 }
    931                 mAlarmManager.cancel(mIdleIntent);
    932                 mScreenOff = false;
    933                 evaluateTrafficStatsPolling();
    934                 mWifiStateMachine.enableRssiPolling(true);
    935                 if (mBackgroundScanSupported) {
    936                     mWifiStateMachine.enableBackgroundScanCommand(false);
    937                 }
    938                 mWifiStateMachine.enableAllNetworks();
    939                 setDeviceIdleAndUpdateWifi(false);
    940             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
    941                 if (DBG) {
    942                     Slog.d(TAG, "ACTION_SCREEN_OFF");
    943                 }
    944                 mScreenOff = true;
    945                 evaluateTrafficStatsPolling();
    946                 mWifiStateMachine.enableRssiPolling(false);
    947                 if (mBackgroundScanSupported) {
    948                     mWifiStateMachine.enableBackgroundScanCommand(true);
    949                 }
    950                 /*
    951                  * Set a timer to put Wi-Fi to sleep, but only if the screen is off
    952                  * AND the "stay on while plugged in" setting doesn't match the
    953                  * current power conditions (i.e, not plugged in, plugged in to USB,
    954                  * or plugged in to AC).
    955                  */
    956                 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
    957                     //Delayed shutdown if wifi is connected
    958                     if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
    959                         if (DBG) Slog.d(TAG, "setting ACTION_DEVICE_IDLE: " + idleMillis + " ms");
    960                         mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
    961                                 + idleMillis, mIdleIntent);
    962                     } else {
    963                         setDeviceIdleAndUpdateWifi(true);
    964                     }
    965                 }
    966             } else if (action.equals(ACTION_DEVICE_IDLE)) {
    967                 setDeviceIdleAndUpdateWifi(true);
    968             } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
    969                 /*
    970                  * Set a timer to put Wi-Fi to sleep, but only if the screen is off
    971                  * AND we are transitioning from a state in which the device was supposed
    972                  * to stay awake to a state in which it is not supposed to stay awake.
    973                  * If "stay awake" state is not changing, we do nothing, to avoid resetting
    974                  * the already-set timer.
    975                  */
    976                 int pluggedType = intent.getIntExtra("plugged", 0);
    977                 if (DBG) {
    978                     Slog.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType);
    979                 }
    980                 if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) &&
    981                         !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) {
    982                     long triggerTime = System.currentTimeMillis() + idleMillis;
    983                     if (DBG) {
    984                         Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
    985                     }
    986                     mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
    987                 }
    988                 mPluggedType = pluggedType;
    989             } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
    990                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
    991                         BluetoothAdapter.STATE_DISCONNECTED);
    992                 mWifiStateMachine.sendBluetoothAdapterStateChange(state);
    993             } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
    994                 mEmergencyCallbackMode = intent.getBooleanExtra("phoneinECMState", false);
    995                 updateWifiState();
    996             }
    997         }
    998 
    999         /**
   1000          * Determines whether the Wi-Fi chipset should stay awake or be put to
   1001          * sleep. Looks at the setting for the sleep policy and the current
   1002          * conditions.
   1003          *
   1004          * @see #shouldDeviceStayAwake(int, int)
   1005          */
   1006         private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) {
   1007             //Never sleep as long as the user has not changed the settings
   1008             int wifiSleepPolicy = Settings.System.getInt(mContext.getContentResolver(),
   1009                     Settings.System.WIFI_SLEEP_POLICY,
   1010                     Settings.System.WIFI_SLEEP_POLICY_NEVER);
   1011 
   1012             if (wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER) {
   1013                 // Never sleep
   1014                 return true;
   1015             } else if ((wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) &&
   1016                     (pluggedType != 0)) {
   1017                 // Never sleep while plugged, and we're plugged
   1018                 return true;
   1019             } else {
   1020                 // Default
   1021                 return shouldDeviceStayAwake(stayAwakeConditions, pluggedType);
   1022             }
   1023         }
   1024 
   1025         /**
   1026          * Determine whether the bit value corresponding to {@code pluggedType} is set in
   1027          * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value
   1028          * of {@code 0} isn't really a plugged type, but rather an indication that the
   1029          * device isn't plugged in at all, there is no bit value corresponding to a
   1030          * {@code pluggedType} value of {@code 0}. That is why we shift by
   1031          * {@code pluggedType - 1} instead of by {@code pluggedType}.
   1032          * @param stayAwakeConditions a bit string specifying which "plugged types" should
   1033          * keep the device (and hence Wi-Fi) awake.
   1034          * @param pluggedType the type of plug (USB, AC, or none) for which the check is
   1035          * being made
   1036          * @return {@code true} if {@code pluggedType} indicates that the device is
   1037          * supposed to stay awake, {@code false} otherwise.
   1038          */
   1039         private boolean shouldDeviceStayAwake(int stayAwakeConditions, int pluggedType) {
   1040             return (stayAwakeConditions & pluggedType) != 0;
   1041         }
   1042     };
   1043 
   1044     private void setDeviceIdleAndUpdateWifi(boolean deviceIdle) {
   1045         mDeviceIdle = deviceIdle;
   1046         reportStartWorkSource();
   1047         updateWifiState();
   1048     }
   1049 
   1050     private synchronized void reportStartWorkSource() {
   1051         mTmpWorkSource.clear();
   1052         if (mDeviceIdle) {
   1053             for (int i=0; i<mLocks.mList.size(); i++) {
   1054                 mTmpWorkSource.add(mLocks.mList.get(i).mWorkSource);
   1055             }
   1056         }
   1057         mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource);
   1058     }
   1059 
   1060     private void updateWifiState() {
   1061         boolean lockHeld = mLocks.hasLocks();
   1062         int strongestLockMode = WifiManager.WIFI_MODE_FULL;
   1063         boolean wifiShouldBeStarted;
   1064 
   1065         if (mEmergencyCallbackMode) {
   1066             wifiShouldBeStarted = false;
   1067         } else {
   1068             wifiShouldBeStarted = !mDeviceIdle || lockHeld;
   1069         }
   1070 
   1071         if (lockHeld) {
   1072             strongestLockMode = mLocks.getStrongestLockMode();
   1073         }
   1074         /* If device is not idle, lockmode cannot be scan only */
   1075         if (!mDeviceIdle && strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY) {
   1076             strongestLockMode = WifiManager.WIFI_MODE_FULL;
   1077         }
   1078 
   1079         /* Disable tethering when airplane mode is enabled */
   1080         if (mAirplaneModeOn.get()) {
   1081             mWifiStateMachine.setWifiApEnabled(null, false);
   1082         }
   1083 
   1084         if (shouldWifiBeEnabled()) {
   1085             if (wifiShouldBeStarted) {
   1086                 reportStartWorkSource();
   1087                 mWifiStateMachine.setWifiEnabled(true);
   1088                 mWifiStateMachine.setScanOnlyMode(
   1089                         strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
   1090                 mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode);
   1091                 mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode
   1092                         == WifiManager.WIFI_MODE_FULL_HIGH_PERF);
   1093             } else {
   1094                 mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode);
   1095             }
   1096         } else {
   1097             mWifiStateMachine.setWifiEnabled(false);
   1098         }
   1099     }
   1100 
   1101     private void registerForBroadcasts() {
   1102         IntentFilter intentFilter = new IntentFilter();
   1103         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
   1104         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
   1105         intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
   1106         intentFilter.addAction(ACTION_DEVICE_IDLE);
   1107         intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
   1108         intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
   1109         mContext.registerReceiver(mReceiver, intentFilter);
   1110     }
   1111 
   1112     private boolean isAirplaneSensitive() {
   1113         String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
   1114                 Settings.System.AIRPLANE_MODE_RADIOS);
   1115         return airplaneModeRadios == null
   1116             || airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
   1117     }
   1118 
   1119     private boolean isAirplaneToggleable() {
   1120         String toggleableRadios = Settings.System.getString(mContext.getContentResolver(),
   1121                 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
   1122         return toggleableRadios != null
   1123             && toggleableRadios.contains(Settings.System.RADIO_WIFI);
   1124     }
   1125 
   1126     /**
   1127      * Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is
   1128      * currently on.
   1129      * @return {@code true} if airplane mode is on.
   1130      */
   1131     private boolean isAirplaneModeOn() {
   1132         return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(),
   1133                 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
   1134     }
   1135 
   1136     @Override
   1137     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1138         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
   1139                 != PackageManager.PERMISSION_GRANTED) {
   1140             pw.println("Permission Denial: can't dump WifiService from from pid="
   1141                     + Binder.getCallingPid()
   1142                     + ", uid=" + Binder.getCallingUid());
   1143             return;
   1144         }
   1145         pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
   1146         pw.println("Stay-awake conditions: " +
   1147                 Settings.System.getInt(mContext.getContentResolver(),
   1148                                        Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
   1149         pw.println();
   1150 
   1151         pw.println("Internal state:");
   1152         pw.println(mWifiStateMachine);
   1153         pw.println();
   1154         pw.println("Latest scan results:");
   1155         List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
   1156         if (scanResults != null && scanResults.size() != 0) {
   1157             pw.println("  BSSID              Frequency   RSSI  Flags             SSID");
   1158             for (ScanResult r : scanResults) {
   1159                 pw.printf("  %17s  %9d  %5d  %-16s  %s%n",
   1160                                          r.BSSID,
   1161                                          r.frequency,
   1162                                          r.level,
   1163                                          r.capabilities,
   1164                                          r.SSID == null ? "" : r.SSID);
   1165             }
   1166         }
   1167         pw.println();
   1168         pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
   1169                 mFullHighPerfLocksAcquired + " full high perf, " +
   1170                 mScanLocksAcquired + " scan");
   1171         pw.println("Locks released: " + mFullLocksReleased + " full, " +
   1172                 mFullHighPerfLocksReleased + " full high perf, " +
   1173                 mScanLocksReleased + " scan");
   1174         pw.println();
   1175         pw.println("Locks held:");
   1176         mLocks.dump(pw);
   1177 
   1178         pw.println();
   1179         pw.println("WifiWatchdogStateMachine dump");
   1180         mWifiWatchdogStateMachine.dump(pw);
   1181     }
   1182 
   1183     private class WifiLock extends DeathRecipient {
   1184         WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
   1185             super(lockMode, tag, binder, ws);
   1186         }
   1187 
   1188         public void binderDied() {
   1189             synchronized (mLocks) {
   1190                 releaseWifiLockLocked(mBinder);
   1191             }
   1192         }
   1193 
   1194         public String toString() {
   1195             return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
   1196         }
   1197     }
   1198 
   1199     private class LockList {
   1200         private List<WifiLock> mList;
   1201 
   1202         private LockList() {
   1203             mList = new ArrayList<WifiLock>();
   1204         }
   1205 
   1206         private synchronized boolean hasLocks() {
   1207             return !mList.isEmpty();
   1208         }
   1209 
   1210         private synchronized int getStrongestLockMode() {
   1211             if (mList.isEmpty()) {
   1212                 return WifiManager.WIFI_MODE_FULL;
   1213             }
   1214 
   1215             if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
   1216                 return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
   1217             }
   1218 
   1219             if (mFullLocksAcquired > mFullLocksReleased) {
   1220                 return WifiManager.WIFI_MODE_FULL;
   1221             }
   1222 
   1223             return WifiManager.WIFI_MODE_SCAN_ONLY;
   1224         }
   1225 
   1226         private void addLock(WifiLock lock) {
   1227             if (findLockByBinder(lock.mBinder) < 0) {
   1228                 mList.add(lock);
   1229             }
   1230         }
   1231 
   1232         private WifiLock removeLock(IBinder binder) {
   1233             int index = findLockByBinder(binder);
   1234             if (index >= 0) {
   1235                 WifiLock ret = mList.remove(index);
   1236                 ret.unlinkDeathRecipient();
   1237                 return ret;
   1238             } else {
   1239                 return null;
   1240             }
   1241         }
   1242 
   1243         private int findLockByBinder(IBinder binder) {
   1244             int size = mList.size();
   1245             for (int i = size - 1; i >= 0; i--)
   1246                 if (mList.get(i).mBinder == binder)
   1247                     return i;
   1248             return -1;
   1249         }
   1250 
   1251         private void dump(PrintWriter pw) {
   1252             for (WifiLock l : mList) {
   1253                 pw.print("    ");
   1254                 pw.println(l);
   1255             }
   1256         }
   1257     }
   1258 
   1259     void enforceWakeSourcePermission(int uid, int pid) {
   1260         if (uid == android.os.Process.myUid()) {
   1261             return;
   1262         }
   1263         mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
   1264                 pid, uid, null);
   1265     }
   1266 
   1267     public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
   1268         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
   1269         if (lockMode != WifiManager.WIFI_MODE_FULL &&
   1270                 lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
   1271                 lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
   1272             Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
   1273             if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
   1274             return false;
   1275         }
   1276         if (ws != null && ws.size() == 0) {
   1277             ws = null;
   1278         }
   1279         if (ws != null) {
   1280             enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
   1281         }
   1282         if (ws == null) {
   1283             ws = new WorkSource(Binder.getCallingUid());
   1284         }
   1285         WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
   1286         synchronized (mLocks) {
   1287             return acquireWifiLockLocked(wifiLock);
   1288         }
   1289     }
   1290 
   1291     private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
   1292         switch(wifiLock.mMode) {
   1293             case WifiManager.WIFI_MODE_FULL:
   1294             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
   1295                 mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
   1296                 break;
   1297             case WifiManager.WIFI_MODE_SCAN_ONLY:
   1298                 mBatteryStats.noteScanWifiLockAcquiredFromSource(wifiLock.mWorkSource);
   1299                 break;
   1300         }
   1301     }
   1302 
   1303     private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
   1304         switch(wifiLock.mMode) {
   1305             case WifiManager.WIFI_MODE_FULL:
   1306             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
   1307                 mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
   1308                 break;
   1309             case WifiManager.WIFI_MODE_SCAN_ONLY:
   1310                 mBatteryStats.noteScanWifiLockReleasedFromSource(wifiLock.mWorkSource);
   1311                 break;
   1312         }
   1313     }
   1314 
   1315     private boolean acquireWifiLockLocked(WifiLock wifiLock) {
   1316         if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
   1317 
   1318         mLocks.addLock(wifiLock);
   1319 
   1320         long ident = Binder.clearCallingIdentity();
   1321         try {
   1322             noteAcquireWifiLock(wifiLock);
   1323             switch(wifiLock.mMode) {
   1324             case WifiManager.WIFI_MODE_FULL:
   1325                 ++mFullLocksAcquired;
   1326                 break;
   1327             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
   1328                 ++mFullHighPerfLocksAcquired;
   1329                 break;
   1330 
   1331             case WifiManager.WIFI_MODE_SCAN_ONLY:
   1332                 ++mScanLocksAcquired;
   1333                 break;
   1334             }
   1335 
   1336             // Be aggressive about adding new locks into the accounted state...
   1337             // we want to over-report rather than under-report.
   1338             reportStartWorkSource();
   1339 
   1340             updateWifiState();
   1341             return true;
   1342         } catch (RemoteException e) {
   1343             return false;
   1344         } finally {
   1345             Binder.restoreCallingIdentity(ident);
   1346         }
   1347     }
   1348 
   1349     public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
   1350         int uid = Binder.getCallingUid();
   1351         int pid = Binder.getCallingPid();
   1352         if (ws != null && ws.size() == 0) {
   1353             ws = null;
   1354         }
   1355         if (ws != null) {
   1356             enforceWakeSourcePermission(uid, pid);
   1357         }
   1358         long ident = Binder.clearCallingIdentity();
   1359         try {
   1360             synchronized (mLocks) {
   1361                 int index = mLocks.findLockByBinder(lock);
   1362                 if (index < 0) {
   1363                     throw new IllegalArgumentException("Wifi lock not active");
   1364                 }
   1365                 WifiLock wl = mLocks.mList.get(index);
   1366                 noteReleaseWifiLock(wl);
   1367                 wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
   1368                 noteAcquireWifiLock(wl);
   1369             }
   1370         } catch (RemoteException e) {
   1371         } finally {
   1372             Binder.restoreCallingIdentity(ident);
   1373         }
   1374     }
   1375 
   1376     public boolean releaseWifiLock(IBinder lock) {
   1377         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
   1378         synchronized (mLocks) {
   1379             return releaseWifiLockLocked(lock);
   1380         }
   1381     }
   1382 
   1383     private boolean releaseWifiLockLocked(IBinder lock) {
   1384         boolean hadLock;
   1385 
   1386         WifiLock wifiLock = mLocks.removeLock(lock);
   1387 
   1388         if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
   1389 
   1390         hadLock = (wifiLock != null);
   1391 
   1392         long ident = Binder.clearCallingIdentity();
   1393         try {
   1394             if (hadLock) {
   1395                 noteReleaseWifiLock(wifiLock);
   1396                 switch(wifiLock.mMode) {
   1397                     case WifiManager.WIFI_MODE_FULL:
   1398                         ++mFullLocksReleased;
   1399                         break;
   1400                     case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
   1401                         ++mFullHighPerfLocksReleased;
   1402                         break;
   1403                     case WifiManager.WIFI_MODE_SCAN_ONLY:
   1404                         ++mScanLocksReleased;
   1405                         break;
   1406                 }
   1407             }
   1408 
   1409             // TODO - should this only happen if you hadLock?
   1410             updateWifiState();
   1411 
   1412         } catch (RemoteException e) {
   1413         } finally {
   1414             Binder.restoreCallingIdentity(ident);
   1415         }
   1416 
   1417         return hadLock;
   1418     }
   1419 
   1420     private abstract class DeathRecipient
   1421             implements IBinder.DeathRecipient {
   1422         String mTag;
   1423         int mMode;
   1424         IBinder mBinder;
   1425         WorkSource mWorkSource;
   1426 
   1427         DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) {
   1428             super();
   1429             mTag = tag;
   1430             mMode = mode;
   1431             mBinder = binder;
   1432             mWorkSource = ws;
   1433             try {
   1434                 mBinder.linkToDeath(this, 0);
   1435             } catch (RemoteException e) {
   1436                 binderDied();
   1437             }
   1438         }
   1439 
   1440         void unlinkDeathRecipient() {
   1441             mBinder.unlinkToDeath(this, 0);
   1442         }
   1443     }
   1444 
   1445     private class Multicaster extends DeathRecipient {
   1446         Multicaster(String tag, IBinder binder) {
   1447             super(Binder.getCallingUid(), tag, binder, null);
   1448         }
   1449 
   1450         public void binderDied() {
   1451             Slog.e(TAG, "Multicaster binderDied");
   1452             synchronized (mMulticasters) {
   1453                 int i = mMulticasters.indexOf(this);
   1454                 if (i != -1) {
   1455                     removeMulticasterLocked(i, mMode);
   1456                 }
   1457             }
   1458         }
   1459 
   1460         public String toString() {
   1461             return "Multicaster{" + mTag + " binder=" + mBinder + "}";
   1462         }
   1463 
   1464         public int getUid() {
   1465             return mMode;
   1466         }
   1467     }
   1468 
   1469     public void initializeMulticastFiltering() {
   1470         enforceMulticastChangePermission();
   1471 
   1472         synchronized (mMulticasters) {
   1473             // if anybody had requested filters be off, leave off
   1474             if (mMulticasters.size() != 0) {
   1475                 return;
   1476             } else {
   1477                 mWifiStateMachine.startFilteringMulticastV4Packets();
   1478             }
   1479         }
   1480     }
   1481 
   1482     public void acquireMulticastLock(IBinder binder, String tag) {
   1483         enforceMulticastChangePermission();
   1484 
   1485         synchronized (mMulticasters) {
   1486             mMulticastEnabled++;
   1487             mMulticasters.add(new Multicaster(tag, binder));
   1488             // Note that we could call stopFilteringMulticastV4Packets only when
   1489             // our new size == 1 (first call), but this function won't
   1490             // be called often and by making the stopPacket call each
   1491             // time we're less fragile and self-healing.
   1492             mWifiStateMachine.stopFilteringMulticastV4Packets();
   1493         }
   1494 
   1495         int uid = Binder.getCallingUid();
   1496         Long ident = Binder.clearCallingIdentity();
   1497         try {
   1498             mBatteryStats.noteWifiMulticastEnabled(uid);
   1499         } catch (RemoteException e) {
   1500         } finally {
   1501             Binder.restoreCallingIdentity(ident);
   1502         }
   1503     }
   1504 
   1505     public void releaseMulticastLock() {
   1506         enforceMulticastChangePermission();
   1507 
   1508         int uid = Binder.getCallingUid();
   1509         synchronized (mMulticasters) {
   1510             mMulticastDisabled++;
   1511             int size = mMulticasters.size();
   1512             for (int i = size - 1; i >= 0; i--) {
   1513                 Multicaster m = mMulticasters.get(i);
   1514                 if ((m != null) && (m.getUid() == uid)) {
   1515                     removeMulticasterLocked(i, uid);
   1516                 }
   1517             }
   1518         }
   1519     }
   1520 
   1521     private void removeMulticasterLocked(int i, int uid)
   1522     {
   1523         Multicaster removed = mMulticasters.remove(i);
   1524 
   1525         if (removed != null) {
   1526             removed.unlinkDeathRecipient();
   1527         }
   1528         if (mMulticasters.size() == 0) {
   1529             mWifiStateMachine.startFilteringMulticastV4Packets();
   1530         }
   1531 
   1532         Long ident = Binder.clearCallingIdentity();
   1533         try {
   1534             mBatteryStats.noteWifiMulticastDisabled(uid);
   1535         } catch (RemoteException e) {
   1536         } finally {
   1537             Binder.restoreCallingIdentity(ident);
   1538         }
   1539     }
   1540 
   1541     public boolean isMulticastEnabled() {
   1542         enforceAccessPermission();
   1543 
   1544         synchronized (mMulticasters) {
   1545             return (mMulticasters.size() > 0);
   1546         }
   1547     }
   1548 
   1549     /**
   1550      * Evaluate if traffic stats polling is needed based on
   1551      * connection and screen on status
   1552      */
   1553     private void evaluateTrafficStatsPolling() {
   1554         Message msg;
   1555         if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED && !mScreenOff) {
   1556             msg = Message.obtain(mAsyncServiceHandler,
   1557                     WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL, 1, 0);
   1558         } else {
   1559             msg = Message.obtain(mAsyncServiceHandler,
   1560                     WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL, 0, 0);
   1561         }
   1562         msg.sendToTarget();
   1563     }
   1564 
   1565     private void notifyOnDataActivity() {
   1566         long sent, received;
   1567         long preTxPkts = mTxPkts, preRxPkts = mRxPkts;
   1568         int dataActivity = WifiManager.DATA_ACTIVITY_NONE;
   1569 
   1570         mTxPkts = TrafficStats.getTxPackets(mInterfaceName);
   1571         mRxPkts = TrafficStats.getRxPackets(mInterfaceName);
   1572 
   1573         if (preTxPkts > 0 || preRxPkts > 0) {
   1574             sent = mTxPkts - preTxPkts;
   1575             received = mRxPkts - preRxPkts;
   1576             if (sent > 0) {
   1577                 dataActivity |= WifiManager.DATA_ACTIVITY_OUT;
   1578             }
   1579             if (received > 0) {
   1580                 dataActivity |= WifiManager.DATA_ACTIVITY_IN;
   1581             }
   1582 
   1583             if (dataActivity != mDataActivity && !mScreenOff) {
   1584                 mDataActivity = dataActivity;
   1585                 for (AsyncChannel client : mClients) {
   1586                     client.sendMessage(WifiManager.DATA_ACTIVITY_NOTIFICATION, mDataActivity);
   1587                 }
   1588             }
   1589         }
   1590     }
   1591 
   1592 
   1593     private void checkAndSetNotification() {
   1594         // If we shouldn't place a notification on available networks, then
   1595         // don't bother doing any of the following
   1596         if (!mNotificationEnabled) return;
   1597 
   1598         State state = mNetworkInfo.getState();
   1599         if ((state == NetworkInfo.State.DISCONNECTED)
   1600                 || (state == NetworkInfo.State.UNKNOWN)) {
   1601             // Look for an open network
   1602             List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
   1603             if (scanResults != null) {
   1604                 int numOpenNetworks = 0;
   1605                 for (int i = scanResults.size() - 1; i >= 0; i--) {
   1606                     ScanResult scanResult = scanResults.get(i);
   1607 
   1608                     //A capability of [ESS] represents an open access point
   1609                     //that is available for an STA to connect
   1610                     if (scanResult.capabilities != null &&
   1611                             scanResult.capabilities.equals("[ESS]")) {
   1612                         numOpenNetworks++;
   1613                     }
   1614                 }
   1615 
   1616                 if (numOpenNetworks > 0) {
   1617                     if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
   1618                         /*
   1619                          * We've scanned continuously at least
   1620                          * NUM_SCANS_BEFORE_NOTIFICATION times. The user
   1621                          * probably does not have a remembered network in range,
   1622                          * since otherwise supplicant would have tried to
   1623                          * associate and thus resetting this counter.
   1624                          */
   1625                         setNotificationVisible(true, numOpenNetworks, false, 0);
   1626                     }
   1627                     return;
   1628                 }
   1629             }
   1630         }
   1631 
   1632         // No open networks in range, remove the notification
   1633         setNotificationVisible(false, 0, false, 0);
   1634     }
   1635 
   1636     /**
   1637      * Clears variables related to tracking whether a notification has been
   1638      * shown recently and clears the current notification.
   1639      */
   1640     private void resetNotification() {
   1641         mNotificationRepeatTime = 0;
   1642         mNumScansSinceNetworkStateChange = 0;
   1643         setNotificationVisible(false, 0, false, 0);
   1644     }
   1645 
   1646     /**
   1647      * Display or don't display a notification that there are open Wi-Fi networks.
   1648      * @param visible {@code true} if notification should be visible, {@code false} otherwise
   1649      * @param numNetworks the number networks seen
   1650      * @param force {@code true} to force notification to be shown/not-shown,
   1651      * even if it is already shown/not-shown.
   1652      * @param delay time in milliseconds after which the notification should be made
   1653      * visible or invisible.
   1654      */
   1655     private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
   1656             int delay) {
   1657 
   1658         // Since we use auto cancel on the notification, when the
   1659         // mNetworksAvailableNotificationShown is true, the notification may
   1660         // have actually been canceled.  However, when it is false we know
   1661         // for sure that it is not being shown (it will not be shown any other
   1662         // place than here)
   1663 
   1664         // If it should be hidden and it is already hidden, then noop
   1665         if (!visible && !mNotificationShown && !force) {
   1666             return;
   1667         }
   1668 
   1669         NotificationManager notificationManager = (NotificationManager) mContext
   1670                 .getSystemService(Context.NOTIFICATION_SERVICE);
   1671 
   1672         Message message;
   1673         if (visible) {
   1674 
   1675             // Not enough time has passed to show the notification again
   1676             if (System.currentTimeMillis() < mNotificationRepeatTime) {
   1677                 return;
   1678             }
   1679 
   1680             if (mNotification == null) {
   1681                 // Cache the Notification object.
   1682                 mNotification = new Notification();
   1683                 mNotification.when = 0;
   1684                 mNotification.icon = ICON_NETWORKS_AVAILABLE;
   1685                 mNotification.flags = Notification.FLAG_AUTO_CANCEL;
   1686                 mNotification.contentIntent = PendingIntent.getActivity(mContext, 0,
   1687                         new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK), 0);
   1688             }
   1689 
   1690             CharSequence title = mContext.getResources().getQuantityText(
   1691                     com.android.internal.R.plurals.wifi_available, numNetworks);
   1692             CharSequence details = mContext.getResources().getQuantityText(
   1693                     com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
   1694             mNotification.tickerText = title;
   1695             mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
   1696 
   1697             mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
   1698 
   1699             notificationManager.notify(ICON_NETWORKS_AVAILABLE, mNotification);
   1700         } else {
   1701             notificationManager.cancel(ICON_NETWORKS_AVAILABLE);
   1702         }
   1703 
   1704         mNotificationShown = visible;
   1705     }
   1706 
   1707     private class NotificationEnabledSettingObserver extends ContentObserver {
   1708 
   1709         public NotificationEnabledSettingObserver(Handler handler) {
   1710             super(handler);
   1711         }
   1712 
   1713         public void register() {
   1714             ContentResolver cr = mContext.getContentResolver();
   1715             cr.registerContentObserver(Settings.Secure.getUriFor(
   1716                 Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
   1717             mNotificationEnabled = getValue();
   1718         }
   1719 
   1720         @Override
   1721         public void onChange(boolean selfChange) {
   1722             super.onChange(selfChange);
   1723 
   1724             mNotificationEnabled = getValue();
   1725             resetNotification();
   1726         }
   1727 
   1728         private boolean getValue() {
   1729             return Settings.Secure.getInt(mContext.getContentResolver(),
   1730                     Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
   1731         }
   1732     }
   1733 
   1734 
   1735 }
   1736