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