Home | History | Annotate | Download | only in wifi
      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.wifi;
     18 
     19 import android.app.ActivityManager;
     20 import android.app.AppOpsManager;
     21 import android.bluetooth.BluetoothAdapter;
     22 import android.content.BroadcastReceiver;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.IntentFilter;
     26 import android.content.pm.PackageManager;
     27 import android.content.pm.UserInfo;
     28 import android.database.ContentObserver;
     29 import android.net.ConnectivityManager;
     30 import android.net.DhcpInfo;
     31 import android.net.DhcpResults;
     32 import android.net.IpConfiguration.ProxySettings;
     33 import android.net.LinkAddress;
     34 import android.net.NetworkUtils;
     35 import android.net.RouteInfo;
     36 import android.net.wifi.*;
     37 import android.net.wifi.IWifiManager;
     38 import android.os.AsyncTask;
     39 import android.os.Binder;
     40 import android.os.Handler;
     41 import android.os.HandlerThread;
     42 import android.os.IBinder;
     43 import android.os.Message;
     44 import android.os.Messenger;
     45 import android.os.RemoteException;
     46 import android.os.SystemProperties;
     47 import android.os.UserHandle;
     48 import android.os.UserManager;
     49 import android.os.WorkSource;
     50 import android.provider.Settings;
     51 import android.util.Log;
     52 import android.util.Slog;
     53 
     54 import java.io.FileNotFoundException;
     55 import java.io.BufferedReader;
     56 import java.io.FileDescriptor;
     57 import java.io.FileReader;
     58 import java.io.IOException;
     59 import java.io.PrintWriter;
     60 import java.lang.Override;
     61 import java.net.InetAddress;
     62 import java.net.Inet4Address;
     63 import java.util.ArrayList;
     64 import java.util.List;
     65 
     66 import com.android.internal.R;
     67 import com.android.internal.app.IBatteryStats;
     68 import com.android.internal.telephony.TelephonyIntents;
     69 import com.android.internal.util.AsyncChannel;
     70 import com.android.server.am.BatteryStatsService;
     71 
     72 import static com.android.server.wifi.WifiController.CMD_AIRPLANE_TOGGLED;
     73 import static com.android.server.wifi.WifiController.CMD_BATTERY_CHANGED;
     74 import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED;
     75 import static com.android.server.wifi.WifiController.CMD_LOCKS_CHANGED;
     76 import static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED;
     77 import static com.android.server.wifi.WifiController.CMD_SCREEN_OFF;
     78 import static com.android.server.wifi.WifiController.CMD_SCREEN_ON;
     79 import static com.android.server.wifi.WifiController.CMD_SET_AP;
     80 import static com.android.server.wifi.WifiController.CMD_USER_PRESENT;
     81 import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED;
     82 /**
     83  * WifiService handles remote WiFi operation requests by implementing
     84  * the IWifiManager interface.
     85  *
     86  * @hide
     87  */
     88 public final class WifiServiceImpl extends IWifiManager.Stub {
     89     private static final String TAG = "WifiService";
     90     private static final boolean DBG = true;
     91 
     92     final WifiStateMachine mWifiStateMachine;
     93 
     94     private final Context mContext;
     95 
     96     final LockList mLocks = new LockList();
     97     // some wifi lock statistics
     98     private int mFullHighPerfLocksAcquired;
     99     private int mFullHighPerfLocksReleased;
    100     private int mFullLocksAcquired;
    101     private int mFullLocksReleased;
    102     private int mScanLocksAcquired;
    103     private int mScanLocksReleased;
    104 
    105     private final List<Multicaster> mMulticasters =
    106             new ArrayList<Multicaster>();
    107     private int mMulticastEnabled;
    108     private int mMulticastDisabled;
    109 
    110     private final IBatteryStats mBatteryStats;
    111     private final AppOpsManager mAppOps;
    112 
    113     private String mInterfaceName;
    114 
    115     // Debug counter tracking scan requests sent by WifiManager
    116     private int scanRequestCounter = 0;
    117 
    118     /* Tracks the open wi-fi network notification */
    119     private WifiNotificationController mNotificationController;
    120     /* Polls traffic stats and notifies clients */
    121     private WifiTrafficPoller mTrafficPoller;
    122     /* Tracks the persisted states for wi-fi & airplane mode */
    123     final WifiSettingsStore mSettingsStore;
    124 
    125     final boolean mBatchedScanSupported;
    126 
    127     /**
    128      * Asynchronous channel to WifiStateMachine
    129      */
    130     private AsyncChannel mWifiStateMachineChannel;
    131 
    132     /**
    133      * Handles client connections
    134      */
    135     private class ClientHandler extends Handler {
    136 
    137         ClientHandler(android.os.Looper looper) {
    138             super(looper);
    139         }
    140 
    141         @Override
    142         public void handleMessage(Message msg) {
    143             switch (msg.what) {
    144                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
    145                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
    146                         if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
    147                         // We track the clients by the Messenger
    148                         // since it is expected to be always available
    149                         mTrafficPoller.addClient(msg.replyTo);
    150                     } else {
    151                         Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
    152                     }
    153                     break;
    154                 }
    155                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
    156                     if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
    157                         if (DBG) Slog.d(TAG, "Send failed, client connection lost");
    158                     } else {
    159                         if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
    160                     }
    161                     mTrafficPoller.removeClient(msg.replyTo);
    162                     break;
    163                 }
    164                 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
    165                     AsyncChannel ac = new AsyncChannel();
    166                     ac.connect(mContext, this, msg.replyTo);
    167                     break;
    168                 }
    169                 /* Client commands are forwarded to state machine */
    170                 case WifiManager.CONNECT_NETWORK:
    171                 case WifiManager.SAVE_NETWORK: {
    172                     WifiConfiguration config = (WifiConfiguration) msg.obj;
    173                     int networkId = msg.arg1;
    174                     if (msg.what == WifiManager.SAVE_NETWORK) {
    175                         if (config != null) {
    176                             if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
    177                                 config.creatorUid = Binder.getCallingUid();
    178                             } else {
    179                                 config.lastUpdateUid = Binder.getCallingUid();
    180                             }
    181                         }
    182                         Slog.e("WiFiServiceImpl ", "SAVE"
    183                                 + " nid=" + Integer.toString(networkId)
    184                                 + " uid=" + Integer.toString(config.creatorUid)
    185                                 + "/" + Integer.toString(config.lastUpdateUid));
    186                     }
    187                     if (msg.what == WifiManager.CONNECT_NETWORK) {
    188                         if (config != null) {
    189                             if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
    190                                 config.creatorUid = Binder.getCallingUid();
    191                             } else {
    192                                 config.lastUpdateUid = Binder.getCallingUid();
    193                             }
    194                         }
    195                         Slog.e("WiFiServiceImpl ", "CONNECT "
    196                                 + " nid=" + Integer.toString(networkId)
    197                                 + " uid=" + Binder.getCallingUid());
    198                     }
    199                     if (config != null && config.isValid()) {
    200                         if (DBG) Slog.d(TAG, "Connect with config" + config);
    201                         mWifiStateMachine.sendMessage(Message.obtain(msg));
    202                     } else if (config == null
    203                             && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
    204                         if (DBG) Slog.d(TAG, "Connect with networkId" + networkId);
    205                         mWifiStateMachine.sendMessage(Message.obtain(msg));
    206                     } else {
    207                         Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
    208                         if (msg.what == WifiManager.CONNECT_NETWORK) {
    209                             replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED,
    210                                     WifiManager.INVALID_ARGS);
    211                         } else {
    212                             replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED,
    213                                     WifiManager.INVALID_ARGS);
    214                         }
    215                     }
    216                     break;
    217                 }
    218                 case WifiManager.FORGET_NETWORK:
    219                     if (isOwner(msg.sendingUid)) {
    220                         mWifiStateMachine.sendMessage(Message.obtain(msg));
    221                     } else {
    222                         Slog.e(TAG, "Forget is not authorized for user");
    223                         replyFailed(msg, WifiManager.FORGET_NETWORK_FAILED,
    224                                 WifiManager.NOT_AUTHORIZED);
    225                     }
    226                     break;
    227                 case WifiManager.START_WPS:
    228                 case WifiManager.CANCEL_WPS:
    229                 case WifiManager.DISABLE_NETWORK:
    230                 case WifiManager.RSSI_PKTCNT_FETCH: {
    231                     mWifiStateMachine.sendMessage(Message.obtain(msg));
    232                     break;
    233                 }
    234                 default: {
    235                     Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg);
    236                     break;
    237                 }
    238             }
    239         }
    240 
    241         private void replyFailed(Message msg, int what, int why) {
    242             Message reply = msg.obtain();
    243             reply.what = what;
    244             reply.arg1 = why;
    245             try {
    246                 msg.replyTo.send(reply);
    247             } catch (RemoteException e) {
    248                 // There's not much we can do if reply can't be sent!
    249             }
    250         }
    251     }
    252     private ClientHandler mClientHandler;
    253 
    254     /**
    255      * Handles interaction with WifiStateMachine
    256      */
    257     private class WifiStateMachineHandler extends Handler {
    258         private AsyncChannel mWsmChannel;
    259 
    260         WifiStateMachineHandler(android.os.Looper looper) {
    261             super(looper);
    262             mWsmChannel = new AsyncChannel();
    263             mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
    264         }
    265 
    266         @Override
    267         public void handleMessage(Message msg) {
    268             switch (msg.what) {
    269                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
    270                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
    271                         mWifiStateMachineChannel = mWsmChannel;
    272                     } else {
    273                         Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1);
    274                         mWifiStateMachineChannel = null;
    275                     }
    276                     break;
    277                 }
    278                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
    279                     Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1);
    280                     mWifiStateMachineChannel = null;
    281                     //Re-establish connection to state machine
    282                     mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
    283                     break;
    284                 }
    285                 default: {
    286                     Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg);
    287                     break;
    288                 }
    289             }
    290         }
    291     }
    292 
    293     WifiStateMachineHandler mWifiStateMachineHandler;
    294 
    295     private WifiWatchdogStateMachine mWifiWatchdogStateMachine;
    296 
    297     private WifiController mWifiController;
    298 
    299     public WifiServiceImpl(Context context) {
    300         mContext = context;
    301 
    302         mInterfaceName =  SystemProperties.get("wifi.interface", "wlan0");
    303 
    304         mTrafficPoller = new WifiTrafficPoller(mContext, mInterfaceName);
    305         mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName, mTrafficPoller);
    306         mWifiStateMachine.enableRssiPolling(true);
    307         mBatteryStats = BatteryStatsService.getService();
    308         mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
    309 
    310         mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine);
    311         mSettingsStore = new WifiSettingsStore(mContext);
    312 
    313         HandlerThread wifiThread = new HandlerThread("WifiService");
    314         wifiThread.start();
    315         mClientHandler = new ClientHandler(wifiThread.getLooper());
    316         mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
    317         mWifiController = new WifiController(mContext, this, wifiThread.getLooper());
    318 
    319         mBatchedScanSupported = mContext.getResources().getBoolean(
    320                 R.bool.config_wifi_batched_scan_supported);
    321     }
    322 
    323 
    324     /**
    325      * Check if Wi-Fi needs to be enabled and start
    326      * if needed
    327      *
    328      * This function is used only at boot time
    329      */
    330     public void checkAndStartWifi() {
    331         /* Check if wi-fi needs to be enabled */
    332         boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled();
    333         Slog.i(TAG, "WifiService starting up with Wi-Fi " +
    334                 (wifiEnabled ? "enabled" : "disabled"));
    335 
    336         registerForScanModeChange();
    337         mContext.registerReceiver(
    338                 new BroadcastReceiver() {
    339                     @Override
    340                     public void onReceive(Context context, Intent intent) {
    341                         if (mSettingsStore.handleAirplaneModeToggled()) {
    342                             mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED);
    343                         }
    344                     }
    345                 },
    346                 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
    347 
    348         // Adding optimizations of only receiving broadcasts when wifi is enabled
    349         // can result in race conditions when apps toggle wifi in the background
    350         // without active user involvement. Always receive broadcasts.
    351         registerForBroadcasts();
    352 
    353         mWifiController.start();
    354 
    355         // If we are already disabled (could be due to airplane mode), avoid changing persist
    356         // state here
    357         if (wifiEnabled) setWifiEnabled(wifiEnabled);
    358 
    359         mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
    360                makeWifiWatchdogStateMachine(mContext, mWifiStateMachine.getMessenger());
    361     }
    362 
    363     /**
    364      * see {@link android.net.wifi.WifiManager#pingSupplicant()}
    365      * @return {@code true} if the operation succeeds, {@code false} otherwise
    366      */
    367     public boolean pingSupplicant() {
    368         enforceAccessPermission();
    369         if (mWifiStateMachineChannel != null) {
    370             return mWifiStateMachine.syncPingSupplicant(mWifiStateMachineChannel);
    371         } else {
    372             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    373             return false;
    374         }
    375     }
    376 
    377     /**
    378      * see {@link android.net.wifi.WifiManager#getChannelList}
    379      */
    380     public List<WifiChannel> getChannelList() {
    381         enforceAccessPermission();
    382         if (mWifiStateMachineChannel != null) {
    383             return mWifiStateMachine.syncGetChannelList(mWifiStateMachineChannel);
    384         } else {
    385             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    386             return null;
    387         }
    388     }
    389 
    390     /**
    391      * see {@link android.net.wifi.WifiManager#startScan}
    392      * and {@link android.net.wifi.WifiManager#startCustomizedScan}
    393      *
    394      * @param settings If null, use default parameter, i.e. full scan.
    395      * @param workSource If null, all blame is given to the calling uid.
    396      */
    397     public void startScan(ScanSettings settings, WorkSource workSource) {
    398         enforceChangePermission();
    399         if (settings != null) {
    400             // TODO: should be removed once the startCustomizedScan API is opened up
    401             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.LOCATION_HARDWARE,
    402                     "LocationHardware");
    403             settings = new ScanSettings(settings);
    404             if (!settings.isValid()) {
    405                 Slog.e(TAG, "invalid scan setting");
    406                 return;
    407             }
    408         }
    409         if (workSource != null) {
    410             enforceWorkSourcePermission();
    411             // WifiManager currently doesn't use names, so need to clear names out of the
    412             // supplied WorkSource to allow future WorkSource combining.
    413             workSource.clearNames();
    414         }
    415         mWifiStateMachine.startScan(Binder.getCallingUid(), scanRequestCounter++,
    416                 settings, workSource);
    417     }
    418 
    419     private class BatchedScanRequest extends DeathRecipient {
    420         final BatchedScanSettings settings;
    421         final int uid;
    422         final int pid;
    423         final WorkSource workSource;
    424 
    425         BatchedScanRequest(BatchedScanSettings settings, IBinder binder, WorkSource ws) {
    426             super(0, null, binder, null);
    427             this.settings = settings;
    428             this.uid = getCallingUid();
    429             this.pid = getCallingPid();
    430             workSource = ws;
    431         }
    432         public void binderDied() {
    433             stopBatchedScan(settings, uid, pid);
    434         }
    435         public String toString() {
    436             return "BatchedScanRequest{settings=" + settings + ", binder=" + mBinder + "}";
    437         }
    438 
    439         public boolean isSameApp(int uid, int pid) {
    440             return (this.uid == uid && this.pid == pid);
    441         }
    442     }
    443 
    444     private final List<BatchedScanRequest> mBatchedScanners = new ArrayList<BatchedScanRequest>();
    445 
    446     public boolean isBatchedScanSupported() {
    447         return mBatchedScanSupported;
    448     }
    449 
    450     public void pollBatchedScan() {
    451         enforceChangePermission();
    452         if (mBatchedScanSupported == false) return;
    453         mWifiStateMachine.requestBatchedScanPoll();
    454     }
    455 
    456     public String getWpsNfcConfigurationToken(int netId) {
    457         enforceConnectivityInternalPermission();
    458         return mWifiStateMachine.syncGetWpsNfcConfigurationToken(netId);
    459     }
    460 
    461     /**
    462      * see {@link android.net.wifi.WifiManager#requestBatchedScan()}
    463      */
    464     public boolean requestBatchedScan(BatchedScanSettings requested, IBinder binder,
    465             WorkSource workSource) {
    466         enforceChangePermission();
    467         if (workSource != null) {
    468             enforceWorkSourcePermission();
    469             // WifiManager currently doesn't use names, so need to clear names out of the
    470             // supplied WorkSource to allow future WorkSource combining.
    471             workSource.clearNames();
    472         }
    473         if (mBatchedScanSupported == false) return false;
    474         requested = new BatchedScanSettings(requested);
    475         if (requested.isInvalid()) return false;
    476         BatchedScanRequest r = new BatchedScanRequest(requested, binder, workSource);
    477         synchronized(mBatchedScanners) {
    478             mBatchedScanners.add(r);
    479             resolveBatchedScannersLocked();
    480         }
    481         return true;
    482     }
    483 
    484     public List<BatchedScanResult> getBatchedScanResults(String callingPackage) {
    485         enforceAccessPermission();
    486         if (mBatchedScanSupported == false) return new ArrayList<BatchedScanResult>();
    487         int uid = Binder.getCallingUid();
    488         int userId = UserHandle.getCallingUserId();
    489         long ident = Binder.clearCallingIdentity();
    490         try {
    491             if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
    492                     != AppOpsManager.MODE_ALLOWED) {
    493                 return new ArrayList<BatchedScanResult>();
    494             }
    495             if (!isCurrentProfile(userId)) {
    496                 return new ArrayList<BatchedScanResult>();
    497             }
    498             return mWifiStateMachine.syncGetBatchedScanResultsList();
    499         } finally {
    500             Binder.restoreCallingIdentity(ident);
    501         }
    502     }
    503 
    504     public void stopBatchedScan(BatchedScanSettings settings) {
    505         enforceChangePermission();
    506         if (mBatchedScanSupported == false) return;
    507         stopBatchedScan(settings, getCallingUid(), getCallingPid());
    508     }
    509 
    510     private void stopBatchedScan(BatchedScanSettings settings, int uid, int pid) {
    511         ArrayList<BatchedScanRequest> found = new ArrayList<BatchedScanRequest>();
    512         synchronized(mBatchedScanners) {
    513             for (BatchedScanRequest r : mBatchedScanners) {
    514                 if (r.isSameApp(uid, pid) && (settings == null || settings.equals(r.settings))) {
    515                     found.add(r);
    516                     if (settings != null) break;
    517                 }
    518             }
    519             for (BatchedScanRequest r : found) {
    520                 mBatchedScanners.remove(r);
    521             }
    522             if (found.size() != 0) {
    523                 resolveBatchedScannersLocked();
    524             }
    525         }
    526     }
    527 
    528     private void resolveBatchedScannersLocked() {
    529         BatchedScanSettings setting = new BatchedScanSettings();
    530         WorkSource responsibleWorkSource = null;
    531         int responsibleUid = 0;
    532         double responsibleCsph = 0; // Channel Scans Per Hour
    533 
    534         if (mBatchedScanners.size() == 0) {
    535             mWifiStateMachine.setBatchedScanSettings(null, 0, 0, null);
    536             return;
    537         }
    538         for (BatchedScanRequest r : mBatchedScanners) {
    539             BatchedScanSettings s = r.settings;
    540 
    541             // evaluate responsibility
    542             int currentChannelCount;
    543             int currentScanInterval;
    544             double currentCsph;
    545 
    546             if (s.channelSet == null || s.channelSet.isEmpty()) {
    547                 // all channels - 11 B and 9 A channels roughly.
    548                 currentChannelCount = 9 + 11;
    549             } else {
    550                 currentChannelCount = s.channelSet.size();
    551                 // these are rough est - no real need to correct for reg-domain;
    552                 if (s.channelSet.contains("A")) currentChannelCount += (9 - 1);
    553                 if (s.channelSet.contains("B")) currentChannelCount += (11 - 1);
    554 
    555             }
    556             if (s.scanIntervalSec == BatchedScanSettings.UNSPECIFIED) {
    557                 currentScanInterval = BatchedScanSettings.DEFAULT_INTERVAL_SEC;
    558             } else {
    559                 currentScanInterval = s.scanIntervalSec;
    560             }
    561             currentCsph = 60 * 60 * currentChannelCount / currentScanInterval;
    562 
    563             if (currentCsph > responsibleCsph) {
    564                 responsibleUid = r.uid;
    565                 responsibleWorkSource = r.workSource;
    566                 responsibleCsph = currentCsph;
    567             }
    568 
    569             if (s.maxScansPerBatch != BatchedScanSettings.UNSPECIFIED &&
    570                     s.maxScansPerBatch < setting.maxScansPerBatch) {
    571                 setting.maxScansPerBatch = s.maxScansPerBatch;
    572             }
    573             if (s.maxApPerScan != BatchedScanSettings.UNSPECIFIED &&
    574                     (setting.maxApPerScan == BatchedScanSettings.UNSPECIFIED ||
    575                     s.maxApPerScan > setting.maxApPerScan)) {
    576                 setting.maxApPerScan = s.maxApPerScan;
    577             }
    578             if (s.scanIntervalSec != BatchedScanSettings.UNSPECIFIED &&
    579                     s.scanIntervalSec < setting.scanIntervalSec) {
    580                 setting.scanIntervalSec = s.scanIntervalSec;
    581             }
    582             if (s.maxApForDistance != BatchedScanSettings.UNSPECIFIED &&
    583                     (setting.maxApForDistance == BatchedScanSettings.UNSPECIFIED ||
    584                     s.maxApForDistance > setting.maxApForDistance)) {
    585                 setting.maxApForDistance = s.maxApForDistance;
    586             }
    587             if (s.channelSet != null && s.channelSet.size() != 0) {
    588                 if (setting.channelSet == null || setting.channelSet.size() != 0) {
    589                     if (setting.channelSet == null) setting.channelSet = new ArrayList<String>();
    590                     for (String i : s.channelSet) {
    591                         if (setting.channelSet.contains(i) == false) setting.channelSet.add(i);
    592                     }
    593                 } // else, ignore the constraint - we already use all channels
    594             } else {
    595                 if (setting.channelSet == null || setting.channelSet.size() != 0) {
    596                     setting.channelSet = new ArrayList<String>();
    597                 }
    598             }
    599         }
    600 
    601         setting.constrain();
    602         mWifiStateMachine.setBatchedScanSettings(setting, responsibleUid, (int)responsibleCsph,
    603                 responsibleWorkSource);
    604     }
    605 
    606     private void enforceAccessPermission() {
    607         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
    608                 "WifiService");
    609     }
    610 
    611     private void enforceChangePermission() {
    612         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
    613                                                 "WifiService");
    614 
    615     }
    616 
    617     private void enforceReadCredentialPermission() {
    618         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL,
    619                                                 "WifiService");
    620     }
    621 
    622     private void enforceWorkSourcePermission() {
    623         mContext.enforceCallingPermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
    624                 "WifiService");
    625 
    626     }
    627 
    628     private void enforceMulticastChangePermission() {
    629         mContext.enforceCallingOrSelfPermission(
    630                 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
    631                 "WifiService");
    632     }
    633 
    634     private void enforceConnectivityInternalPermission() {
    635         mContext.enforceCallingOrSelfPermission(
    636                 android.Manifest.permission.CONNECTIVITY_INTERNAL,
    637                 "ConnectivityService");
    638     }
    639 
    640     /**
    641      * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
    642      * @param enable {@code true} to enable, {@code false} to disable.
    643      * @return {@code true} if the enable/disable operation was
    644      *         started or is already in the queue.
    645      */
    646     public synchronized boolean setWifiEnabled(boolean enable) {
    647         enforceChangePermission();
    648         Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
    649                     + ", uid=" + Binder.getCallingUid());
    650         if (DBG) {
    651             Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
    652         }
    653 
    654         /*
    655         * Caller might not have WRITE_SECURE_SETTINGS,
    656         * only CHANGE_WIFI_STATE is enforced
    657         */
    658 
    659         long ident = Binder.clearCallingIdentity();
    660         try {
    661             if (! mSettingsStore.handleWifiToggled(enable)) {
    662                 // Nothing to do if wifi cannot be toggled
    663                 return true;
    664             }
    665         } finally {
    666             Binder.restoreCallingIdentity(ident);
    667         }
    668 
    669         mWifiController.sendMessage(CMD_WIFI_TOGGLED);
    670         return true;
    671     }
    672 
    673     /**
    674      * see {@link WifiManager#getWifiState()}
    675      * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
    676      *         {@link WifiManager#WIFI_STATE_DISABLING},
    677      *         {@link WifiManager#WIFI_STATE_ENABLED},
    678      *         {@link WifiManager#WIFI_STATE_ENABLING},
    679      *         {@link WifiManager#WIFI_STATE_UNKNOWN}
    680      */
    681     public int getWifiEnabledState() {
    682         enforceAccessPermission();
    683         return mWifiStateMachine.syncGetWifiState();
    684     }
    685 
    686     /**
    687      * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
    688      * @param wifiConfig SSID, security and channel details as
    689      *        part of WifiConfiguration
    690      * @param enabled true to enable and false to disable
    691      */
    692     public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
    693         enforceChangePermission();
    694         ConnectivityManager.enforceTetherChangePermission(mContext);
    695         UserManager um = UserManager.get(mContext);
    696         if (um.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
    697             throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user.");
    698         }
    699         // null wifiConfig is a meaningful input for CMD_SET_AP
    700         if (wifiConfig == null || wifiConfig.isValid()) {
    701             mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
    702         } else {
    703             Slog.e(TAG, "Invalid WifiConfiguration");
    704         }
    705     }
    706 
    707     /**
    708      * see {@link WifiManager#getWifiApState()}
    709      * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
    710      *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
    711      *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
    712      *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
    713      *         {@link WifiManager#WIFI_AP_STATE_FAILED}
    714      */
    715     public int getWifiApEnabledState() {
    716         enforceAccessPermission();
    717         return mWifiStateMachine.syncGetWifiApState();
    718     }
    719 
    720     /**
    721      * see {@link WifiManager#getWifiApConfiguration()}
    722      * @return soft access point configuration
    723      */
    724     public WifiConfiguration getWifiApConfiguration() {
    725         enforceAccessPermission();
    726         return mWifiStateMachine.syncGetWifiApConfiguration();
    727     }
    728 
    729     /**
    730      * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
    731      * @param wifiConfig WifiConfiguration details for soft access point
    732      */
    733     public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
    734         enforceChangePermission();
    735         if (wifiConfig == null)
    736             return;
    737         if (wifiConfig.isValid()) {
    738             mWifiStateMachine.setWifiApConfiguration(wifiConfig);
    739         } else {
    740             Slog.e(TAG, "Invalid WifiConfiguration");
    741         }
    742     }
    743 
    744     /**
    745      * @param enable {@code true} to enable, {@code false} to disable.
    746      * @return {@code true} if the enable/disable operation was
    747      *         started or is already in the queue.
    748      */
    749     public boolean isScanAlwaysAvailable() {
    750         enforceAccessPermission();
    751         return mSettingsStore.isScanAlwaysAvailable();
    752     }
    753 
    754     /**
    755      * see {@link android.net.wifi.WifiManager#disconnect()}
    756      */
    757     public void disconnect() {
    758         enforceChangePermission();
    759         mWifiStateMachine.disconnectCommand();
    760     }
    761 
    762     /**
    763      * see {@link android.net.wifi.WifiManager#reconnect()}
    764      */
    765     public void reconnect() {
    766         enforceChangePermission();
    767         mWifiStateMachine.reconnectCommand();
    768     }
    769 
    770     /**
    771      * see {@link android.net.wifi.WifiManager#reassociate()}
    772      */
    773     public void reassociate() {
    774         enforceChangePermission();
    775         mWifiStateMachine.reassociateCommand();
    776     }
    777 
    778     /**
    779      * see {@link android.net.wifi.WifiManager#getSupportedFeatures}
    780      */
    781     public int getSupportedFeatures() {
    782         enforceAccessPermission();
    783         if (mWifiStateMachineChannel != null) {
    784             return mWifiStateMachine.syncGetSupportedFeatures(mWifiStateMachineChannel);
    785         } else {
    786             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    787             return 0;
    788         }
    789     }
    790 
    791     /**
    792      * see {@link android.net.wifi.WifiAdapter#reportActivityInfo}
    793      */
    794     public WifiActivityEnergyInfo reportActivityInfo() {
    795         enforceAccessPermission();
    796         WifiLinkLayerStats stats;
    797         WifiActivityEnergyInfo energyInfo = null;
    798         if (mWifiStateMachineChannel != null) {
    799             stats = mWifiStateMachine.syncGetLinkLayerStats(mWifiStateMachineChannel);
    800             if (stats != null) {
    801                 // Convert the LinkLayerStats into EnergyActivity
    802                 energyInfo = new WifiActivityEnergyInfo(
    803                         WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE, stats.tx_time,
    804                         stats.rx_time, stats.on_time - stats.tx_time - stats.rx_time,
    805                         0 /* TBD */);
    806             }
    807             return energyInfo;
    808         } else {
    809             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    810             return null;
    811         }
    812     }
    813 
    814     /**
    815      * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
    816      * @return the list of configured networks
    817      */
    818     public List<WifiConfiguration> getConfiguredNetworks() {
    819         enforceAccessPermission();
    820         if (mWifiStateMachineChannel != null) {
    821             return mWifiStateMachine.syncGetConfiguredNetworks(Binder.getCallingUid(),
    822                     mWifiStateMachineChannel);
    823         } else {
    824             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    825             return null;
    826         }
    827     }
    828 
    829     /**
    830      * see {@link android.net.wifi.WifiManager#getPrivilegedConfiguredNetworks()}
    831      * @return the list of configured networks with real preSharedKey
    832      */
    833     public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
    834         enforceReadCredentialPermission();
    835         enforceAccessPermission();
    836         if (mWifiStateMachineChannel != null) {
    837             return mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel);
    838         } else {
    839             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    840             return null;
    841         }
    842     }
    843 
    844     /**
    845      * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
    846      * @return the supplicant-assigned identifier for the new or updated
    847      * network if the operation succeeds, or {@code -1} if it fails
    848      */
    849     public int addOrUpdateNetwork(WifiConfiguration config) {
    850         enforceChangePermission();
    851         if (config.isValid()) {
    852             //TODO: pass the Uid the WifiStateMachine as a message parameter
    853             Slog.e("addOrUpdateNetwork", " uid = " + Integer.toString(Binder.getCallingUid())
    854                     + " SSID " + config.SSID
    855                     + " nid=" + Integer.toString(config.networkId));
    856             if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
    857                 config.creatorUid = Binder.getCallingUid();
    858             } else {
    859                 config.lastUpdateUid = Binder.getCallingUid();
    860             }
    861             if (mWifiStateMachineChannel != null) {
    862                 return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
    863             } else {
    864                 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    865                 return -1;
    866             }
    867         } else {
    868             Slog.e(TAG, "bad network configuration");
    869             return -1;
    870         }
    871     }
    872 
    873      /**
    874      * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
    875      * @param netId the integer that identifies the network configuration
    876      * to the supplicant
    877      * @return {@code true} if the operation succeeded
    878      */
    879     public boolean removeNetwork(int netId) {
    880         enforceChangePermission();
    881 
    882         if (!isOwner(Binder.getCallingUid())) {
    883             Slog.e(TAG, "Remove is not authorized for user");
    884             return false;
    885         }
    886 
    887         if (mWifiStateMachineChannel != null) {
    888             return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
    889         } else {
    890             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    891             return false;
    892         }
    893     }
    894 
    895     /**
    896      * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
    897      * @param netId the integer that identifies the network configuration
    898      * to the supplicant
    899      * @param disableOthers if true, disable all other networks.
    900      * @return {@code true} if the operation succeeded
    901      */
    902     public boolean enableNetwork(int netId, boolean disableOthers) {
    903         enforceChangePermission();
    904         if (mWifiStateMachineChannel != null) {
    905             return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
    906                     disableOthers);
    907         } else {
    908             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    909             return false;
    910         }
    911     }
    912 
    913     /**
    914      * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
    915      * @param netId the integer that identifies the network configuration
    916      * to the supplicant
    917      * @return {@code true} if the operation succeeded
    918      */
    919     public boolean disableNetwork(int netId) {
    920         enforceChangePermission();
    921         if (mWifiStateMachineChannel != null) {
    922             return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
    923         } else {
    924             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
    925             return false;
    926         }
    927     }
    928 
    929     /**
    930      * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
    931      * @return the Wi-Fi information, contained in {@link WifiInfo}.
    932      */
    933     public WifiInfo getConnectionInfo() {
    934         enforceAccessPermission();
    935         /*
    936          * Make sure we have the latest information, by sending
    937          * a status request to the supplicant.
    938          */
    939         return mWifiStateMachine.syncRequestConnectionInfo();
    940     }
    941 
    942     /**
    943      * Return the results of the most recent access point scan, in the form of
    944      * a list of {@link ScanResult} objects.
    945      * @return the list of results
    946      */
    947     public List<ScanResult> getScanResults(String callingPackage) {
    948         enforceAccessPermission();
    949         int userId = UserHandle.getCallingUserId();
    950         int uid = Binder.getCallingUid();
    951         long ident = Binder.clearCallingIdentity();
    952         try {
    953             if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
    954                     != AppOpsManager.MODE_ALLOWED) {
    955                 return new ArrayList<ScanResult>();
    956             }
    957             if (!isCurrentProfile(userId)) {
    958                 return new ArrayList<ScanResult>();
    959             }
    960             return mWifiStateMachine.syncGetScanResultsList();
    961         } finally {
    962             Binder.restoreCallingIdentity(ident);
    963         }
    964     }
    965 
    966     /**
    967      * Returns true if the calling user is the current one or a profile of the
    968      * current user..
    969      */
    970     private boolean isCurrentProfile(int userId) {
    971         int currentUser = ActivityManager.getCurrentUser();
    972         if (userId == currentUser) {
    973             return true;
    974         }
    975         List<UserInfo> profiles = UserManager.get(mContext).getProfiles(currentUser);
    976         for (UserInfo user : profiles) {
    977             if (userId == user.id) {
    978                 return true;
    979             }
    980         }
    981         return false;
    982     }
    983 
    984     /**
    985      * Returns true if uid is an application running under the owner or a profile of the owner.
    986      *
    987      * Note: Should not be called if identity is cleared.
    988      */
    989     private boolean isOwner(int uid) {
    990         long ident = Binder.clearCallingIdentity();
    991         int userId = UserHandle.getUserId(uid);
    992         try {
    993             int ownerUser = UserHandle.USER_OWNER;
    994             if (userId == ownerUser) {
    995                 return true;
    996             }
    997             List<UserInfo> profiles = UserManager.get(mContext).getProfiles(ownerUser);
    998             for (UserInfo profile : profiles) {
    999                 if (userId == profile.id) {
   1000                     return true;
   1001                 }
   1002             }
   1003             return false;
   1004         }
   1005         finally {
   1006             Binder.restoreCallingIdentity(ident);
   1007         }
   1008     }
   1009 
   1010 
   1011     /**
   1012      * Tell the supplicant to persist the current list of configured networks.
   1013      * @return {@code true} if the operation succeeded
   1014      *
   1015      * TODO: deprecate this
   1016      */
   1017     public boolean saveConfiguration() {
   1018         boolean result = true;
   1019         enforceChangePermission();
   1020         if (mWifiStateMachineChannel != null) {
   1021             return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
   1022         } else {
   1023             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
   1024             return false;
   1025         }
   1026     }
   1027 
   1028     /**
   1029      * Set the country code
   1030      * @param countryCode ISO 3166 country code.
   1031      * @param persist {@code true} if the setting should be remembered.
   1032      *
   1033      * The persist behavior exists so that wifi can fall back to the last
   1034      * persisted country code on a restart, when the locale information is
   1035      * not available from telephony.
   1036      */
   1037     public void setCountryCode(String countryCode, boolean persist) {
   1038         Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
   1039                 " with persist set to " + persist);
   1040         enforceConnectivityInternalPermission();
   1041         final long token = Binder.clearCallingIdentity();
   1042         try {
   1043             mWifiStateMachine.setCountryCode(countryCode, persist);
   1044         } finally {
   1045             Binder.restoreCallingIdentity(token);
   1046         }
   1047     }
   1048 
   1049     /**
   1050      * Set the operational frequency band
   1051      * @param band One of
   1052      *     {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
   1053      *     {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
   1054      *     {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
   1055      * @param persist {@code true} if the setting should be remembered.
   1056      *
   1057      */
   1058     public void setFrequencyBand(int band, boolean persist) {
   1059         enforceChangePermission();
   1060         if (!isDualBandSupported()) return;
   1061         Slog.i(TAG, "WifiService trying to set frequency band to " + band +
   1062                 " with persist set to " + persist);
   1063         final long token = Binder.clearCallingIdentity();
   1064         try {
   1065             mWifiStateMachine.setFrequencyBand(band, persist);
   1066         } finally {
   1067             Binder.restoreCallingIdentity(token);
   1068         }
   1069     }
   1070 
   1071 
   1072     /**
   1073      * Get the operational frequency band
   1074      */
   1075     public int getFrequencyBand() {
   1076         enforceAccessPermission();
   1077         return mWifiStateMachine.getFrequencyBand();
   1078     }
   1079 
   1080     public boolean isDualBandSupported() {
   1081         //TODO: Should move towards adding a driver API that checks at runtime
   1082         return mContext.getResources().getBoolean(
   1083                 com.android.internal.R.bool.config_wifi_dual_band_support);
   1084     }
   1085 
   1086     /**
   1087      * Return the DHCP-assigned addresses from the last successful DHCP request,
   1088      * if any.
   1089      * @return the DHCP information
   1090      * @deprecated
   1091      */
   1092     public DhcpInfo getDhcpInfo() {
   1093         enforceAccessPermission();
   1094         DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults();
   1095 
   1096         DhcpInfo info = new DhcpInfo();
   1097 
   1098         if (dhcpResults.ipAddress != null &&
   1099                 dhcpResults.ipAddress.getAddress() instanceof Inet4Address) {
   1100             info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.ipAddress.getAddress());
   1101         }
   1102 
   1103         if (dhcpResults.gateway != null) {
   1104             info.gateway = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.gateway);
   1105         }
   1106 
   1107         int dnsFound = 0;
   1108         for (InetAddress dns : dhcpResults.dnsServers) {
   1109             if (dns instanceof Inet4Address) {
   1110                 if (dnsFound == 0) {
   1111                     info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
   1112                 } else {
   1113                     info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
   1114                 }
   1115                 if (++dnsFound > 1) break;
   1116             }
   1117         }
   1118         InetAddress serverAddress = dhcpResults.serverAddress;
   1119         if (serverAddress instanceof Inet4Address) {
   1120             info.serverAddress = NetworkUtils.inetAddressToInt((Inet4Address)serverAddress);
   1121         }
   1122         info.leaseDuration = dhcpResults.leaseDuration;
   1123 
   1124         return info;
   1125     }
   1126 
   1127     /**
   1128      * see {@link android.net.wifi.WifiManager#startWifi}
   1129      *
   1130      */
   1131     public void startWifi() {
   1132         enforceConnectivityInternalPermission();
   1133         /* TODO: may be add permissions for access only to connectivity service
   1134          * TODO: if a start issued, keep wifi alive until a stop issued irrespective
   1135          * of WifiLock & device idle status unless wifi enabled status is toggled
   1136          */
   1137 
   1138         mWifiStateMachine.setDriverStart(true);
   1139         mWifiStateMachine.reconnectCommand();
   1140     }
   1141 
   1142     /**
   1143      * see {@link android.net.wifi.WifiManager#stopWifi}
   1144      *
   1145      */
   1146     public void stopWifi() {
   1147         enforceConnectivityInternalPermission();
   1148         /*
   1149          * TODO: if a stop is issued, wifi is brought up only by startWifi
   1150          * unless wifi enabled status is toggled
   1151          */
   1152         mWifiStateMachine.setDriverStart(false);
   1153     }
   1154 
   1155     /**
   1156      * see {@link android.net.wifi.WifiManager#addToBlacklist}
   1157      *
   1158      */
   1159     public void addToBlacklist(String bssid) {
   1160         enforceChangePermission();
   1161 
   1162         mWifiStateMachine.addToBlacklist(bssid);
   1163     }
   1164 
   1165     /**
   1166      * see {@link android.net.wifi.WifiManager#clearBlacklist}
   1167      *
   1168      */
   1169     public void clearBlacklist() {
   1170         enforceChangePermission();
   1171 
   1172         mWifiStateMachine.clearBlacklist();
   1173     }
   1174 
   1175     /**
   1176      * enable TDLS for the local NIC to remote NIC
   1177      * The APPs don't know the remote MAC address to identify NIC though,
   1178      * so we need to do additional work to find it from remote IP address
   1179      */
   1180 
   1181     class TdlsTaskParams {
   1182         public String remoteIpAddress;
   1183         public boolean enable;
   1184     }
   1185 
   1186     class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> {
   1187         @Override
   1188         protected Integer doInBackground(TdlsTaskParams... params) {
   1189 
   1190             // Retrieve parameters for the call
   1191             TdlsTaskParams param = params[0];
   1192             String remoteIpAddress = param.remoteIpAddress.trim();
   1193             boolean enable = param.enable;
   1194 
   1195             // Get MAC address of Remote IP
   1196             String macAddress = null;
   1197 
   1198             BufferedReader reader = null;
   1199 
   1200             try {
   1201                 reader = new BufferedReader(new FileReader("/proc/net/arp"));
   1202 
   1203                 // Skip over the line bearing colum titles
   1204                 String line = reader.readLine();
   1205 
   1206                 while ((line = reader.readLine()) != null) {
   1207                     String[] tokens = line.split("[ ]+");
   1208                     if (tokens.length < 6) {
   1209                         continue;
   1210                     }
   1211 
   1212                     // ARP column format is
   1213                     // Address HWType HWAddress Flags Mask IFace
   1214                     String ip = tokens[0];
   1215                     String mac = tokens[3];
   1216 
   1217                     if (remoteIpAddress.equals(ip)) {
   1218                         macAddress = mac;
   1219                         break;
   1220                     }
   1221                 }
   1222 
   1223                 if (macAddress == null) {
   1224                     Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " +
   1225                             "/proc/net/arp");
   1226                 } else {
   1227                     enableTdlsWithMacAddress(macAddress, enable);
   1228                 }
   1229 
   1230             } catch (FileNotFoundException e) {
   1231                 Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address");
   1232             } catch (IOException e) {
   1233                 Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address");
   1234             } finally {
   1235                 try {
   1236                     if (reader != null) {
   1237                         reader.close();
   1238                     }
   1239                 }
   1240                 catch (IOException e) {
   1241                     // Do nothing
   1242                 }
   1243             }
   1244 
   1245             return 0;
   1246         }
   1247     }
   1248 
   1249     public void enableTdls(String remoteAddress, boolean enable) {
   1250         if (remoteAddress == null) {
   1251           throw new IllegalArgumentException("remoteAddress cannot be null");
   1252         }
   1253 
   1254         TdlsTaskParams params = new TdlsTaskParams();
   1255         params.remoteIpAddress = remoteAddress;
   1256         params.enable = enable;
   1257         new TdlsTask().execute(params);
   1258     }
   1259 
   1260 
   1261     public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
   1262         if (remoteMacAddress == null) {
   1263           throw new IllegalArgumentException("remoteMacAddress cannot be null");
   1264         }
   1265 
   1266         mWifiStateMachine.enableTdls(remoteMacAddress, enable);
   1267     }
   1268 
   1269     /**
   1270      * Get a reference to handler. This is used by a client to establish
   1271      * an AsyncChannel communication with WifiService
   1272      */
   1273     public Messenger getWifiServiceMessenger() {
   1274         enforceAccessPermission();
   1275         enforceChangePermission();
   1276         return new Messenger(mClientHandler);
   1277     }
   1278 
   1279 
   1280     /**
   1281      * Get the IP and proxy configuration file
   1282      */
   1283     public String getConfigFile() {
   1284         enforceAccessPermission();
   1285         return mWifiStateMachine.getConfigFile();
   1286     }
   1287 
   1288     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
   1289         @Override
   1290         public void onReceive(Context context, Intent intent) {
   1291             String action = intent.getAction();
   1292             if (action.equals(Intent.ACTION_SCREEN_ON)) {
   1293                 mWifiController.sendMessage(CMD_SCREEN_ON);
   1294             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
   1295                 mWifiController.sendMessage(CMD_USER_PRESENT);
   1296             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
   1297                 mWifiController.sendMessage(CMD_SCREEN_OFF);
   1298             } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
   1299                 int pluggedType = intent.getIntExtra("plugged", 0);
   1300                 mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null);
   1301             } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
   1302                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
   1303                         BluetoothAdapter.STATE_DISCONNECTED);
   1304                 mWifiStateMachine.sendBluetoothAdapterStateChange(state);
   1305             } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
   1306                 boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false);
   1307                 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0);
   1308             }
   1309         }
   1310     };
   1311 
   1312     /**
   1313      * Observes settings changes to scan always mode.
   1314      */
   1315     private void registerForScanModeChange() {
   1316         ContentObserver contentObserver = new ContentObserver(null) {
   1317             @Override
   1318             public void onChange(boolean selfChange) {
   1319                 mSettingsStore.handleWifiScanAlwaysAvailableToggled();
   1320                 mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED);
   1321             }
   1322         };
   1323 
   1324         mContext.getContentResolver().registerContentObserver(
   1325                 Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE),
   1326                 false, contentObserver);
   1327     }
   1328 
   1329     private void registerForBroadcasts() {
   1330         IntentFilter intentFilter = new IntentFilter();
   1331         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
   1332         intentFilter.addAction(Intent.ACTION_USER_PRESENT);
   1333         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
   1334         intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
   1335         intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
   1336         intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
   1337         intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
   1338         mContext.registerReceiver(mReceiver, intentFilter);
   1339     }
   1340 
   1341     @Override
   1342     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1343         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
   1344                 != PackageManager.PERMISSION_GRANTED) {
   1345             pw.println("Permission Denial: can't dump WifiService from from pid="
   1346                     + Binder.getCallingPid()
   1347                     + ", uid=" + Binder.getCallingUid());
   1348             return;
   1349         }
   1350         pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
   1351         pw.println("Stay-awake conditions: " +
   1352                 Settings.Global.getInt(mContext.getContentResolver(),
   1353                                        Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
   1354         pw.println("mMulticastEnabled " + mMulticastEnabled);
   1355         pw.println("mMulticastDisabled " + mMulticastDisabled);
   1356         mWifiController.dump(fd, pw, args);
   1357         mSettingsStore.dump(fd, pw, args);
   1358         mNotificationController.dump(fd, pw, args);
   1359         mTrafficPoller.dump(fd, pw, args);
   1360 
   1361         pw.println("Latest scan results:");
   1362         List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
   1363         long nowMs = System.currentTimeMillis();
   1364         if (scanResults != null && scanResults.size() != 0) {
   1365             pw.println("    BSSID              Frequency  RSSI    Age      SSID " +
   1366                     "                                Flags");
   1367             for (ScanResult r : scanResults) {
   1368                 long ageSec = 0;
   1369                 long ageMilli = 0;
   1370                 if (nowMs > r.seen && r.seen > 0) {
   1371                     ageSec = (nowMs - r.seen) / 1000;
   1372                     ageMilli = (nowMs - r.seen) % 1000;
   1373                 }
   1374                 String candidate = " ";
   1375                 if (r.isAutoJoinCandidate > 0) candidate = "+";
   1376                 pw.printf("  %17s  %9d  %5d  %3d.%03d%s   %-32s  %s\n",
   1377                                          r.BSSID,
   1378                                          r.frequency,
   1379                                          r.level,
   1380                                          ageSec, ageMilli,
   1381                                          candidate,
   1382                                          r.SSID == null ? "" : r.SSID,
   1383                                          r.capabilities);
   1384             }
   1385         }
   1386         pw.println();
   1387         pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
   1388                 mFullHighPerfLocksAcquired + " full high perf, " +
   1389                 mScanLocksAcquired + " scan");
   1390         pw.println("Locks released: " + mFullLocksReleased + " full, " +
   1391                 mFullHighPerfLocksReleased + " full high perf, " +
   1392                 mScanLocksReleased + " scan");
   1393         pw.println();
   1394         pw.println("Locks held:");
   1395         mLocks.dump(pw);
   1396 
   1397         mWifiWatchdogStateMachine.dump(fd, pw, args);
   1398         pw.println();
   1399         mWifiStateMachine.dump(fd, pw, args);
   1400         pw.println();
   1401     }
   1402 
   1403     private class WifiLock extends DeathRecipient {
   1404         WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
   1405             super(lockMode, tag, binder, ws);
   1406         }
   1407 
   1408         public void binderDied() {
   1409             synchronized (mLocks) {
   1410                 releaseWifiLockLocked(mBinder);
   1411             }
   1412         }
   1413 
   1414         public String toString() {
   1415             return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
   1416         }
   1417     }
   1418 
   1419     class LockList {
   1420         private List<WifiLock> mList;
   1421 
   1422         private LockList() {
   1423             mList = new ArrayList<WifiLock>();
   1424         }
   1425 
   1426         synchronized boolean hasLocks() {
   1427             return !mList.isEmpty();
   1428         }
   1429 
   1430         synchronized int getStrongestLockMode() {
   1431             if (mList.isEmpty()) {
   1432                 return WifiManager.WIFI_MODE_FULL;
   1433             }
   1434 
   1435             if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
   1436                 return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
   1437             }
   1438 
   1439             if (mFullLocksAcquired > mFullLocksReleased) {
   1440                 return WifiManager.WIFI_MODE_FULL;
   1441             }
   1442 
   1443             return WifiManager.WIFI_MODE_SCAN_ONLY;
   1444         }
   1445 
   1446         synchronized void updateWorkSource(WorkSource ws) {
   1447             for (int i = 0; i < mLocks.mList.size(); i++) {
   1448                 ws.add(mLocks.mList.get(i).mWorkSource);
   1449             }
   1450         }
   1451 
   1452         private void addLock(WifiLock lock) {
   1453             if (findLockByBinder(lock.mBinder) < 0) {
   1454                 mList.add(lock);
   1455             }
   1456         }
   1457 
   1458         private WifiLock removeLock(IBinder binder) {
   1459             int index = findLockByBinder(binder);
   1460             if (index >= 0) {
   1461                 WifiLock ret = mList.remove(index);
   1462                 ret.unlinkDeathRecipient();
   1463                 return ret;
   1464             } else {
   1465                 return null;
   1466             }
   1467         }
   1468 
   1469         private int findLockByBinder(IBinder binder) {
   1470             int size = mList.size();
   1471             for (int i = size - 1; i >= 0; i--) {
   1472                 if (mList.get(i).mBinder == binder)
   1473                     return i;
   1474             }
   1475             return -1;
   1476         }
   1477 
   1478         private void dump(PrintWriter pw) {
   1479             for (WifiLock l : mList) {
   1480                 pw.print("    ");
   1481                 pw.println(l);
   1482             }
   1483         }
   1484     }
   1485 
   1486     void enforceWakeSourcePermission(int uid, int pid) {
   1487         if (uid == android.os.Process.myUid()) {
   1488             return;
   1489         }
   1490         mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
   1491                 pid, uid, null);
   1492     }
   1493 
   1494     public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
   1495         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
   1496         if (lockMode != WifiManager.WIFI_MODE_FULL &&
   1497                 lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
   1498                 lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
   1499             Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
   1500             if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
   1501             return false;
   1502         }
   1503         if (ws != null && ws.size() == 0) {
   1504             ws = null;
   1505         }
   1506         if (ws != null) {
   1507             enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
   1508         }
   1509         if (ws == null) {
   1510             ws = new WorkSource(Binder.getCallingUid());
   1511         }
   1512         WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
   1513         synchronized (mLocks) {
   1514             return acquireWifiLockLocked(wifiLock);
   1515         }
   1516     }
   1517 
   1518     private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
   1519         switch(wifiLock.mMode) {
   1520             case WifiManager.WIFI_MODE_FULL:
   1521             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
   1522             case WifiManager.WIFI_MODE_SCAN_ONLY:
   1523                 mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
   1524                 break;
   1525         }
   1526     }
   1527 
   1528     private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
   1529         switch(wifiLock.mMode) {
   1530             case WifiManager.WIFI_MODE_FULL:
   1531             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
   1532             case WifiManager.WIFI_MODE_SCAN_ONLY:
   1533                 mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
   1534                 break;
   1535         }
   1536     }
   1537 
   1538     private boolean acquireWifiLockLocked(WifiLock wifiLock) {
   1539         if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
   1540 
   1541         mLocks.addLock(wifiLock);
   1542 
   1543         long ident = Binder.clearCallingIdentity();
   1544         try {
   1545             noteAcquireWifiLock(wifiLock);
   1546             switch(wifiLock.mMode) {
   1547             case WifiManager.WIFI_MODE_FULL:
   1548                 ++mFullLocksAcquired;
   1549                 break;
   1550             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
   1551                 ++mFullHighPerfLocksAcquired;
   1552                 break;
   1553 
   1554             case WifiManager.WIFI_MODE_SCAN_ONLY:
   1555                 ++mScanLocksAcquired;
   1556                 break;
   1557             }
   1558             mWifiController.sendMessage(CMD_LOCKS_CHANGED);
   1559             return true;
   1560         } catch (RemoteException e) {
   1561             return false;
   1562         } finally {
   1563             Binder.restoreCallingIdentity(ident);
   1564         }
   1565     }
   1566 
   1567     public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
   1568         int uid = Binder.getCallingUid();
   1569         int pid = Binder.getCallingPid();
   1570         if (ws != null && ws.size() == 0) {
   1571             ws = null;
   1572         }
   1573         if (ws != null) {
   1574             enforceWakeSourcePermission(uid, pid);
   1575         }
   1576         long ident = Binder.clearCallingIdentity();
   1577         try {
   1578             synchronized (mLocks) {
   1579                 int index = mLocks.findLockByBinder(lock);
   1580                 if (index < 0) {
   1581                     throw new IllegalArgumentException("Wifi lock not active");
   1582                 }
   1583                 WifiLock wl = mLocks.mList.get(index);
   1584                 noteReleaseWifiLock(wl);
   1585                 wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
   1586                 noteAcquireWifiLock(wl);
   1587             }
   1588         } catch (RemoteException e) {
   1589         } finally {
   1590             Binder.restoreCallingIdentity(ident);
   1591         }
   1592     }
   1593 
   1594     public boolean releaseWifiLock(IBinder lock) {
   1595         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
   1596         synchronized (mLocks) {
   1597             return releaseWifiLockLocked(lock);
   1598         }
   1599     }
   1600 
   1601     private boolean releaseWifiLockLocked(IBinder lock) {
   1602         boolean hadLock;
   1603 
   1604         WifiLock wifiLock = mLocks.removeLock(lock);
   1605 
   1606         if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
   1607 
   1608         hadLock = (wifiLock != null);
   1609 
   1610         long ident = Binder.clearCallingIdentity();
   1611         try {
   1612             if (hadLock) {
   1613                 noteReleaseWifiLock(wifiLock);
   1614                 switch(wifiLock.mMode) {
   1615                     case WifiManager.WIFI_MODE_FULL:
   1616                         ++mFullLocksReleased;
   1617                         break;
   1618                     case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
   1619                         ++mFullHighPerfLocksReleased;
   1620                         break;
   1621                     case WifiManager.WIFI_MODE_SCAN_ONLY:
   1622                         ++mScanLocksReleased;
   1623                         break;
   1624                 }
   1625                 mWifiController.sendMessage(CMD_LOCKS_CHANGED);
   1626             }
   1627         } catch (RemoteException e) {
   1628         } finally {
   1629             Binder.restoreCallingIdentity(ident);
   1630         }
   1631 
   1632         return hadLock;
   1633     }
   1634 
   1635     private abstract class DeathRecipient
   1636             implements IBinder.DeathRecipient {
   1637         String mTag;
   1638         int mMode;
   1639         IBinder mBinder;
   1640         WorkSource mWorkSource;
   1641 
   1642         DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) {
   1643             super();
   1644             mTag = tag;
   1645             mMode = mode;
   1646             mBinder = binder;
   1647             mWorkSource = ws;
   1648             try {
   1649                 mBinder.linkToDeath(this, 0);
   1650             } catch (RemoteException e) {
   1651                 binderDied();
   1652             }
   1653         }
   1654 
   1655         void unlinkDeathRecipient() {
   1656             mBinder.unlinkToDeath(this, 0);
   1657         }
   1658     }
   1659 
   1660     private class Multicaster extends DeathRecipient {
   1661         Multicaster(String tag, IBinder binder) {
   1662             super(Binder.getCallingUid(), tag, binder, null);
   1663         }
   1664 
   1665         public void binderDied() {
   1666             Slog.e(TAG, "Multicaster binderDied");
   1667             synchronized (mMulticasters) {
   1668                 int i = mMulticasters.indexOf(this);
   1669                 if (i != -1) {
   1670                     removeMulticasterLocked(i, mMode);
   1671                 }
   1672             }
   1673         }
   1674 
   1675         public String toString() {
   1676             return "Multicaster{" + mTag + " binder=" + mBinder + "}";
   1677         }
   1678 
   1679         public int getUid() {
   1680             return mMode;
   1681         }
   1682     }
   1683 
   1684     public void initializeMulticastFiltering() {
   1685         enforceMulticastChangePermission();
   1686 
   1687         synchronized (mMulticasters) {
   1688             // if anybody had requested filters be off, leave off
   1689             if (mMulticasters.size() != 0) {
   1690                 return;
   1691             } else {
   1692                 mWifiStateMachine.startFilteringMulticastV4Packets();
   1693             }
   1694         }
   1695     }
   1696 
   1697     public void acquireMulticastLock(IBinder binder, String tag) {
   1698         enforceMulticastChangePermission();
   1699 
   1700         synchronized (mMulticasters) {
   1701             mMulticastEnabled++;
   1702             mMulticasters.add(new Multicaster(tag, binder));
   1703             // Note that we could call stopFilteringMulticastV4Packets only when
   1704             // our new size == 1 (first call), but this function won't
   1705             // be called often and by making the stopPacket call each
   1706             // time we're less fragile and self-healing.
   1707             mWifiStateMachine.stopFilteringMulticastV4Packets();
   1708         }
   1709 
   1710         int uid = Binder.getCallingUid();
   1711         final long ident = Binder.clearCallingIdentity();
   1712         try {
   1713             mBatteryStats.noteWifiMulticastEnabled(uid);
   1714         } catch (RemoteException e) {
   1715         } finally {
   1716             Binder.restoreCallingIdentity(ident);
   1717         }
   1718     }
   1719 
   1720     public void releaseMulticastLock() {
   1721         enforceMulticastChangePermission();
   1722 
   1723         int uid = Binder.getCallingUid();
   1724         synchronized (mMulticasters) {
   1725             mMulticastDisabled++;
   1726             int size = mMulticasters.size();
   1727             for (int i = size - 1; i >= 0; i--) {
   1728                 Multicaster m = mMulticasters.get(i);
   1729                 if ((m != null) && (m.getUid() == uid)) {
   1730                     removeMulticasterLocked(i, uid);
   1731                 }
   1732             }
   1733         }
   1734     }
   1735 
   1736     private void removeMulticasterLocked(int i, int uid)
   1737     {
   1738         Multicaster removed = mMulticasters.remove(i);
   1739 
   1740         if (removed != null) {
   1741             removed.unlinkDeathRecipient();
   1742         }
   1743         if (mMulticasters.size() == 0) {
   1744             mWifiStateMachine.startFilteringMulticastV4Packets();
   1745         }
   1746 
   1747         final long ident = Binder.clearCallingIdentity();
   1748         try {
   1749             mBatteryStats.noteWifiMulticastDisabled(uid);
   1750         } catch (RemoteException e) {
   1751         } finally {
   1752             Binder.restoreCallingIdentity(ident);
   1753         }
   1754     }
   1755 
   1756     public boolean isMulticastEnabled() {
   1757         enforceAccessPermission();
   1758 
   1759         synchronized (mMulticasters) {
   1760             return (mMulticasters.size() > 0);
   1761         }
   1762     }
   1763 
   1764     public WifiMonitor getWifiMonitor() {
   1765         return mWifiStateMachine.getWifiMonitor();
   1766     }
   1767 
   1768     public void enableVerboseLogging(int verbose) {
   1769         enforceAccessPermission();
   1770         mWifiStateMachine.enableVerboseLogging(verbose);
   1771     }
   1772 
   1773     public int getVerboseLoggingLevel() {
   1774         enforceAccessPermission();
   1775         return mWifiStateMachine.getVerboseLoggingLevel();
   1776     }
   1777 
   1778     public void enableAggressiveHandover(int enabled) {
   1779         enforceAccessPermission();
   1780         mWifiStateMachine.enableAggressiveHandover(enabled);
   1781     }
   1782 
   1783     public int getAggressiveHandover() {
   1784         enforceAccessPermission();
   1785         return mWifiStateMachine.getAggressiveHandover();
   1786     }
   1787 
   1788     public void setAllowScansWithTraffic(int enabled) {
   1789         enforceAccessPermission();
   1790         mWifiStateMachine.setAllowScansWithTraffic(enabled);
   1791     }
   1792 
   1793     public int getAllowScansWithTraffic() {
   1794         enforceAccessPermission();
   1795         return mWifiStateMachine.getAllowScansWithTraffic();
   1796     }
   1797 
   1798     /* Return the Wifi Connection statistics object */
   1799     public WifiConnectionStatistics getConnectionStatistics() {
   1800         enforceAccessPermission();
   1801         enforceReadCredentialPermission();
   1802         if (mWifiStateMachineChannel != null) {
   1803             return mWifiStateMachine.syncGetConnectionStatistics(mWifiStateMachineChannel);
   1804         } else {
   1805             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
   1806             return null;
   1807         }
   1808     }
   1809 }
   1810