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