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