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