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 android.net.wifi.WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE;
     20 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_FAILURE_REASON;
     21 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
     22 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
     23 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
     24 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
     25 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL;
     26 import static android.net.wifi.WifiManager.SAP_START_FAILURE_NO_CHANNEL;
     27 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
     28 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
     29 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
     30 
     31 import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERROR;
     32 import static com.android.server.wifi.WifiController.CMD_AIRPLANE_TOGGLED;
     33 import static com.android.server.wifi.WifiController.CMD_BATTERY_CHANGED;
     34 import static com.android.server.wifi.WifiController.CMD_EMERGENCY_CALL_STATE_CHANGED;
     35 import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED;
     36 import static com.android.server.wifi.WifiController.CMD_LOCKS_CHANGED;
     37 import static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED;
     38 import static com.android.server.wifi.WifiController.CMD_SCREEN_OFF;
     39 import static com.android.server.wifi.WifiController.CMD_SCREEN_ON;
     40 import static com.android.server.wifi.WifiController.CMD_SET_AP;
     41 import static com.android.server.wifi.WifiController.CMD_USER_PRESENT;
     42 import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED;
     43 
     44 import android.Manifest;
     45 import android.app.ActivityManager;
     46 import android.app.ActivityManager.RunningAppProcessInfo;
     47 import android.app.AppOpsManager;
     48 import android.bluetooth.BluetoothAdapter;
     49 import android.content.BroadcastReceiver;
     50 import android.content.Context;
     51 import android.content.Intent;
     52 import android.content.IntentFilter;
     53 import android.content.pm.ApplicationInfo;
     54 import android.content.pm.PackageManager;
     55 import android.content.pm.ParceledListSlice;
     56 import android.database.ContentObserver;
     57 import android.net.DhcpInfo;
     58 import android.net.DhcpResults;
     59 import android.net.IpConfiguration;
     60 import android.net.Network;
     61 import android.net.NetworkUtils;
     62 import android.net.StaticIpConfiguration;
     63 import android.net.Uri;
     64 import android.net.ip.IpManager;
     65 import android.net.wifi.IWifiManager;
     66 import android.net.wifi.ScanResult;
     67 import android.net.wifi.ScanSettings;
     68 import android.net.wifi.WifiActivityEnergyInfo;
     69 import android.net.wifi.WifiConfiguration;
     70 import android.net.wifi.WifiConnectionStatistics;
     71 import android.net.wifi.WifiInfo;
     72 import android.net.wifi.WifiLinkLayerStats;
     73 import android.net.wifi.WifiManager;
     74 import android.net.wifi.WifiManager.LocalOnlyHotspotCallback;
     75 import android.net.wifi.WifiScanner;
     76 import android.net.wifi.hotspot2.PasspointConfiguration;
     77 import android.os.AsyncTask;
     78 import android.os.BatteryStats;
     79 import android.os.Binder;
     80 import android.os.Build;
     81 import android.os.Bundle;
     82 import android.os.HandlerThread;
     83 import android.os.IBinder;
     84 import android.os.Looper;
     85 import android.os.Message;
     86 import android.os.Messenger;
     87 import android.os.PowerManager;
     88 import android.os.Process;
     89 import android.os.RemoteException;
     90 import android.os.ResultReceiver;
     91 import android.os.UserHandle;
     92 import android.os.UserManager;
     93 import android.os.WorkSource;
     94 import android.provider.Settings;
     95 import android.util.ArrayMap;
     96 import android.util.ArraySet;
     97 import android.util.Log;
     98 import android.util.Slog;
     99 
    100 import com.android.internal.annotations.GuardedBy;
    101 import com.android.internal.annotations.VisibleForTesting;
    102 import com.android.internal.telephony.IccCardConstants;
    103 import com.android.internal.telephony.PhoneConstants;
    104 import com.android.internal.telephony.TelephonyIntents;
    105 import com.android.internal.util.AsyncChannel;
    106 import com.android.server.wifi.hotspot2.PasspointProvider;
    107 import com.android.server.wifi.util.WifiHandler;
    108 import com.android.server.wifi.util.WifiPermissionsUtil;
    109 
    110 import java.io.BufferedReader;
    111 import java.io.FileDescriptor;
    112 import java.io.FileNotFoundException;
    113 import java.io.FileReader;
    114 import java.io.IOException;
    115 import java.io.PrintWriter;
    116 import java.net.Inet4Address;
    117 import java.net.InetAddress;
    118 import java.security.GeneralSecurityException;
    119 import java.security.KeyStore;
    120 import java.security.cert.CertPath;
    121 import java.security.cert.CertPathValidator;
    122 import java.security.cert.CertificateFactory;
    123 import java.security.cert.PKIXParameters;
    124 import java.security.cert.X509Certificate;
    125 import java.util.ArrayList;
    126 import java.util.Arrays;
    127 import java.util.HashMap;
    128 import java.util.List;
    129 import java.util.concurrent.ConcurrentHashMap;
    130 
    131 /**
    132  * WifiService handles remote WiFi operation requests by implementing
    133  * the IWifiManager interface.
    134  *
    135  * @hide
    136  */
    137 public class WifiServiceImpl extends IWifiManager.Stub {
    138     private static final String TAG = "WifiService";
    139     private static final boolean DBG = true;
    140     private static final boolean VDBG = false;
    141 
    142     // Dumpsys argument to enable/disable disconnect on IP reachability failures.
    143     private static final String DUMP_ARG_SET_IPREACH_DISCONNECT = "set-ipreach-disconnect";
    144     private static final String DUMP_ARG_SET_IPREACH_DISCONNECT_ENABLED = "enabled";
    145     private static final String DUMP_ARG_SET_IPREACH_DISCONNECT_DISABLED = "disabled";
    146 
    147     // Default scan background throttling interval if not overriden in settings
    148     private static final long DEFAULT_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
    149 
    150     // Apps with importance higher than this value is considered as background app.
    151     private static final int BACKGROUND_IMPORTANCE_CUTOFF =
    152             RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
    153 
    154     final WifiStateMachine mWifiStateMachine;
    155 
    156     private final Context mContext;
    157     private final FrameworkFacade mFacade;
    158     private final Clock mClock;
    159     private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
    160 
    161     private final PowerManager mPowerManager;
    162     private final AppOpsManager mAppOps;
    163     private final UserManager mUserManager;
    164     private final ActivityManager mActivityManager;
    165     private final WifiCountryCode mCountryCode;
    166     private long mBackgroundThrottleInterval;
    167     // Debug counter tracking scan requests sent by WifiManager
    168     private int scanRequestCounter = 0;
    169 
    170     /* Tracks the open wi-fi network notification */
    171     private WifiNotificationController mNotificationController;
    172     /* Polls traffic stats and notifies clients */
    173     private WifiTrafficPoller mTrafficPoller;
    174     /* Tracks the persisted states for wi-fi & airplane mode */
    175     final WifiSettingsStore mSettingsStore;
    176     /* Logs connection events and some general router and scan stats */
    177     private final WifiMetrics mWifiMetrics;
    178     /* Manages affiliated certificates for current user */
    179     private final WifiCertManager mCertManager;
    180 
    181     private final WifiInjector mWifiInjector;
    182     /* Backup/Restore Module */
    183     private final WifiBackupRestore mWifiBackupRestore;
    184 
    185     // Map of package name of background scan apps and last scan timestamp.
    186     private final ArrayMap<String, Long> mLastScanTimestamps;
    187 
    188     private WifiScanner mWifiScanner;
    189     private WifiLog mLog;
    190 
    191     /**
    192      * Asynchronous channel to WifiStateMachine
    193      */
    194     private AsyncChannel mWifiStateMachineChannel;
    195 
    196     private final boolean mPermissionReviewRequired;
    197     private final FrameworkFacade mFrameworkFacade;
    198 
    199     private WifiPermissionsUtil mWifiPermissionsUtil;
    200 
    201     @GuardedBy("mLocalOnlyHotspotRequests")
    202     private final HashMap<Integer, LocalOnlyHotspotRequestInfo> mLocalOnlyHotspotRequests;
    203     @GuardedBy("mLocalOnlyHotspotRequests")
    204     private WifiConfiguration mLocalOnlyHotspotConfig = null;
    205     @GuardedBy("mLocalOnlyHotspotRequests")
    206     private final ConcurrentHashMap<String, Integer> mIfaceIpModes;
    207 
    208     /**
    209      * Callback for use with LocalOnlyHotspot to unregister requesting applications upon death.
    210      *
    211      * @hide
    212      */
    213     public final class LocalOnlyRequestorCallback
    214             implements LocalOnlyHotspotRequestInfo.RequestingApplicationDeathCallback {
    215         /**
    216          * Called with requesting app has died.
    217          */
    218         @Override
    219         public void onLocalOnlyHotspotRequestorDeath(LocalOnlyHotspotRequestInfo requestor) {
    220             unregisterCallingAppAndStopLocalOnlyHotspot(requestor);
    221         };
    222     }
    223 
    224     /**
    225      * Handles client connections
    226      */
    227     private class ClientHandler extends WifiHandler {
    228 
    229         ClientHandler(String tag, Looper looper) {
    230             super(tag, looper);
    231         }
    232 
    233         @Override
    234         public void handleMessage(Message msg) {
    235             super.handleMessage(msg);
    236             switch (msg.what) {
    237                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
    238                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
    239                         if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
    240                         // We track the clients by the Messenger
    241                         // since it is expected to be always available
    242                         mTrafficPoller.addClient(msg.replyTo);
    243                     } else {
    244                         Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
    245                     }
    246                     break;
    247                 }
    248                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
    249                     if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
    250                         if (DBG) Slog.d(TAG, "Send failed, client connection lost");
    251                     } else {
    252                         if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
    253                     }
    254                     mTrafficPoller.removeClient(msg.replyTo);
    255                     break;
    256                 }
    257                 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
    258                     AsyncChannel ac = mFrameworkFacade.makeWifiAsyncChannel(TAG);
    259                     ac.connect(mContext, this, msg.replyTo);
    260                     break;
    261                 }
    262                 case WifiManager.CONNECT_NETWORK: {
    263                     WifiConfiguration config = (WifiConfiguration) msg.obj;
    264                     int networkId = msg.arg1;
    265                     Slog.d("WiFiServiceImpl ", "CONNECT "
    266                             + " nid=" + Integer.toString(networkId)
    267                             + " uid=" + msg.sendingUid
    268                             + " name="
    269                             + mContext.getPackageManager().getNameForUid(msg.sendingUid));
    270                     if (config != null && isValid(config)) {
    271                         if (DBG) Slog.d(TAG, "Connect with config " + config);
    272                         /* Command is forwarded to state machine */
    273                         mWifiStateMachine.sendMessage(Message.obtain(msg));
    274                     } else if (config == null
    275                             && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
    276                         if (DBG) Slog.d(TAG, "Connect with networkId " + networkId);
    277                         mWifiStateMachine.sendMessage(Message.obtain(msg));
    278                     } else {
    279                         Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
    280                         replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED,
    281                                 WifiManager.INVALID_ARGS);
    282                     }
    283                     break;
    284                 }
    285                 case WifiManager.SAVE_NETWORK: {
    286                     WifiConfiguration config = (WifiConfiguration) msg.obj;
    287                     int networkId = msg.arg1;
    288                     Slog.d("WiFiServiceImpl ", "SAVE"
    289                             + " nid=" + Integer.toString(networkId)
    290                             + " uid=" + msg.sendingUid
    291                             + " name="
    292                             + mContext.getPackageManager().getNameForUid(msg.sendingUid));
    293                     if (config != null && isValid(config)) {
    294                         if (DBG) Slog.d(TAG, "Save network with config " + config);
    295                         /* Command is forwarded to state machine */
    296                         mWifiStateMachine.sendMessage(Message.obtain(msg));
    297                     } else {
    298                         Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
    299                         replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED,
    300                                 WifiManager.INVALID_ARGS);
    301                     }
    302                     break;
    303                 }
    304                 case WifiManager.FORGET_NETWORK:
    305                     mWifiStateMachine.sendMessage(Message.obtain(msg));
    306                     break;
    307                 case WifiManager.START_WPS:
    308                 case WifiManager.CANCEL_WPS:
    309                 case WifiManager.DISABLE_NETWORK:
    310                 case WifiManager.RSSI_PKTCNT_FETCH: {
    311                     mWifiStateMachine.sendMessage(Message.obtain(msg));
    312                     break;
    313                 }
    314                 default: {
    315                     Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg);
    316                     break;
    317                 }
    318             }
    319         }
    320 
    321         private void replyFailed(Message msg, int what, int why) {
    322             if (msg.replyTo == null) return;
    323             Message reply = Message.obtain();
    324             reply.what = what;
    325             reply.arg1 = why;
    326             try {
    327                 msg.replyTo.send(reply);
    328             } catch (RemoteException e) {
    329                 // There's not much we can do if reply can't be sent!
    330             }
    331         }
    332     }
    333     private ClientHandler mClientHandler;
    334 
    335     /**
    336      * Handles interaction with WifiStateMachine
    337      */
    338     private class WifiStateMachineHandler extends WifiHandler {
    339         private AsyncChannel mWsmChannel;
    340 
    341         WifiStateMachineHandler(String tag, Looper looper, AsyncChannel asyncChannel) {
    342             super(tag, looper);
    343             mWsmChannel = asyncChannel;
    344             mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
    345         }
    346 
    347         @Override
    348         public void handleMessage(Message msg) {
    349             super.handleMessage(msg);
    350             switch (msg.what) {
    351                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
    352                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
    353                         mWifiStateMachineChannel = mWsmChannel;
    354                     } else {
    355                         Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1);
    356                         mWifiStateMachineChannel = null;
    357                     }
    358                     break;
    359                 }
    360                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
    361                     Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1);
    362                     mWifiStateMachineChannel = null;
    363                     //Re-establish connection to state machine
    364                     mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
    365                     break;
    366                 }
    367                 default: {
    368                     Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg);
    369                     break;
    370                 }
    371             }
    372         }
    373     }
    374 
    375     WifiStateMachineHandler mWifiStateMachineHandler;
    376     private WifiController mWifiController;
    377     private final WifiLockManager mWifiLockManager;
    378     private final WifiMulticastLockManager mWifiMulticastLockManager;
    379 
    380     public WifiServiceImpl(Context context, WifiInjector wifiInjector, AsyncChannel asyncChannel) {
    381         mContext = context;
    382         mWifiInjector = wifiInjector;
    383         mClock = wifiInjector.getClock();
    384 
    385         mFacade = mWifiInjector.getFrameworkFacade();
    386         mWifiMetrics = mWifiInjector.getWifiMetrics();
    387         mTrafficPoller = mWifiInjector.getWifiTrafficPoller();
    388         mUserManager = mWifiInjector.getUserManager();
    389         mCountryCode = mWifiInjector.getWifiCountryCode();
    390         mWifiStateMachine = mWifiInjector.getWifiStateMachine();
    391         mWifiStateMachine.enableRssiPolling(true);
    392         mSettingsStore = mWifiInjector.getWifiSettingsStore();
    393         mPowerManager = mContext.getSystemService(PowerManager.class);
    394         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
    395         mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
    396         mCertManager = mWifiInjector.getWifiCertManager();
    397         mNotificationController = mWifiInjector.getWifiNotificationController();
    398         mWifiLockManager = mWifiInjector.getWifiLockManager();
    399         mWifiMulticastLockManager = mWifiInjector.getWifiMulticastLockManager();
    400         HandlerThread wifiServiceHandlerThread = mWifiInjector.getWifiServiceHandlerThread();
    401         mClientHandler = new ClientHandler(TAG, wifiServiceHandlerThread.getLooper());
    402         mWifiStateMachineHandler = new WifiStateMachineHandler(TAG,
    403                 wifiServiceHandlerThread.getLooper(), asyncChannel);
    404         mWifiController = mWifiInjector.getWifiController();
    405         mWifiBackupRestore = mWifiInjector.getWifiBackupRestore();
    406         mPermissionReviewRequired = Build.PERMISSIONS_REVIEW_REQUIRED
    407                 || context.getResources().getBoolean(
    408                 com.android.internal.R.bool.config_permissionReviewRequired);
    409         mWifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil();
    410         mLog = mWifiInjector.makeLog(TAG);
    411         mFrameworkFacade = wifiInjector.getFrameworkFacade();
    412         mLastScanTimestamps = new ArrayMap<>();
    413         updateBackgroundThrottleInterval();
    414         updateBackgroundThrottlingWhitelist();
    415         mIfaceIpModes = new ConcurrentHashMap<>();
    416         mLocalOnlyHotspotRequests = new HashMap<>();
    417         enableVerboseLoggingInternal(getVerboseLoggingLevel());
    418     }
    419 
    420     /**
    421      * Provide a way for unit tests to set valid log object in the WifiHandler
    422      * @param log WifiLog object to assign to the clientHandler
    423      */
    424     @VisibleForTesting
    425     public void setWifiHandlerLogForTest(WifiLog log) {
    426         mClientHandler.setWifiLog(log);
    427     }
    428 
    429     /**
    430      * Check if we are ready to start wifi.
    431      *
    432      * First check if we will be restarting system services to decrypt the device. If the device is
    433      * not encrypted, check if Wi-Fi needs to be enabled and start if needed
    434      *
    435      * This function is used only at boot time.
    436      */
    437     public void checkAndStartWifi() {
    438         // First check if we will end up restarting WifiService
    439         if (mFrameworkFacade.inStorageManagerCryptKeeperBounce()) {
    440             Log.d(TAG, "Device still encrypted. Need to restart SystemServer.  Do not start wifi.");
    441             return;
    442         }
    443 
    444         // Check if wi-fi needs to be enabled
    445         boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled();
    446         Slog.i(TAG, "WifiService starting up with Wi-Fi " +
    447                 (wifiEnabled ? "enabled" : "disabled"));
    448 
    449         registerForScanModeChange();
    450         registerForBackgroundThrottleChanges();
    451         mContext.registerReceiver(
    452                 new BroadcastReceiver() {
    453                     @Override
    454                     public void onReceive(Context context, Intent intent) {
    455                         if (mSettingsStore.handleAirplaneModeToggled()) {
    456                             mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED);
    457                         }
    458                         if (mSettingsStore.isAirplaneModeOn()) {
    459                             Log.d(TAG, "resetting country code because Airplane mode is ON");
    460                             mCountryCode.airplaneModeEnabled();
    461                         }
    462                     }
    463                 },
    464                 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
    465 
    466         mContext.registerReceiver(
    467                 new BroadcastReceiver() {
    468                     @Override
    469                     public void onReceive(Context context, Intent intent) {
    470                         String state = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
    471                         if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state)) {
    472                             Log.d(TAG, "resetting networks because SIM was removed");
    473                             mWifiStateMachine.resetSimAuthNetworks(false);
    474                             Log.d(TAG, "resetting country code because SIM is removed");
    475                             mCountryCode.simCardRemoved();
    476                         } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state)) {
    477                             Log.d(TAG, "resetting networks because SIM was loaded");
    478                             mWifiStateMachine.resetSimAuthNetworks(true);
    479                         }
    480                     }
    481                 },
    482                 new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
    483 
    484         mContext.registerReceiver(
    485                 new BroadcastReceiver() {
    486                     @Override
    487                     public void onReceive(Context context, Intent intent) {
    488                         final int currState = intent.getIntExtra(EXTRA_WIFI_AP_STATE,
    489                                                                     WIFI_AP_STATE_DISABLED);
    490                         final int prevState = intent.getIntExtra(EXTRA_PREVIOUS_WIFI_AP_STATE,
    491                                                                  WIFI_AP_STATE_DISABLED);
    492                         final int errorCode = intent.getIntExtra(EXTRA_WIFI_AP_FAILURE_REASON,
    493                                                                  HOTSPOT_NO_ERROR);
    494                         final String ifaceName =
    495                                 intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME);
    496                         final int mode = intent.getIntExtra(EXTRA_WIFI_AP_MODE,
    497                                                             WifiManager.IFACE_IP_MODE_UNSPECIFIED);
    498                         handleWifiApStateChange(currState, prevState, errorCode, ifaceName, mode);
    499                     }
    500                 },
    501                 new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION));
    502 
    503         // Adding optimizations of only receiving broadcasts when wifi is enabled
    504         // can result in race conditions when apps toggle wifi in the background
    505         // without active user involvement. Always receive broadcasts.
    506         registerForBroadcasts();
    507         registerForPackageOrUserRemoval();
    508         mInIdleMode = mPowerManager.isDeviceIdleMode();
    509 
    510         if (!mWifiStateMachine.syncInitialize(mWifiStateMachineChannel)) {
    511             Log.wtf(TAG, "Failed to initialize WifiStateMachine");
    512         }
    513         mWifiController.start();
    514 
    515         // If we are already disabled (could be due to airplane mode), avoid changing persist
    516         // state here
    517         if (wifiEnabled) {
    518             try {
    519                 setWifiEnabled(mContext.getPackageName(), wifiEnabled);
    520             } catch (RemoteException e) {
    521                 /* ignore - local call */
    522             }
    523         }
    524     }
    525 
    526     public void handleUserSwitch(int userId) {
    527         mWifiStateMachine.handleUserSwitch(userId);
    528     }
    529 
    530     public void handleUserUnlock(int userId) {
    531         mWifiStateMachine.handleUserUnlock(userId);
    532     }
    533 
    534     public void handleUserStop(int userId) {
    535         mWifiStateMachine.handleUserStop(userId);
    536     }
    537 
    538     /**
    539      * see {@link android.net.wifi.WifiManager#startScan}
    540      * and {@link android.net.wifi.WifiManager#startCustomizedScan}
    541      *
    542      * @param settings If null, use default parameter, i.e. full scan.
    543      * @param workSource If null, all blame is given to the calling uid.
    544      * @param packageName Package name of the app that requests wifi scan.
    545      */
    546     @Override
    547     public void startScan(ScanSettings settings, WorkSource workSource, String packageName) {
    548         enforceChangePermission();
    549 
    550         mLog.trace("startScan uid=%").c(Binder.getCallingUid()).flush();
    551         // Check and throttle background apps for wifi scan.
    552         if (isRequestFromBackground(packageName)) {
    553             long lastScanMs = mLastScanTimestamps.getOrDefault(packageName, 0L);
    554             long elapsedRealtime = mClock.getElapsedSinceBootMillis();
    555 
    556             if (lastScanMs != 0 && (elapsedRealtime - lastScanMs) < mBackgroundThrottleInterval) {
    557                 sendFailedScanBroadcast();
    558                 return;
    559             }
    560             // Proceed with the scan request and record the time.
    561             mLastScanTimestamps.put(packageName, elapsedRealtime);
    562         }
    563         synchronized (this) {
    564             if (mWifiScanner == null) {
    565                 mWifiScanner = mWifiInjector.getWifiScanner();
    566             }
    567             if (mInIdleMode) {
    568                 // Need to send an immediate scan result broadcast in case the
    569                 // caller is waiting for a result ..
    570 
    571                 // TODO: investigate if the logic to cancel scans when idle can move to
    572                 // WifiScanningServiceImpl.  This will 1 - clean up WifiServiceImpl and 2 -
    573                 // avoid plumbing an awkward path to report a cancelled/failed scan.  This will
    574                 // be sent directly until b/31398592 is fixed.
    575                 sendFailedScanBroadcast();
    576                 mScanPending = true;
    577                 return;
    578             }
    579         }
    580         if (settings != null) {
    581             settings = new ScanSettings(settings);
    582             if (!settings.isValid()) {
    583                 Slog.e(TAG, "invalid scan setting");
    584                 return;
    585             }
    586         }
    587         if (workSource != null) {
    588             enforceWorkSourcePermission();
    589             // WifiManager currently doesn't use names, so need to clear names out of the
    590             // supplied WorkSource to allow future WorkSource combining.
    591             workSource.clearNames();
    592         }
    593         if (workSource == null && Binder.getCallingUid() >= 0) {
    594             workSource = new WorkSource(Binder.getCallingUid());
    595         }
    596         mWifiStateMachine.startScan(Binder.getCallingUid(), scanRequestCounter++,
    597                 settings, workSource);
    598     }
    599 
    600     // Send a failed scan broadcast to indicate the current scan request failed.
    601     private void sendFailedScanBroadcast() {
    602         // clear calling identity to send broadcast
    603         long callingIdentity = Binder.clearCallingIdentity();
    604         try {
    605             Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
    606             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    607             intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
    608             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
    609         } finally {
    610             // restore calling identity
    611             Binder.restoreCallingIdentity(callingIdentity);
    612         }
    613 
    614     }
    615 
    616     // Check if the request comes from background.
    617     private boolean isRequestFromBackground(String packageName) {
    618         // Requests from system or wifi are not background.
    619         if (Binder.getCallingUid() == Process.SYSTEM_UID
    620                 || Binder.getCallingUid() == Process.WIFI_UID) {
    621             return false;
    622         }
    623         mAppOps.checkPackage(Binder.getCallingUid(), packageName);
    624         if (mBackgroundThrottlePackageWhitelist.contains(packageName)) {
    625             return false;
    626         }
    627 
    628         // getPackageImportance requires PACKAGE_USAGE_STATS permission, so clearing the incoming
    629         // identify so the permission check can be done on system process where wifi runs in.
    630         long callingIdentity = Binder.clearCallingIdentity();
    631         try {
    632             return mActivityManager.getPackageImportance(packageName)
    633                     > BACKGROUND_IMPORTANCE_CUTOFF;
    634         } finally {
    635             Binder.restoreCallingIdentity(callingIdentity);
    636         }
    637     }
    638 
    639     @Override
    640     public String getCurrentNetworkWpsNfcConfigurationToken() {
    641         enforceConnectivityInternalPermission();
    642         mLog.trace("getCurrentNetworkWpsNfcConfigurationToken uid=%")
    643                 .c(Binder.getCallingUid()).flush();
    644         // TODO Add private logging for netId b/33807876
    645         return mWifiStateMachine.syncGetCurrentNetworkWpsNfcConfigurationToken();
    646     }
    647 
    648     boolean mInIdleMode;
    649     boolean mScanPending;
    650 
    651     void handleIdleModeChanged() {
    652         boolean doScan = false;
    653         synchronized (this) {
    654             boolean idle = mPowerManager.isDeviceIdleMode();
    655             if (mInIdleMode != idle) {
    656                 mInIdleMode = idle;
    657                 if (!idle) {
    658                     if (mScanPending) {
    659                         mScanPending = false;
    660                         doScan = true;
    661                     }
    662                 }
    663             }
    664         }
    665         if (doScan) {
    666             // Someone requested a scan while we were idle; do a full scan now.
    667             // The package name doesn't matter as the request comes from System UID.
    668             startScan(null, null, "");
    669         }
    670     }
    671 
    672     private void enforceNetworkSettingsPermission() {
    673         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS,
    674                 "WifiService");
    675     }
    676 
    677     private void enforceNetworkStackPermission() {
    678         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK,
    679                 "WifiService");
    680     }
    681 
    682     private void enforceAccessPermission() {
    683         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
    684                 "WifiService");
    685     }
    686 
    687     private void enforceChangePermission() {
    688         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
    689                 "WifiService");
    690     }
    691 
    692     private void enforceLocationHardwarePermission() {
    693         mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE,
    694                 "LocationHardware");
    695     }
    696 
    697     private void enforceReadCredentialPermission() {
    698         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL,
    699                                                 "WifiService");
    700     }
    701 
    702     private void enforceWorkSourcePermission() {
    703         mContext.enforceCallingPermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
    704                 "WifiService");
    705 
    706     }
    707 
    708     private void enforceMulticastChangePermission() {
    709         mContext.enforceCallingOrSelfPermission(
    710                 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
    711                 "WifiService");
    712     }
    713 
    714     private void enforceConnectivityInternalPermission() {
    715         mContext.enforceCallingOrSelfPermission(
    716                 android.Manifest.permission.CONNECTIVITY_INTERNAL,
    717                 "ConnectivityService");
    718     }
    719 
    720     private void enforceLocationPermission(String pkgName, int uid) {
    721         mWifiPermissionsUtil.enforceLocationPermission(pkgName, uid);
    722     }
    723 
    724     private boolean checkNetworkSettingsPermission() {
    725         int result = mContext.checkCallingOrSelfPermission(
    726                 android.Manifest.permission.NETWORK_SETTINGS);
    727         return result == PackageManager.PERMISSION_GRANTED;
    728     }
    729 
    730     /**
    731      * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
    732      * @param enable {@code true} to enable, {@code false} to disable.
    733      * @return {@code true} if the enable/disable operation was
    734      *         started or is already in the queue.
    735      */
    736     @Override
    737     public synchronized boolean setWifiEnabled(String packageName, boolean enable)
    738             throws RemoteException {
    739         enforceChangePermission();
    740         Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
    741                     + ", uid=" + Binder.getCallingUid() + ", package=" + packageName);
    742         mLog.trace("setWifiEnabled package=% uid=% enable=%").c(packageName)
    743                 .c(Binder.getCallingUid()).c(enable).flush();
    744 
    745         // If SoftAp is enabled, only Settings is allowed to toggle wifi
    746         boolean apEnabled =
    747                 mWifiStateMachine.syncGetWifiApState() != WifiManager.WIFI_AP_STATE_DISABLED;
    748         boolean isFromSettings = checkNetworkSettingsPermission();
    749         if (apEnabled && !isFromSettings) {
    750             mLog.trace("setWifiEnabled SoftAp not disabled: only Settings can enable wifi").flush();
    751             return false;
    752         }
    753 
    754         /*
    755         * Caller might not have WRITE_SECURE_SETTINGS,
    756         * only CHANGE_WIFI_STATE is enforced
    757         */
    758         long ident = Binder.clearCallingIdentity();
    759         try {
    760             if (! mSettingsStore.handleWifiToggled(enable)) {
    761                 // Nothing to do if wifi cannot be toggled
    762                 return true;
    763             }
    764         } finally {
    765             Binder.restoreCallingIdentity(ident);
    766         }
    767 
    768 
    769         if (mPermissionReviewRequired) {
    770             final int wiFiEnabledState = getWifiEnabledState();
    771             if (enable) {
    772                 if (wiFiEnabledState == WifiManager.WIFI_STATE_DISABLING
    773                         || wiFiEnabledState == WifiManager.WIFI_STATE_DISABLED) {
    774                     if (startConsentUi(packageName, Binder.getCallingUid(),
    775                             WifiManager.ACTION_REQUEST_ENABLE)) {
    776                         return true;
    777                     }
    778                 }
    779             } else if (wiFiEnabledState == WifiManager.WIFI_STATE_ENABLING
    780                     || wiFiEnabledState == WifiManager.WIFI_STATE_ENABLED) {
    781                 if (startConsentUi(packageName, Binder.getCallingUid(),
    782                         WifiManager.ACTION_REQUEST_DISABLE)) {
    783                     return true;
    784                 }
    785             }
    786         }
    787 
    788         mWifiController.sendMessage(CMD_WIFI_TOGGLED);
    789         return true;
    790     }
    791 
    792     /**
    793      * see {@link WifiManager#getWifiState()}
    794      * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
    795      *         {@link WifiManager#WIFI_STATE_DISABLING},
    796      *         {@link WifiManager#WIFI_STATE_ENABLED},
    797      *         {@link WifiManager#WIFI_STATE_ENABLING},
    798      *         {@link WifiManager#WIFI_STATE_UNKNOWN}
    799      */
    800     @Override
    801     public int getWifiEnabledState() {
    802         enforceAccessPermission();
    803         mLog.trace("getWifiEnabledState uid=%").c(Binder.getCallingUid()).flush();
    804         return mWifiStateMachine.syncGetWifiState();
    805     }
    806 
    807     /**
    808      * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
    809      * @param wifiConfig SSID, security and channel details as
    810      *        part of WifiConfiguration
    811      * @param enabled true to enable and false to disable
    812      */
    813     @Override
    814     public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
    815         enforceChangePermission();
    816         mWifiPermissionsUtil.enforceTetherChangePermission(mContext);
    817 
    818         mLog.trace("setWifiApEnabled uid=% enable=%").c(Binder.getCallingUid()).c(enabled).flush();
    819 
    820         if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
    821             throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user.");
    822         }
    823         // null wifiConfig is a meaningful input for CMD_SET_AP
    824         if (wifiConfig == null || isValid(wifiConfig)) {
    825             int mode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
    826             SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
    827             mWifiController.sendMessage(CMD_SET_AP, enabled ? 1 : 0, 0, softApConfig);
    828         } else {
    829             Slog.e(TAG, "Invalid WifiConfiguration");
    830         }
    831     }
    832 
    833     /**
    834      * see {@link WifiManager#getWifiApState()}
    835      * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
    836      *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
    837      *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
    838      *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
    839      *         {@link WifiManager#WIFI_AP_STATE_FAILED}
    840      */
    841     @Override
    842     public int getWifiApEnabledState() {
    843         enforceAccessPermission();
    844         mLog.trace("getWifiApEnabledState uid=%").c(Binder.getCallingUid()).flush();
    845         return mWifiStateMachine.syncGetWifiApState();
    846     }
    847 
    848     /**
    849      * see {@link android.net.wifi.WifiManager#updateInterfaceIpState(String, int)}
    850      *
    851      * The possible modes include: {@link WifiManager#IFACE_IP_MODE_TETHERED},
    852      *                             {@link WifiManager#IFACE_IP_MODE_LOCAL_ONLY},
    853      *                             {@link WifiManager#IFACE_IP_MODE_CONFIGURATION_ERROR}
    854      *
    855      * @param ifaceName String name of the updated interface
    856      * @param mode new operating mode of the interface
    857      *
    858      * @throws SecurityException if the caller does not have permission to call update
    859      */
    860     @Override
    861     public void updateInterfaceIpState(String ifaceName, int mode) {
    862         // NETWORK_STACK is a signature only permission.
    863         enforceNetworkStackPermission();
    864 
    865         // hand off the work to our handler thread
    866         mClientHandler.post(() -> {
    867             updateInterfaceIpStateInternal(ifaceName, mode);
    868         });
    869     }
    870 
    871     private void updateInterfaceIpStateInternal(String ifaceName, int mode) {
    872         // update interface IP state related to tethering and hotspot
    873         synchronized (mLocalOnlyHotspotRequests) {
    874             // update the mode tracker here - we clear out state below
    875             Integer previousMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
    876             if (ifaceName != null) {
    877                 previousMode = mIfaceIpModes.put(ifaceName, mode);
    878             }
    879             Slog.d(TAG, "updateInterfaceIpState: ifaceName=" + ifaceName + " mode=" + mode
    880                     + " previous mode= " + previousMode);
    881 
    882             switch (mode) {
    883                 case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
    884                     // first make sure we have registered requests..  otherwise clean up
    885                     if (mLocalOnlyHotspotRequests.isEmpty()) {
    886                         // we don't have requests...  stop the hotspot
    887                         stopSoftAp();
    888                         updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
    889                         return;
    890                     }
    891                     // LOHS is ready to go!  Call our registered requestors!
    892                     sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked();
    893                     break;
    894                 case WifiManager.IFACE_IP_MODE_TETHERED:
    895                     // we have tethered an interface. we don't really act on this now other than if
    896                     // we have LOHS requests, and this is an issue.  return incompatible mode for
    897                     // onFailed for the registered requestors since this can result from a race
    898                     // between a tether request and a hotspot request (tethering wins).
    899                     sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
    900                             LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE);
    901                     break;
    902                 case WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR:
    903                     // there was an error setting up the hotspot...  trigger onFailed for the
    904                     // registered LOHS requestors
    905                     sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
    906                             LocalOnlyHotspotCallback.ERROR_GENERIC);
    907                     updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
    908                     break;
    909                 case WifiManager.IFACE_IP_MODE_UNSPECIFIED:
    910                     if (ifaceName == null) {
    911                         // interface name is null, this is due to softap teardown.  clear all
    912                         // entries for now.
    913                         // TODO: Deal with individual interfaces when we receive updates for them
    914                         mIfaceIpModes.clear();
    915                         return;
    916                     }
    917                     break;
    918                 default:
    919                     mLog.trace("updateInterfaceIpStateInternal: unknown mode %").c(mode).flush();
    920             }
    921         }
    922     }
    923 
    924     /**
    925      * see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)}
    926      * @param wifiConfig SSID, security and channel details as part of WifiConfiguration
    927      * @return {@code true} if softap start was triggered
    928      * @throws SecurityException if the caller does not have permission to start softap
    929      */
    930     @Override
    931     public boolean startSoftAp(WifiConfiguration wifiConfig) {
    932         // NETWORK_STACK is a signature only permission.
    933         enforceNetworkStackPermission();
    934 
    935         mLog.trace("startSoftAp uid=%").c(Binder.getCallingUid()).flush();
    936 
    937         synchronized (mLocalOnlyHotspotRequests) {
    938             // If a tethering request comes in while we have LOHS running (or requested), call stop
    939             // for softap mode and restart softap with the tethering config.
    940             if (!mLocalOnlyHotspotRequests.isEmpty()) {
    941                 stopSoftApInternal();
    942             }
    943 
    944             return startSoftApInternal(wifiConfig, WifiManager.IFACE_IP_MODE_TETHERED);
    945         }
    946     }
    947 
    948     /**
    949      * Internal method to start softap mode. Callers of this method should have already checked
    950      * proper permissions beyond the NetworkStack permission.
    951      */
    952     private boolean startSoftApInternal(WifiConfiguration wifiConfig, int mode) {
    953         mLog.trace("startSoftApInternal uid=% mode=%")
    954                 .c(Binder.getCallingUid()).c(mode).flush();
    955 
    956         // null wifiConfig is a meaningful input for CMD_SET_AP
    957         if (wifiConfig == null || isValid(wifiConfig)) {
    958             SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
    959             mWifiController.sendMessage(CMD_SET_AP, 1, 0, softApConfig);
    960             return true;
    961         }
    962         Slog.e(TAG, "Invalid WifiConfiguration");
    963         return false;
    964     }
    965 
    966     /**
    967      * see {@link android.net.wifi.WifiManager#stopSoftAp()}
    968      * @return {@code true} if softap stop was triggered
    969      * @throws SecurityException if the caller does not have permission to stop softap
    970      */
    971     @Override
    972     public boolean stopSoftAp() {
    973         // NETWORK_STACK is a signature only permission.
    974         enforceNetworkStackPermission();
    975 
    976         // only permitted callers are allowed to this point - they must have gone through
    977         // connectivity service since this method is protected with the NETWORK_STACK PERMISSION
    978 
    979         mLog.trace("stopSoftAp uid=%").c(Binder.getCallingUid()).flush();
    980 
    981         synchronized (mLocalOnlyHotspotRequests) {
    982             // If a tethering request comes in while we have LOHS running (or requested), call stop
    983             // for softap mode and restart softap with the tethering config.
    984             if (!mLocalOnlyHotspotRequests.isEmpty()) {
    985                 mLog.trace("Call to stop Tethering while LOHS is active,"
    986                         + " Registered LOHS callers will be updated when softap stopped.");
    987             }
    988 
    989             return stopSoftApInternal();
    990         }
    991     }
    992 
    993     /**
    994      * Internal method to stop softap mode.  Callers of this method should have already checked
    995      * proper permissions beyond the NetworkStack permission.
    996      */
    997     private boolean stopSoftApInternal() {
    998         mLog.trace("stopSoftApInternal uid=%").c(Binder.getCallingUid()).flush();
    999 
   1000         mWifiController.sendMessage(CMD_SET_AP, 0, 0);
   1001         return true;
   1002     }
   1003 
   1004     /**
   1005      * Private method to handle SoftAp state changes
   1006      */
   1007     private void handleWifiApStateChange(
   1008             int currentState, int previousState, int errorCode, String ifaceName, int mode) {
   1009         // The AP state update from WifiStateMachine for softap
   1010         Slog.d(TAG, "handleWifiApStateChange: currentState=" + currentState
   1011                 + " previousState=" + previousState + " errorCode= " + errorCode
   1012                 + " ifaceName=" + ifaceName + " mode=" + mode);
   1013 
   1014         // check if we have a failure - since it is possible (worst case scenario where
   1015         // WifiController and WifiStateMachine are out of sync wrt modes) to get two FAILED
   1016         // notifications in a row, we need to handle this first.
   1017         if (currentState == WIFI_AP_STATE_FAILED) {
   1018             // update registered LOHS callbacks if we see a failure
   1019             synchronized (mLocalOnlyHotspotRequests) {
   1020                 int errorToReport = ERROR_GENERIC;
   1021                 if (errorCode == SAP_START_FAILURE_NO_CHANNEL) {
   1022                     errorToReport = ERROR_NO_CHANNEL;
   1023                 }
   1024                 // holding the required lock: send message to requestors and clear the list
   1025                 sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
   1026                         errorToReport);
   1027                 // also need to clear interface ip state - send null for now since we don't know
   1028                 // what interface (and we have one anyway)
   1029                 updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
   1030             }
   1031             return;
   1032         }
   1033 
   1034         if (currentState == WIFI_AP_STATE_DISABLING || currentState == WIFI_AP_STATE_DISABLED) {
   1035             // softap is shutting down or is down...  let requestors know via the onStopped call
   1036             synchronized (mLocalOnlyHotspotRequests) {
   1037                 // if we are currently in hotspot mode, then trigger onStopped for registered
   1038                 // requestors, otherwise something odd happened and we should clear state
   1039                 if (mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_LOCAL_ONLY)) {
   1040                     // holding the required lock: send message to requestors and clear the list
   1041                     sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked();
   1042                 } else {
   1043                     // LOHS not active: report an error (still holding the required lock)
   1044                     sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(ERROR_GENERIC);
   1045                 }
   1046                 // also clear interface ip state - send null for now since we don't know what
   1047                 // interface (and we only have one anyway)
   1048                 updateInterfaceIpState(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
   1049             }
   1050             return;
   1051         }
   1052 
   1053         // remaining states are enabling or enabled...  those are not used for the callbacks
   1054     }
   1055 
   1056     /**
   1057      * Helper method to send a HOTSPOT_FAILED message to all registered LocalOnlyHotspotRequest
   1058      * callers and clear the registrations.
   1059      *
   1060      * Callers should already hold the mLocalOnlyHotspotRequests lock.
   1061      */
   1062     private void sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(int arg1) {
   1063         for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
   1064             try {
   1065                 requestor.sendHotspotFailedMessage(arg1);
   1066                 requestor.unlinkDeathRecipient();
   1067             } catch (RemoteException e) {
   1068                 // This will be cleaned up by binder death handling
   1069             }
   1070         }
   1071 
   1072         // Since all callers were notified, now clear the registrations.
   1073         mLocalOnlyHotspotRequests.clear();
   1074     }
   1075 
   1076     /**
   1077      * Helper method to send a HOTSPOT_STOPPED message to all registered LocalOnlyHotspotRequest
   1078      * callers and clear the registrations.
   1079      *
   1080      * Callers should already hold the mLocalOnlyHotspotRequests lock.
   1081      */
   1082     private void sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked() {
   1083         for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
   1084             try {
   1085                 requestor.sendHotspotStoppedMessage();
   1086                 requestor.unlinkDeathRecipient();
   1087             } catch (RemoteException e) {
   1088                 // This will be cleaned up by binder death handling
   1089             }
   1090         }
   1091 
   1092         // Since all callers were notified, now clear the registrations.
   1093         mLocalOnlyHotspotRequests.clear();
   1094     }
   1095 
   1096     /**
   1097      * Helper method to send a HOTSPOT_STARTED message to all registered LocalOnlyHotspotRequest
   1098      * callers.
   1099      *
   1100      * Callers should already hold the mLocalOnlyHotspotRequests lock.
   1101      */
   1102     private void sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked() {
   1103         for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
   1104             try {
   1105                 requestor.sendHotspotStartedMessage(mLocalOnlyHotspotConfig);
   1106             } catch (RemoteException e) {
   1107                 // This will be cleaned up by binder death handling
   1108             }
   1109         }
   1110     }
   1111 
   1112     /**
   1113      * Temporary method used for testing while startLocalOnlyHotspot is not fully implemented.  This
   1114      * method allows unit tests to register callbacks directly for testing mechanisms triggered by
   1115      * softap mode changes.
   1116      */
   1117     @VisibleForTesting
   1118     void registerLOHSForTest(int pid, LocalOnlyHotspotRequestInfo request) {
   1119         mLocalOnlyHotspotRequests.put(pid, request);
   1120     }
   1121 
   1122     /**
   1123      * Method to start LocalOnlyHotspot.  In this method, permissions, settings and modes are
   1124      * checked to verify that we can enter softapmode.  This method returns
   1125      * {@link LocalOnlyHotspotCallback#REQUEST_REGISTERED} if we will attempt to start, otherwise,
   1126      * possible startup erros may include tethering being disallowed failure reason {@link
   1127      * LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED} or an incompatible mode failure reason
   1128      * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE}.
   1129      *
   1130      * see {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback)}
   1131      *
   1132      * @param messenger Messenger to send messages to the corresponding WifiManager.
   1133      * @param binder IBinder instance to allow cleanup if the app dies
   1134      * @param packageName String name of the calling package
   1135      *
   1136      * @return int return code for attempt to start LocalOnlyHotspot.
   1137      *
   1138      * @throws SecurityException if the caller does not have permission to start a Local Only
   1139      * Hotspot.
   1140      * @throws IllegalStateException if the caller attempts to start the LocalOnlyHotspot while they
   1141      * have an outstanding request.
   1142      */
   1143     @Override
   1144     public int startLocalOnlyHotspot(Messenger messenger, IBinder binder, String packageName) {
   1145         // first check if the caller has permission to start a local only hotspot
   1146         // need to check for WIFI_STATE_CHANGE and location permission
   1147         final int uid = Binder.getCallingUid();
   1148         final int pid = Binder.getCallingPid();
   1149 
   1150         enforceChangePermission();
   1151         enforceLocationPermission(packageName, uid);
   1152         // also need to verify that Locations services are enabled.
   1153         if (mSettingsStore.getLocationModeSetting(mContext) == Settings.Secure.LOCATION_MODE_OFF) {
   1154             throw new SecurityException("Location mode is not enabled.");
   1155         }
   1156 
   1157         // verify that tethering is not disabled
   1158         if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
   1159             return LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED;
   1160         }
   1161 
   1162         // the app should be in the foreground
   1163         try {
   1164             if (!mFrameworkFacade.isAppForeground(uid)) {
   1165                 return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
   1166             }
   1167         } catch (RemoteException e) {
   1168             mLog.trace("RemoteException during isAppForeground when calling startLOHS");
   1169             return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
   1170         }
   1171 
   1172         mLog.trace("startLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush();
   1173 
   1174         synchronized (mLocalOnlyHotspotRequests) {
   1175             // check if we are currently tethering
   1176             if (mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_TETHERED)) {
   1177                 // Tethering is enabled, cannot start LocalOnlyHotspot
   1178                 mLog.trace("Cannot start localOnlyHotspot when WiFi Tethering is active.");
   1179                 return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
   1180             }
   1181 
   1182             // does this caller already have a request?
   1183             LocalOnlyHotspotRequestInfo request = mLocalOnlyHotspotRequests.get(pid);
   1184             if (request != null) {
   1185                 mLog.trace("caller already has an active request");
   1186                 throw new IllegalStateException(
   1187                         "Caller already has an active LocalOnlyHotspot request");
   1188             }
   1189 
   1190             // now create the new LOHS request info object
   1191             request = new LocalOnlyHotspotRequestInfo(binder, messenger,
   1192                     new LocalOnlyRequestorCallback());
   1193 
   1194             // check current operating state and take action if needed
   1195             if (mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_LOCAL_ONLY)) {
   1196                 // LOHS is already active, send out what is running
   1197                 try {
   1198                     mLog.trace("LOHS already up, trigger onStarted callback");
   1199                     request.sendHotspotStartedMessage(mLocalOnlyHotspotConfig);
   1200                 } catch (RemoteException e) {
   1201                     return LocalOnlyHotspotCallback.ERROR_GENERIC;
   1202                 }
   1203             } else if (mLocalOnlyHotspotRequests.isEmpty()) {
   1204                 // this is the first request, then set up our config and start LOHS
   1205                 mLocalOnlyHotspotConfig =
   1206                         WifiApConfigStore.generateLocalOnlyHotspotConfig(mContext);
   1207                 startSoftApInternal(mLocalOnlyHotspotConfig, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
   1208             }
   1209 
   1210             mLocalOnlyHotspotRequests.put(pid, request);
   1211             return LocalOnlyHotspotCallback.REQUEST_REGISTERED;
   1212         }
   1213     }
   1214 
   1215     /**
   1216      * see {@link WifiManager#stopLocalOnlyHotspot()}
   1217      *
   1218      * @throws SecurityException if the caller does not have permission to stop a Local Only
   1219      * Hotspot.
   1220      */
   1221     @Override
   1222     public void stopLocalOnlyHotspot() {
   1223         // first check if the caller has permission to stop a local only hotspot
   1224         enforceChangePermission();
   1225         final int uid = Binder.getCallingUid();
   1226         final int pid = Binder.getCallingPid();
   1227 
   1228         mLog.trace("stopLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush();
   1229 
   1230         synchronized (mLocalOnlyHotspotRequests) {
   1231             // was the caller already registered?  check request tracker - return false if not
   1232             LocalOnlyHotspotRequestInfo requestInfo = mLocalOnlyHotspotRequests.get(pid);
   1233             if (requestInfo == null) {
   1234                 return;
   1235             }
   1236             requestInfo.unlinkDeathRecipient();
   1237             unregisterCallingAppAndStopLocalOnlyHotspot(requestInfo);
   1238         } // end synchronized
   1239     }
   1240 
   1241     /**
   1242      * Helper method to unregister LocalOnlyHotspot requestors and stop the hotspot if needed.
   1243      */
   1244     private void unregisterCallingAppAndStopLocalOnlyHotspot(LocalOnlyHotspotRequestInfo request) {
   1245         mLog.trace("unregisterCallingAppAndStopLocalOnlyHotspot pid=%").c(request.getPid()).flush();
   1246 
   1247         synchronized (mLocalOnlyHotspotRequests) {
   1248             if (mLocalOnlyHotspotRequests.remove(request.getPid()) == null) {
   1249                 mLog.trace("LocalOnlyHotspotRequestInfo not found to remove");
   1250                 return;
   1251             }
   1252 
   1253             if (mLocalOnlyHotspotRequests.isEmpty()) {
   1254                 mLocalOnlyHotspotConfig = null;
   1255                 updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
   1256                 // if that was the last caller, then call stopSoftAp as WifiService
   1257                 long identity = Binder.clearCallingIdentity();
   1258                 try {
   1259                     stopSoftApInternal();
   1260                 } finally {
   1261                     Binder.restoreCallingIdentity(identity);
   1262                 }
   1263             }
   1264         }
   1265     }
   1266 
   1267     /**
   1268      * see {@link WifiManager#watchLocalOnlyHotspot(LocalOnlyHotspotObserver)}
   1269      *
   1270      * This call requires the android.permission.NETWORK_SETTINGS permission.
   1271      *
   1272      * @param messenger Messenger to send messages to the corresponding WifiManager.
   1273      * @param binder IBinder instance to allow cleanup if the app dies
   1274      *
   1275      * @throws SecurityException if the caller does not have permission to watch Local Only Hotspot
   1276      * status updates.
   1277      * @throws IllegalStateException if the caller attempts to watch LocalOnlyHotspot updates with
   1278      * an existing subscription.
   1279      */
   1280     @Override
   1281     public void startWatchLocalOnlyHotspot(Messenger messenger, IBinder binder) {
   1282         final String packageName = mContext.getOpPackageName();
   1283 
   1284         // NETWORK_SETTINGS is a signature only permission.
   1285         enforceNetworkSettingsPermission();
   1286 
   1287         throw new UnsupportedOperationException("LocalOnlyHotspot is still in development");
   1288     }
   1289 
   1290     /**
   1291      * see {@link WifiManager#unregisterLocalOnlyHotspotObserver()}
   1292      */
   1293     @Override
   1294     public void stopWatchLocalOnlyHotspot() {
   1295         // NETWORK_STACK is a signature only permission.
   1296         enforceNetworkSettingsPermission();
   1297         throw new UnsupportedOperationException("LocalOnlyHotspot is still in development");
   1298     }
   1299 
   1300     /**
   1301      * see {@link WifiManager#getWifiApConfiguration()}
   1302      * @return soft access point configuration
   1303      * @throws SecurityException if the caller does not have permission to retrieve the softap
   1304      * config
   1305      */
   1306     @Override
   1307     public WifiConfiguration getWifiApConfiguration() {
   1308         enforceAccessPermission();
   1309         int uid = Binder.getCallingUid();
   1310         // only allow Settings UI to get the saved SoftApConfig
   1311         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {
   1312             // random apps should not be allowed to read the user specified config
   1313             throw new SecurityException("App not allowed to read or update stored WiFi Ap config "
   1314                     + "(uid = " + uid + ")");
   1315         }
   1316         mLog.trace("getWifiApConfiguration uid=%").c(uid).flush();
   1317         return mWifiStateMachine.syncGetWifiApConfiguration();
   1318     }
   1319 
   1320     /**
   1321      * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
   1322      * @param wifiConfig WifiConfiguration details for soft access point
   1323      * @throws SecurityException if the caller does not have permission to write the sotap config
   1324      */
   1325     @Override
   1326     public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
   1327         enforceChangePermission();
   1328         int uid = Binder.getCallingUid();
   1329         // only allow Settings UI to write the stored SoftApConfig
   1330         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {
   1331             // random apps should not be allowed to read the user specified config
   1332             throw new SecurityException("App not allowed to read or update stored WiFi AP config "
   1333                     + "(uid = " + uid + ")");
   1334         }
   1335         mLog.trace("setWifiApConfiguration uid=%").c(uid).flush();
   1336         if (wifiConfig == null)
   1337             return;
   1338         if (isValid(wifiConfig)) {
   1339             mWifiStateMachine.setWifiApConfiguration(wifiConfig);
   1340         } else {
   1341             Slog.e(TAG, "Invalid WifiConfiguration");
   1342         }
   1343     }
   1344 
   1345     /**
   1346      * see {@link android.net.wifi.WifiManager#isScanAlwaysAvailable()}
   1347      */
   1348     @Override
   1349     public boolean isScanAlwaysAvailable() {
   1350         enforceAccessPermission();
   1351         mLog.trace("isScanAlwaysAvailable uid=%").c(Binder.getCallingUid()).flush();
   1352         return mSettingsStore.isScanAlwaysAvailable();
   1353     }
   1354 
   1355     /**
   1356      * see {@link android.net.wifi.WifiManager#disconnect()}
   1357      */
   1358     @Override
   1359     public void disconnect() {
   1360         enforceChangePermission();
   1361         mLog.trace("disconnect uid=%").c(Binder.getCallingUid()).flush();
   1362         mWifiStateMachine.disconnectCommand();
   1363     }
   1364 
   1365     /**
   1366      * see {@link android.net.wifi.WifiManager#reconnect()}
   1367      */
   1368     @Override
   1369     public void reconnect() {
   1370         enforceChangePermission();
   1371         mLog.trace("reconnect uid=%").c(Binder.getCallingUid()).flush();
   1372         mWifiStateMachine.reconnectCommand();
   1373     }
   1374 
   1375     /**
   1376      * see {@link android.net.wifi.WifiManager#reassociate()}
   1377      */
   1378     @Override
   1379     public void reassociate() {
   1380         enforceChangePermission();
   1381         mLog.trace("reassociate uid=%").c(Binder.getCallingUid()).flush();
   1382         mWifiStateMachine.reassociateCommand();
   1383     }
   1384 
   1385     /**
   1386      * see {@link android.net.wifi.WifiManager#getSupportedFeatures}
   1387      */
   1388     @Override
   1389     public int getSupportedFeatures() {
   1390         enforceAccessPermission();
   1391         mLog.trace("getSupportedFeatures uid=%").c(Binder.getCallingUid()).flush();
   1392         if (mWifiStateMachineChannel != null) {
   1393             return mWifiStateMachine.syncGetSupportedFeatures(mWifiStateMachineChannel);
   1394         } else {
   1395             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
   1396             return 0;
   1397         }
   1398     }
   1399 
   1400     @Override
   1401     public void requestActivityInfo(ResultReceiver result) {
   1402         Bundle bundle = new Bundle();
   1403         mLog.trace("requestActivityInfo uid=%").c(Binder.getCallingUid()).flush();
   1404         bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, reportActivityInfo());
   1405         result.send(0, bundle);
   1406     }
   1407 
   1408     /**
   1409      * see {@link android.net.wifi.WifiManager#getControllerActivityEnergyInfo(int)}
   1410      */
   1411     @Override
   1412     public WifiActivityEnergyInfo reportActivityInfo() {
   1413         enforceAccessPermission();
   1414         mLog.trace("reportActivityInfo uid=%").c(Binder.getCallingUid()).flush();
   1415         if ((getSupportedFeatures() & WifiManager.WIFI_FEATURE_LINK_LAYER_STATS) == 0) {
   1416             return null;
   1417         }
   1418         WifiLinkLayerStats stats;
   1419         WifiActivityEnergyInfo energyInfo = null;
   1420         if (mWifiStateMachineChannel != null) {
   1421             stats = mWifiStateMachine.syncGetLinkLayerStats(mWifiStateMachineChannel);
   1422             if (stats != null) {
   1423                 final long rxIdleCurrent = mContext.getResources().getInteger(
   1424                         com.android.internal.R.integer.config_wifi_idle_receive_cur_ma);
   1425                 final long rxCurrent = mContext.getResources().getInteger(
   1426                         com.android.internal.R.integer.config_wifi_active_rx_cur_ma);
   1427                 final long txCurrent = mContext.getResources().getInteger(
   1428                         com.android.internal.R.integer.config_wifi_tx_cur_ma);
   1429                 final double voltage = mContext.getResources().getInteger(
   1430                         com.android.internal.R.integer.config_wifi_operating_voltage_mv)
   1431                         / 1000.0;
   1432 
   1433                 final long rxIdleTime = stats.on_time - stats.tx_time - stats.rx_time;
   1434                 final long[] txTimePerLevel;
   1435                 if (stats.tx_time_per_level != null) {
   1436                     txTimePerLevel = new long[stats.tx_time_per_level.length];
   1437                     for (int i = 0; i < txTimePerLevel.length; i++) {
   1438                         txTimePerLevel[i] = stats.tx_time_per_level[i];
   1439                         // TODO(b/27227497): Need to read the power consumed per level from config
   1440                     }
   1441                 } else {
   1442                     // This will happen if the HAL get link layer API returned null.
   1443                     txTimePerLevel = new long[0];
   1444                 }
   1445                 final long energyUsed = (long)((stats.tx_time * txCurrent +
   1446                         stats.rx_time * rxCurrent +
   1447                         rxIdleTime * rxIdleCurrent) * voltage);
   1448                 if (VDBG || rxIdleTime < 0 || stats.on_time < 0 || stats.tx_time < 0 ||
   1449                         stats.rx_time < 0 || energyUsed < 0) {
   1450                     StringBuilder sb = new StringBuilder();
   1451                     sb.append(" rxIdleCur=" + rxIdleCurrent);
   1452                     sb.append(" rxCur=" + rxCurrent);
   1453                     sb.append(" txCur=" + txCurrent);
   1454                     sb.append(" voltage=" + voltage);
   1455                     sb.append(" on_time=" + stats.on_time);
   1456                     sb.append(" tx_time=" + stats.tx_time);
   1457                     sb.append(" tx_time_per_level=" + Arrays.toString(txTimePerLevel));
   1458                     sb.append(" rx_time=" + stats.rx_time);
   1459                     sb.append(" rxIdleTime=" + rxIdleTime);
   1460                     sb.append(" energy=" + energyUsed);
   1461                     Log.d(TAG, " reportActivityInfo: " + sb.toString());
   1462                 }
   1463 
   1464                 // Convert the LinkLayerStats into EnergyActivity
   1465                 energyInfo = new WifiActivityEnergyInfo(mClock.getElapsedSinceBootMillis(),
   1466                         WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE, stats.tx_time,
   1467                         txTimePerLevel, stats.rx_time, rxIdleTime, energyUsed);
   1468             }
   1469             if (energyInfo != null && energyInfo.isValid()) {
   1470                 return energyInfo;
   1471             } else {
   1472                 return null;
   1473             }
   1474         } else {
   1475             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
   1476             return null;
   1477         }
   1478     }
   1479 
   1480     /**
   1481      * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
   1482      * @return the list of configured networks
   1483      */
   1484     @Override
   1485     public ParceledListSlice<WifiConfiguration> getConfiguredNetworks() {
   1486         enforceAccessPermission();
   1487         mLog.trace("getConfiguredNetworks uid=%").c(Binder.getCallingUid()).flush();
   1488         if (mWifiStateMachineChannel != null) {
   1489             List<WifiConfiguration> configs = mWifiStateMachine.syncGetConfiguredNetworks(
   1490                     Binder.getCallingUid(), mWifiStateMachineChannel);
   1491             if (configs != null) {
   1492                 return new ParceledListSlice<WifiConfiguration>(configs);
   1493             }
   1494         } else {
   1495             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
   1496         }
   1497         return null;
   1498     }
   1499 
   1500     /**
   1501      * see {@link android.net.wifi.WifiManager#getPrivilegedConfiguredNetworks()}
   1502      * @return the list of configured networks with real preSharedKey
   1503      */
   1504     @Override
   1505     public ParceledListSlice<WifiConfiguration> getPrivilegedConfiguredNetworks() {
   1506         enforceReadCredentialPermission();
   1507         enforceAccessPermission();
   1508         mLog.trace("getPrivilegedConfiguredNetworks uid=%").c(Binder.getCallingUid()).flush();
   1509         if (mWifiStateMachineChannel != null) {
   1510             List<WifiConfiguration> configs =
   1511                     mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel);
   1512             if (configs != null) {
   1513                 return new ParceledListSlice<WifiConfiguration>(configs);
   1514             }
   1515         } else {
   1516             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
   1517         }
   1518         return null;
   1519     }
   1520 
   1521     /**
   1522      * Returns a WifiConfiguration for a Passpoint network matching this ScanResult.
   1523      *
   1524      * @param scanResult scanResult that represents the BSSID
   1525      * @return {@link WifiConfiguration} that matches this BSSID or null
   1526      */
   1527     @Override
   1528     public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) {
   1529         enforceAccessPermission();
   1530         mLog.trace("getMatchingWifiConfig uid=%").c(Binder.getCallingUid()).flush();
   1531         if (!mContext.getResources().getBoolean(
   1532                 com.android.internal.R.bool.config_wifi_hotspot2_enabled)) {
   1533             throw new UnsupportedOperationException("Passpoint not enabled");
   1534         }
   1535         return mWifiStateMachine.syncGetMatchingWifiConfig(scanResult, mWifiStateMachineChannel);
   1536     }
   1537 
   1538     /**
   1539      * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
   1540      * @return the supplicant-assigned identifier for the new or updated
   1541      * network if the operation succeeds, or {@code -1} if it fails
   1542      */
   1543     @Override
   1544     public int addOrUpdateNetwork(WifiConfiguration config) {
   1545         enforceChangePermission();
   1546         mLog.trace("addOrUpdateNetwork uid=%").c(Binder.getCallingUid()).flush();
   1547 
   1548         // Previously, this API is overloaded for installing Passpoint profiles.  Now
   1549         // that we have a dedicated API for doing it, redirect the call to the dedicated API.
   1550         if (config.isPasspoint()) {
   1551             PasspointConfiguration passpointConfig =
   1552                     PasspointProvider.convertFromWifiConfig(config);
   1553             if (passpointConfig.getCredential() == null) {
   1554                 Slog.e(TAG, "Missing credential for Passpoint profile");
   1555                 return -1;
   1556             }
   1557             // Copy over certificates and keys.
   1558             passpointConfig.getCredential().setCaCertificate(
   1559                     config.enterpriseConfig.getCaCertificate());
   1560             passpointConfig.getCredential().setClientCertificateChain(
   1561                     config.enterpriseConfig.getClientCertificateChain());
   1562             passpointConfig.getCredential().setClientPrivateKey(
   1563                     config.enterpriseConfig.getClientPrivateKey());
   1564             if (!addOrUpdatePasspointConfiguration(passpointConfig)) {
   1565                 Slog.e(TAG, "Failed to add Passpoint profile");
   1566                 return -1;
   1567             }
   1568             // There is no network ID associated with a Passpoint profile.
   1569             return 0;
   1570         }
   1571 
   1572         if (isValid(config)) {
   1573             //TODO: pass the Uid the WifiStateMachine as a message parameter
   1574             Slog.i("addOrUpdateNetwork", " uid = " + Integer.toString(Binder.getCallingUid())
   1575                     + " SSID " + config.SSID
   1576                     + " nid=" + Integer.toString(config.networkId));
   1577             if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
   1578                 config.creatorUid = Binder.getCallingUid();
   1579             } else {
   1580                 config.lastUpdateUid = Binder.getCallingUid();
   1581             }
   1582             if (mWifiStateMachineChannel != null) {
   1583                 return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
   1584             } else {
   1585                 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
   1586                 return -1;
   1587             }
   1588         } else {
   1589             Slog.e(TAG, "bad network configuration");
   1590             return -1;
   1591         }
   1592     }
   1593 
   1594     public static void verifyCert(X509Certificate caCert)
   1595             throws GeneralSecurityException, IOException {
   1596         CertificateFactory factory = CertificateFactory.getInstance("X.509");
   1597         CertPathValidator validator =
   1598                 CertPathValidator.getInstance(CertPathValidator.getDefaultType());
   1599         CertPath path = factory.generateCertPath(
   1600                 Arrays.asList(caCert));
   1601         KeyStore ks = KeyStore.getInstance("AndroidCAStore");
   1602         ks.load(null, null);
   1603         PKIXParameters params = new PKIXParameters(ks);
   1604         params.setRevocationEnabled(false);
   1605         validator.validate(path, params);
   1606     }
   1607 
   1608     /**
   1609      * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
   1610      * @param netId the integer that identifies the network configuration
   1611      * to the supplicant
   1612      * @return {@code true} if the operation succeeded
   1613      */
   1614     @Override
   1615     public boolean removeNetwork(int netId) {
   1616         enforceChangePermission();
   1617         mLog.trace("removeNetwork uid=%").c(Binder.getCallingUid()).flush();
   1618         // TODO Add private logging for netId b/33807876
   1619         if (mWifiStateMachineChannel != null) {
   1620             return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
   1621         } else {
   1622             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
   1623             return false;
   1624         }
   1625     }
   1626 
   1627     /**
   1628      * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
   1629      * @param netId the integer that identifies the network configuration
   1630      * to the supplicant
   1631      * @param disableOthers if true, disable all other networks.
   1632      * @return {@code true} if the operation succeeded
   1633      */
   1634     @Override
   1635     public boolean enableNetwork(int netId, boolean disableOthers) {
   1636         enforceChangePermission();
   1637         // TODO b/33807876 Log netId
   1638         mLog.trace("enableNetwork uid=% disableOthers=%")
   1639                 .c(Binder.getCallingUid())
   1640                 .c(disableOthers).flush();
   1641 
   1642         if (mWifiStateMachineChannel != null) {
   1643             return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
   1644                     disableOthers);
   1645         } else {
   1646             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
   1647             return false;
   1648         }
   1649     }
   1650 
   1651     /**
   1652      * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
   1653      * @param netId the integer that identifies the network configuration
   1654      * to the supplicant
   1655      * @return {@code true} if the operation succeeded
   1656      */
   1657     @Override
   1658     public boolean disableNetwork(int netId) {
   1659         enforceChangePermission();
   1660         // TODO b/33807876 Log netId
   1661         mLog.trace("disableNetwork uid=%").c(Binder.getCallingUid()).flush();
   1662 
   1663         if (mWifiStateMachineChannel != null) {
   1664             return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
   1665         } else {
   1666             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
   1667             return false;
   1668         }
   1669     }
   1670 
   1671     /**
   1672      * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
   1673      * @return the Wi-Fi information, contained in {@link WifiInfo}.
   1674      */
   1675     @Override
   1676     public WifiInfo getConnectionInfo() {
   1677         enforceAccessPermission();
   1678         mLog.trace("getConnectionInfo uid=%").c(Binder.getCallingUid()).flush();
   1679         /*
   1680          * Make sure we have the latest information, by sending
   1681          * a status request to the supplicant.
   1682          */
   1683         return mWifiStateMachine.syncRequestConnectionInfo();
   1684     }
   1685 
   1686     /**
   1687      * Return the results of the most recent access point scan, in the form of
   1688      * a list of {@link ScanResult} objects.
   1689      * @return the list of results
   1690      */
   1691     @Override
   1692     public List<ScanResult> getScanResults(String callingPackage) {
   1693         enforceAccessPermission();
   1694         int uid = Binder.getCallingUid();
   1695         long ident = Binder.clearCallingIdentity();
   1696         try {
   1697             if (!mWifiPermissionsUtil.canAccessScanResults(callingPackage,
   1698                       uid, Build.VERSION_CODES.M)) {
   1699                 return new ArrayList<ScanResult>();
   1700             }
   1701             if (mWifiScanner == null) {
   1702                 mWifiScanner = mWifiInjector.getWifiScanner();
   1703             }
   1704             return mWifiScanner.getSingleScanResults();
   1705         } finally {
   1706             Binder.restoreCallingIdentity(ident);
   1707         }
   1708     }
   1709 
   1710     /**
   1711      * Add or update a Passpoint configuration.
   1712      *
   1713      * @param config The Passpoint configuration to be added
   1714      * @return true on success or false on failure
   1715      */
   1716     @Override
   1717     public boolean addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
   1718         enforceChangePermission();
   1719         mLog.trace("addorUpdatePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush();
   1720         if (!mContext.getResources().getBoolean(
   1721                 com.android.internal.R.bool.config_wifi_hotspot2_enabled)) {
   1722             throw new UnsupportedOperationException("Passpoint not enabled");
   1723         }
   1724         return mWifiStateMachine.syncAddOrUpdatePasspointConfig(mWifiStateMachineChannel, config,
   1725                 Binder.getCallingUid());
   1726     }
   1727 
   1728     /**
   1729      * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
   1730      *
   1731      * @param fqdn The FQDN of the Passpoint configuration to be removed
   1732      * @return true on success or false on failure
   1733      */
   1734     @Override
   1735     public boolean removePasspointConfiguration(String fqdn) {
   1736         enforceChangePermission();
   1737         mLog.trace("removePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush();
   1738         if (!mContext.getResources().getBoolean(
   1739                 com.android.internal.R.bool.config_wifi_hotspot2_enabled)) {
   1740             throw new UnsupportedOperationException("Passpoint not enabled");
   1741         }
   1742         return mWifiStateMachine.syncRemovePasspointConfig(mWifiStateMachineChannel, fqdn);
   1743     }
   1744 
   1745     /**
   1746      * Return the list of the installed Passpoint configurations.
   1747      *
   1748      * An empty list will be returned when no configuration is installed.
   1749      *
   1750      * @return A list of {@link PasspointConfiguration}
   1751      */
   1752     @Override
   1753     public List<PasspointConfiguration> getPasspointConfigurations() {
   1754         enforceAccessPermission();
   1755         mLog.trace("getPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush();
   1756         if (!mContext.getResources().getBoolean(
   1757                 com.android.internal.R.bool.config_wifi_hotspot2_enabled)) {
   1758             throw new UnsupportedOperationException("Passpoint not enabled");
   1759         }
   1760         return mWifiStateMachine.syncGetPasspointConfigs(mWifiStateMachineChannel);
   1761     }
   1762 
   1763     /**
   1764      * Query for a Hotspot 2.0 release 2 OSU icon
   1765      * @param bssid The BSSID of the AP
   1766      * @param fileName Icon file name
   1767      */
   1768     @Override
   1769     public void queryPasspointIcon(long bssid, String fileName) {
   1770         enforceAccessPermission();
   1771         mLog.trace("queryPasspointIcon uid=%").c(Binder.getCallingUid()).flush();
   1772         if (!mContext.getResources().getBoolean(
   1773                 com.android.internal.R.bool.config_wifi_hotspot2_enabled)) {
   1774             throw new UnsupportedOperationException("Passpoint not enabled");
   1775         }
   1776         mWifiStateMachine.syncQueryPasspointIcon(mWifiStateMachineChannel, bssid, fileName);
   1777     }
   1778 
   1779     /**
   1780      * Match the currently associated network against the SP matching the given FQDN
   1781      * @param fqdn FQDN of the SP
   1782      * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
   1783      */
   1784     @Override
   1785     public int matchProviderWithCurrentNetwork(String fqdn) {
   1786         mLog.trace("matchProviderWithCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
   1787         return mWifiStateMachine.matchProviderWithCurrentNetwork(mWifiStateMachineChannel, fqdn);
   1788     }
   1789 
   1790     /**
   1791      * Deauthenticate and set the re-authentication hold off time for the current network
   1792      * @param holdoff hold off time in milliseconds
   1793      * @param ess set if the hold off pertains to an ESS rather than a BSS
   1794      */
   1795     @Override
   1796     public void deauthenticateNetwork(long holdoff, boolean ess) {
   1797         mLog.trace("deauthenticateNetwork uid=%").c(Binder.getCallingUid()).flush();
   1798         mWifiStateMachine.deauthenticateNetwork(mWifiStateMachineChannel, holdoff, ess);
   1799     }
   1800 
   1801     /**
   1802      * Tell the supplicant to persist the current list of configured networks.
   1803      * @return {@code true} if the operation succeeded
   1804      *
   1805      * TODO: deprecate this
   1806      */
   1807     @Override
   1808     public boolean saveConfiguration() {
   1809         enforceChangePermission();
   1810         mLog.trace("saveConfiguration uid=%").c(Binder.getCallingUid()).flush();
   1811         if (mWifiStateMachineChannel != null) {
   1812             return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
   1813         } else {
   1814             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
   1815             return false;
   1816         }
   1817     }
   1818 
   1819     /**
   1820      * Set the country code
   1821      * @param countryCode ISO 3166 country code.
   1822      * @param persist {@code true} if the setting should be remembered.
   1823      *
   1824      * The persist behavior exists so that wifi can fall back to the last
   1825      * persisted country code on a restart, when the locale information is
   1826      * not available from telephony.
   1827      */
   1828     @Override
   1829     public void setCountryCode(String countryCode, boolean persist) {
   1830         Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
   1831                 " with persist set to " + persist);
   1832         enforceConnectivityInternalPermission();
   1833         mLog.trace("setCountryCode uid=%").c(Binder.getCallingUid()).flush();
   1834         final long token = Binder.clearCallingIdentity();
   1835         mCountryCode.setCountryCode(countryCode);
   1836         Binder.restoreCallingIdentity(token);
   1837     }
   1838 
   1839      /**
   1840      * Get the country code
   1841      * @return Get the best choice country code for wifi, regardless of if it was set or
   1842      * not.
   1843      * Returns null when there is no country code available.
   1844      */
   1845     @Override
   1846     public String getCountryCode() {
   1847         enforceConnectivityInternalPermission();
   1848         mLog.trace("getCountryCode uid=%").c(Binder.getCallingUid()).flush();
   1849         String country = mCountryCode.getCountryCode();
   1850         return country;
   1851     }
   1852 
   1853     @Override
   1854     public boolean isDualBandSupported() {
   1855         //TODO: Should move towards adding a driver API that checks at runtime
   1856         mLog.trace("isDualBandSupported uid=%").c(Binder.getCallingUid()).flush();
   1857         return mContext.getResources().getBoolean(
   1858                 com.android.internal.R.bool.config_wifi_dual_band_support);
   1859     }
   1860 
   1861     /**
   1862      * Return the DHCP-assigned addresses from the last successful DHCP request,
   1863      * if any.
   1864      * @return the DHCP information
   1865      * @deprecated
   1866      */
   1867     @Override
   1868     @Deprecated
   1869     public DhcpInfo getDhcpInfo() {
   1870         enforceAccessPermission();
   1871         mLog.trace("getDhcpInfo uid=%").c(Binder.getCallingUid()).flush();
   1872         DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults();
   1873 
   1874         DhcpInfo info = new DhcpInfo();
   1875 
   1876         if (dhcpResults.ipAddress != null &&
   1877                 dhcpResults.ipAddress.getAddress() instanceof Inet4Address) {
   1878             info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.ipAddress.getAddress());
   1879         }
   1880 
   1881         if (dhcpResults.gateway != null) {
   1882             info.gateway = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.gateway);
   1883         }
   1884 
   1885         int dnsFound = 0;
   1886         for (InetAddress dns : dhcpResults.dnsServers) {
   1887             if (dns instanceof Inet4Address) {
   1888                 if (dnsFound == 0) {
   1889                     info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
   1890                 } else {
   1891                     info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
   1892                 }
   1893                 if (++dnsFound > 1) break;
   1894             }
   1895         }
   1896         Inet4Address serverAddress = dhcpResults.serverAddress;
   1897         if (serverAddress != null) {
   1898             info.serverAddress = NetworkUtils.inetAddressToInt(serverAddress);
   1899         }
   1900         info.leaseDuration = dhcpResults.leaseDuration;
   1901 
   1902         return info;
   1903     }
   1904 
   1905     /**
   1906      * enable TDLS for the local NIC to remote NIC
   1907      * The APPs don't know the remote MAC address to identify NIC though,
   1908      * so we need to do additional work to find it from remote IP address
   1909      */
   1910 
   1911     class TdlsTaskParams {
   1912         public String remoteIpAddress;
   1913         public boolean enable;
   1914     }
   1915 
   1916     class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> {
   1917         @Override
   1918         protected Integer doInBackground(TdlsTaskParams... params) {
   1919 
   1920             // Retrieve parameters for the call
   1921             TdlsTaskParams param = params[0];
   1922             String remoteIpAddress = param.remoteIpAddress.trim();
   1923             boolean enable = param.enable;
   1924 
   1925             // Get MAC address of Remote IP
   1926             String macAddress = null;
   1927 
   1928             BufferedReader reader = null;
   1929 
   1930             try {
   1931                 reader = new BufferedReader(new FileReader("/proc/net/arp"));
   1932 
   1933                 // Skip over the line bearing colum titles
   1934                 String line = reader.readLine();
   1935 
   1936                 while ((line = reader.readLine()) != null) {
   1937                     String[] tokens = line.split("[ ]+");
   1938                     if (tokens.length < 6) {
   1939                         continue;
   1940                     }
   1941 
   1942                     // ARP column format is
   1943                     // Address HWType HWAddress Flags Mask IFace
   1944                     String ip = tokens[0];
   1945                     String mac = tokens[3];
   1946 
   1947                     if (remoteIpAddress.equals(ip)) {
   1948                         macAddress = mac;
   1949                         break;
   1950                     }
   1951                 }
   1952 
   1953                 if (macAddress == null) {
   1954                     Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " +
   1955                             "/proc/net/arp");
   1956                 } else {
   1957                     enableTdlsWithMacAddress(macAddress, enable);
   1958                 }
   1959 
   1960             } catch (FileNotFoundException e) {
   1961                 Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address");
   1962             } catch (IOException e) {
   1963                 Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address");
   1964             } finally {
   1965                 try {
   1966                     if (reader != null) {
   1967                         reader.close();
   1968                     }
   1969                 }
   1970                 catch (IOException e) {
   1971                     // Do nothing
   1972                 }
   1973             }
   1974 
   1975             return 0;
   1976         }
   1977     }
   1978 
   1979     @Override
   1980     public void enableTdls(String remoteAddress, boolean enable) {
   1981         if (remoteAddress == null) {
   1982           throw new IllegalArgumentException("remoteAddress cannot be null");
   1983         }
   1984         mLog.trace("enableTdls uid=% enable=%").c(Binder.getCallingUid()).c(enable).flush();
   1985         TdlsTaskParams params = new TdlsTaskParams();
   1986         params.remoteIpAddress = remoteAddress;
   1987         params.enable = enable;
   1988         new TdlsTask().execute(params);
   1989     }
   1990 
   1991 
   1992     @Override
   1993     public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
   1994         mLog.trace("enableTdlsWithMacAddress uid=% enable=%")
   1995                 .c(Binder.getCallingUid())
   1996                 .c(enable)
   1997                 .flush();
   1998         if (remoteMacAddress == null) {
   1999           throw new IllegalArgumentException("remoteMacAddress cannot be null");
   2000         }
   2001 
   2002         mWifiStateMachine.enableTdls(remoteMacAddress, enable);
   2003     }
   2004 
   2005     /**
   2006      * Get a reference to handler. This is used by a client to establish
   2007      * an AsyncChannel communication with WifiService
   2008      */
   2009     @Override
   2010     public Messenger getWifiServiceMessenger() {
   2011         enforceAccessPermission();
   2012         enforceChangePermission();
   2013         mLog.trace("getWifiServiceMessenger uid=%").c(Binder.getCallingUid()).flush();
   2014         return new Messenger(mClientHandler);
   2015     }
   2016 
   2017     /**
   2018      * Disable an ephemeral network, i.e. network that is created thru a WiFi Scorer
   2019      */
   2020     @Override
   2021     public void disableEphemeralNetwork(String SSID) {
   2022         enforceAccessPermission();
   2023         enforceChangePermission();
   2024         mLog.trace("disableEphemeralNetwork uid=%").c(Binder.getCallingUid()).flush();
   2025         mWifiStateMachine.disableEphemeralNetwork(SSID);
   2026     }
   2027 
   2028     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
   2029         @Override
   2030         public void onReceive(Context context, Intent intent) {
   2031             String action = intent.getAction();
   2032             if (action.equals(Intent.ACTION_SCREEN_ON)) {
   2033                 mWifiController.sendMessage(CMD_SCREEN_ON);
   2034             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
   2035                 mWifiController.sendMessage(CMD_USER_PRESENT);
   2036             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
   2037                 mWifiController.sendMessage(CMD_SCREEN_OFF);
   2038             } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
   2039                 int pluggedType = intent.getIntExtra("plugged", 0);
   2040                 mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null);
   2041             } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
   2042                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
   2043                         BluetoothAdapter.STATE_DISCONNECTED);
   2044                 mWifiStateMachine.sendBluetoothAdapterStateChange(state);
   2045             } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
   2046                 boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false);
   2047                 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0);
   2048             } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED)) {
   2049                 boolean inCall = intent.getBooleanExtra(PhoneConstants.PHONE_IN_EMERGENCY_CALL, false);
   2050                 mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, inCall ? 1 : 0, 0);
   2051             } else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
   2052                 handleIdleModeChanged();
   2053             }
   2054         }
   2055     };
   2056 
   2057     private boolean startConsentUi(String packageName,
   2058             int callingUid, String intentAction) throws RemoteException {
   2059         if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
   2060             return false;
   2061         }
   2062         try {
   2063             // Validate the package only if we are going to use it
   2064             ApplicationInfo applicationInfo = mContext.getPackageManager()
   2065                     .getApplicationInfoAsUser(packageName,
   2066                             PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
   2067                             UserHandle.getUserId(callingUid));
   2068             if (applicationInfo.uid != callingUid) {
   2069                 throw new SecurityException("Package " + callingUid
   2070                         + " not in uid " + callingUid);
   2071             }
   2072 
   2073             // Permission review mode, trigger a user prompt
   2074             Intent intent = new Intent(intentAction);
   2075             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
   2076                     | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
   2077             intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
   2078             mContext.startActivity(intent);
   2079             return true;
   2080         } catch (PackageManager.NameNotFoundException e) {
   2081             throw new RemoteException(e.getMessage());
   2082         }
   2083     }
   2084 
   2085     /**
   2086      * Observes settings changes to scan always mode.
   2087      */
   2088     private void registerForScanModeChange() {
   2089         ContentObserver contentObserver = new ContentObserver(null) {
   2090             @Override
   2091             public void onChange(boolean selfChange) {
   2092                 mSettingsStore.handleWifiScanAlwaysAvailableToggled();
   2093                 mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED);
   2094             }
   2095         };
   2096         mFrameworkFacade.registerContentObserver(mContext,
   2097                 Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE),
   2098                 false, contentObserver);
   2099 
   2100     }
   2101 
   2102     // Monitors settings changes related to background wifi scan throttling.
   2103     private void registerForBackgroundThrottleChanges() {
   2104         mFrameworkFacade.registerContentObserver(
   2105                 mContext,
   2106                 Settings.Global.getUriFor(
   2107                         Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS),
   2108                 false,
   2109                 new ContentObserver(null) {
   2110                     @Override
   2111                     public void onChange(boolean selfChange) {
   2112                         updateBackgroundThrottleInterval();
   2113                     }
   2114                 }
   2115         );
   2116         mFrameworkFacade.registerContentObserver(
   2117                 mContext,
   2118                 Settings.Global.getUriFor(
   2119                         Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
   2120                 false,
   2121                 new ContentObserver(null) {
   2122                     @Override
   2123                     public void onChange(boolean selfChange) {
   2124                         updateBackgroundThrottlingWhitelist();
   2125                     }
   2126                 }
   2127         );
   2128     }
   2129 
   2130     private void updateBackgroundThrottleInterval() {
   2131         mBackgroundThrottleInterval = mFrameworkFacade.getLongSetting(
   2132                 mContext,
   2133                 Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS,
   2134                 DEFAULT_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS);
   2135     }
   2136 
   2137     private void updateBackgroundThrottlingWhitelist() {
   2138         String setting = mFrameworkFacade.getStringSetting(
   2139                 mContext,
   2140                 Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
   2141         mBackgroundThrottlePackageWhitelist.clear();
   2142         if (setting != null) {
   2143             mBackgroundThrottlePackageWhitelist.addAll(Arrays.asList(setting.split(",")));
   2144         }
   2145     }
   2146 
   2147     private void registerForBroadcasts() {
   2148         IntentFilter intentFilter = new IntentFilter();
   2149         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
   2150         intentFilter.addAction(Intent.ACTION_USER_PRESENT);
   2151         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
   2152         intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
   2153         intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
   2154         intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
   2155         intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
   2156         intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
   2157 
   2158         boolean trackEmergencyCallState = mContext.getResources().getBoolean(
   2159                 com.android.internal.R.bool.config_wifi_turn_off_during_emergency_call);
   2160         if (trackEmergencyCallState) {
   2161             intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED);
   2162         }
   2163 
   2164         mContext.registerReceiver(mReceiver, intentFilter);
   2165     }
   2166 
   2167     private void registerForPackageOrUserRemoval() {
   2168         IntentFilter intentFilter = new IntentFilter();
   2169         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
   2170         intentFilter.addAction(Intent.ACTION_USER_REMOVED);
   2171         mContext.registerReceiverAsUser(new BroadcastReceiver() {
   2172             @Override
   2173             public void onReceive(Context context, Intent intent) {
   2174                 switch (intent.getAction()) {
   2175                     case Intent.ACTION_PACKAGE_REMOVED: {
   2176                         if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
   2177                             return;
   2178                         }
   2179                         int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
   2180                         Uri uri = intent.getData();
   2181                         if (uid == -1 || uri == null) {
   2182                             return;
   2183                         }
   2184                         String pkgName = uri.getSchemeSpecificPart();
   2185                         mWifiStateMachine.removeAppConfigs(pkgName, uid);
   2186                         break;
   2187                     }
   2188                     case Intent.ACTION_USER_REMOVED: {
   2189                         int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
   2190                         mWifiStateMachine.removeUserConfigs(userHandle);
   2191                         break;
   2192                     }
   2193                 }
   2194             }
   2195         }, UserHandle.ALL, intentFilter, null, null);
   2196     }
   2197 
   2198     @Override
   2199     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   2200         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
   2201                 != PackageManager.PERMISSION_GRANTED) {
   2202             pw.println("Permission Denial: can't dump WifiService from from pid="
   2203                     + Binder.getCallingPid()
   2204                     + ", uid=" + Binder.getCallingUid());
   2205             return;
   2206         }
   2207         if (args != null && args.length > 0 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])) {
   2208             // WifiMetrics proto bytes were requested. Dump only these.
   2209             mWifiStateMachine.updateWifiMetrics();
   2210             mWifiMetrics.dump(fd, pw, args);
   2211         } else if (args != null && args.length > 0 && IpManager.DUMP_ARG.equals(args[0])) {
   2212             // IpManager dump was requested. Pass it along and take no further action.
   2213             String[] ipManagerArgs = new String[args.length - 1];
   2214             System.arraycopy(args, 1, ipManagerArgs, 0, ipManagerArgs.length);
   2215             mWifiStateMachine.dumpIpManager(fd, pw, ipManagerArgs);
   2216         } else if (args != null && args.length > 0
   2217                 && DUMP_ARG_SET_IPREACH_DISCONNECT.equals(args[0])) {
   2218             if (args.length > 1) {
   2219                 if (DUMP_ARG_SET_IPREACH_DISCONNECT_ENABLED.equals(args[1])) {
   2220                     mWifiStateMachine.setIpReachabilityDisconnectEnabled(true);
   2221                 } else if (DUMP_ARG_SET_IPREACH_DISCONNECT_DISABLED.equals(args[1])) {
   2222                     mWifiStateMachine.setIpReachabilityDisconnectEnabled(false);
   2223                 }
   2224             }
   2225             pw.println("IPREACH_DISCONNECT state is "
   2226                     + mWifiStateMachine.getIpReachabilityDisconnectEnabled());
   2227             return;
   2228         } else {
   2229             pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
   2230             pw.println("Stay-awake conditions: " +
   2231                     mFacade.getIntegerSetting(mContext,
   2232                             Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
   2233             pw.println("mInIdleMode " + mInIdleMode);
   2234             pw.println("mScanPending " + mScanPending);
   2235             mWifiController.dump(fd, pw, args);
   2236             mSettingsStore.dump(fd, pw, args);
   2237             mNotificationController.dump(fd, pw, args);
   2238             mTrafficPoller.dump(fd, pw, args);
   2239             pw.println();
   2240             pw.println("Locks held:");
   2241             mWifiLockManager.dump(pw);
   2242             pw.println();
   2243             mWifiMulticastLockManager.dump(pw);
   2244             pw.println();
   2245             mWifiStateMachine.dump(fd, pw, args);
   2246             pw.println();
   2247             mWifiStateMachine.updateWifiMetrics();
   2248             mWifiMetrics.dump(fd, pw, args);
   2249             pw.println();
   2250             mWifiBackupRestore.dump(fd, pw, args);
   2251             pw.println();
   2252         }
   2253     }
   2254 
   2255     @Override
   2256     public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
   2257         mLog.trace("acquireWifiLock uid=% lockMode=%")
   2258                 .c(Binder.getCallingUid())
   2259                 .c(lockMode).flush();
   2260         if (mWifiLockManager.acquireWifiLock(lockMode, tag, binder, ws)) {
   2261             mWifiController.sendMessage(CMD_LOCKS_CHANGED);
   2262             return true;
   2263         }
   2264         return false;
   2265     }
   2266 
   2267     @Override
   2268     public void updateWifiLockWorkSource(IBinder binder, WorkSource ws) {
   2269         mLog.trace("updateWifiLockWorkSource uid=%").c(Binder.getCallingUid()).flush();
   2270         mWifiLockManager.updateWifiLockWorkSource(binder, ws);
   2271     }
   2272 
   2273     @Override
   2274     public boolean releaseWifiLock(IBinder binder) {
   2275         mLog.trace("releaseWifiLock uid=%").c(Binder.getCallingUid()).flush();
   2276         if (mWifiLockManager.releaseWifiLock(binder)) {
   2277             mWifiController.sendMessage(CMD_LOCKS_CHANGED);
   2278             return true;
   2279         }
   2280         return false;
   2281     }
   2282 
   2283     @Override
   2284     public void initializeMulticastFiltering() {
   2285         enforceMulticastChangePermission();
   2286         mLog.trace("initializeMulticastFiltering uid=%").c(Binder.getCallingUid()).flush();
   2287         mWifiMulticastLockManager.initializeFiltering();
   2288     }
   2289 
   2290     @Override
   2291     public void acquireMulticastLock(IBinder binder, String tag) {
   2292         enforceMulticastChangePermission();
   2293         mLog.trace("acquireMulticastLock uid=%").c(Binder.getCallingUid()).flush();
   2294         mWifiMulticastLockManager.acquireLock(binder, tag);
   2295     }
   2296 
   2297     @Override
   2298     public void releaseMulticastLock() {
   2299         enforceMulticastChangePermission();
   2300         mLog.trace("releaseMulticastLock uid=%").c(Binder.getCallingUid()).flush();
   2301         mWifiMulticastLockManager.releaseLock();
   2302     }
   2303 
   2304     @Override
   2305     public boolean isMulticastEnabled() {
   2306         enforceAccessPermission();
   2307         mLog.trace("isMulticastEnabled uid=%").c(Binder.getCallingUid()).flush();
   2308         return mWifiMulticastLockManager.isMulticastEnabled();
   2309     }
   2310 
   2311     @Override
   2312     public void enableVerboseLogging(int verbose) {
   2313         enforceAccessPermission();
   2314         mLog.trace("enableVerboseLogging uid=% verbose=%")
   2315                 .c(Binder.getCallingUid())
   2316                 .c(verbose).flush();
   2317         mFacade.setIntegerSetting(
   2318                 mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, verbose);
   2319         enableVerboseLoggingInternal(verbose);
   2320     }
   2321 
   2322     void enableVerboseLoggingInternal(int verbose) {
   2323         mWifiStateMachine.enableVerboseLogging(verbose);
   2324         mWifiLockManager.enableVerboseLogging(verbose);
   2325         mWifiMulticastLockManager.enableVerboseLogging(verbose);
   2326         mWifiInjector.getWifiLastResortWatchdog().enableVerboseLogging(verbose);
   2327         mWifiInjector.getWifiBackupRestore().enableVerboseLogging(verbose);
   2328         LogcatLog.enableVerboseLogging(verbose);
   2329     }
   2330 
   2331     @Override
   2332     public int getVerboseLoggingLevel() {
   2333         enforceAccessPermission();
   2334         mLog.trace("getVerboseLoggingLevel uid=%").c(Binder.getCallingUid()).flush();
   2335         return mFacade.getIntegerSetting(
   2336                 mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0);
   2337     }
   2338 
   2339     @Override
   2340     public void enableAggressiveHandover(int enabled) {
   2341         enforceAccessPermission();
   2342         mLog.trace("enableAggressiveHandover uid=% enabled=%")
   2343             .c(Binder.getCallingUid())
   2344             .c(enabled)
   2345             .flush();
   2346         mWifiStateMachine.enableAggressiveHandover(enabled);
   2347     }
   2348 
   2349     @Override
   2350     public int getAggressiveHandover() {
   2351         enforceAccessPermission();
   2352         mLog.trace("getAggressiveHandover uid=%").c(Binder.getCallingUid()).flush();
   2353         return mWifiStateMachine.getAggressiveHandover();
   2354     }
   2355 
   2356     @Override
   2357     public void setAllowScansWithTraffic(int enabled) {
   2358         enforceAccessPermission();
   2359         mLog.trace("setAllowScansWithTraffic uid=% enabled=%")
   2360                 .c(Binder.getCallingUid())
   2361                 .c(enabled).flush();
   2362         mWifiStateMachine.setAllowScansWithTraffic(enabled);
   2363     }
   2364 
   2365     @Override
   2366     public int getAllowScansWithTraffic() {
   2367         enforceAccessPermission();
   2368         mLog.trace("getAllowScansWithTraffic uid=%").c(Binder.getCallingUid()).flush();
   2369         return mWifiStateMachine.getAllowScansWithTraffic();
   2370     }
   2371 
   2372     @Override
   2373     public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
   2374         enforceChangePermission();
   2375         mLog.trace("setEnableAutoJoinWhenAssociated uid=% enabled=%")
   2376                 .c(Binder.getCallingUid())
   2377                 .c(enabled).flush();
   2378         return mWifiStateMachine.setEnableAutoJoinWhenAssociated(enabled);
   2379     }
   2380 
   2381     @Override
   2382     public boolean getEnableAutoJoinWhenAssociated() {
   2383         enforceAccessPermission();
   2384         mLog.trace("getEnableAutoJoinWhenAssociated uid=%").c(Binder.getCallingUid()).flush();
   2385         return mWifiStateMachine.getEnableAutoJoinWhenAssociated();
   2386     }
   2387 
   2388     /* Return the Wifi Connection statistics object */
   2389     @Override
   2390     public WifiConnectionStatistics getConnectionStatistics() {
   2391         enforceAccessPermission();
   2392         enforceReadCredentialPermission();
   2393         mLog.trace("getConnectionStatistics uid=%").c(Binder.getCallingUid()).flush();
   2394         if (mWifiStateMachineChannel != null) {
   2395             return mWifiStateMachine.syncGetConnectionStatistics(mWifiStateMachineChannel);
   2396         } else {
   2397             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
   2398             return null;
   2399         }
   2400     }
   2401 
   2402     @Override
   2403     public void factoryReset() {
   2404         enforceConnectivityInternalPermission();
   2405         mLog.trace("factoryReset uid=%").c(Binder.getCallingUid()).flush();
   2406         if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
   2407             return;
   2408         }
   2409 
   2410         if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
   2411             // Turn mobile hotspot off - will also clear any registered LOHS requests when it is
   2412             // shut down
   2413             stopSoftApInternal();
   2414         }
   2415 
   2416         if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI)) {
   2417             // Enable wifi
   2418             try {
   2419                 setWifiEnabled(mContext.getOpPackageName(), true);
   2420             } catch (RemoteException e) {
   2421                 /* ignore - local call */
   2422             }
   2423             // Delete all Wifi SSIDs
   2424             if (mWifiStateMachineChannel != null) {
   2425                 List<WifiConfiguration> networks = mWifiStateMachine.syncGetConfiguredNetworks(
   2426                         Binder.getCallingUid(), mWifiStateMachineChannel);
   2427                 if (networks != null) {
   2428                     for (WifiConfiguration config : networks) {
   2429                         removeNetwork(config.networkId);
   2430                     }
   2431                     saveConfiguration();
   2432                 }
   2433             }
   2434         }
   2435     }
   2436 
   2437     /* private methods */
   2438     static boolean logAndReturnFalse(String s) {
   2439         Log.d(TAG, s);
   2440         return false;
   2441     }
   2442 
   2443     public static boolean isValid(WifiConfiguration config) {
   2444         String validity = checkValidity(config);
   2445         return validity == null || logAndReturnFalse(validity);
   2446     }
   2447 
   2448     public static String checkValidity(WifiConfiguration config) {
   2449         if (config.allowedKeyManagement == null)
   2450             return "allowed kmgmt";
   2451 
   2452         if (config.allowedKeyManagement.cardinality() > 1) {
   2453             if (config.allowedKeyManagement.cardinality() != 2) {
   2454                 return "cardinality != 2";
   2455             }
   2456             if (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP)) {
   2457                 return "not WPA_EAP";
   2458             }
   2459             if ((!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X))
   2460                     && (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK))) {
   2461                 return "not PSK or 8021X";
   2462             }
   2463         }
   2464         if (config.getIpAssignment() == IpConfiguration.IpAssignment.STATIC) {
   2465             StaticIpConfiguration staticIpConf = config.getStaticIpConfiguration();
   2466             if (staticIpConf == null) {
   2467                 return "null StaticIpConfiguration";
   2468             }
   2469             if (staticIpConf.ipAddress == null) {
   2470                 return "null static ip Address";
   2471             }
   2472         }
   2473         return null;
   2474     }
   2475 
   2476     @Override
   2477     public Network getCurrentNetwork() {
   2478         enforceAccessPermission();
   2479         mLog.trace("getCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
   2480         return mWifiStateMachine.getCurrentNetwork();
   2481     }
   2482 
   2483     public static String toHexString(String s) {
   2484         if (s == null) {
   2485             return "null";
   2486         }
   2487         StringBuilder sb = new StringBuilder();
   2488         sb.append('\'').append(s).append('\'');
   2489         for (int n = 0; n < s.length(); n++) {
   2490             sb.append(String.format(" %02x", s.charAt(n) & 0xffff));
   2491         }
   2492         return sb.toString();
   2493     }
   2494 
   2495     public void hideCertFromUnaffiliatedUsers(String alias) {
   2496         mCertManager.hideCertFromUnaffiliatedUsers(alias);
   2497     }
   2498 
   2499     public String[] listClientCertsForCurrentUser() {
   2500         return mCertManager.listClientCertsForCurrentUser();
   2501     }
   2502 
   2503     /**
   2504      * Enable/disable WifiConnectivityManager at runtime
   2505      *
   2506      * @param enabled true-enable; false-disable
   2507      */
   2508     @Override
   2509     public void enableWifiConnectivityManager(boolean enabled) {
   2510         enforceConnectivityInternalPermission();
   2511         mLog.trace("enableWifiConnectivityManager uid=% enabled=%")
   2512             .c(Binder.getCallingUid())
   2513             .c(enabled).flush();
   2514         mWifiStateMachine.enableWifiConnectivityManager(enabled);
   2515     }
   2516 
   2517     /**
   2518      * Retrieve the data to be backed to save the current state.
   2519      *
   2520      * @return  Raw byte stream of the data to be backed up.
   2521      */
   2522     @Override
   2523     public byte[] retrieveBackupData() {
   2524         enforceNetworkSettingsPermission();
   2525         mLog.trace("retrieveBackupData uid=%").c(Binder.getCallingUid()).flush();
   2526         if (mWifiStateMachineChannel == null) {
   2527             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
   2528             return null;
   2529         }
   2530 
   2531         Slog.d(TAG, "Retrieving backup data");
   2532         List<WifiConfiguration> wifiConfigurations =
   2533                 mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel);
   2534         byte[] backupData =
   2535                 mWifiBackupRestore.retrieveBackupDataFromConfigurations(wifiConfigurations);
   2536         Slog.d(TAG, "Retrieved backup data");
   2537         return backupData;
   2538     }
   2539 
   2540     /**
   2541      * Helper method to restore networks retrieved from backup data.
   2542      *
   2543      * @param configurations list of WifiConfiguration objects parsed from the backup data.
   2544      */
   2545     private void restoreNetworks(List<WifiConfiguration> configurations) {
   2546         if (configurations == null) {
   2547             Slog.e(TAG, "Backup data parse failed");
   2548             return;
   2549         }
   2550         for (WifiConfiguration configuration : configurations) {
   2551             int networkId = mWifiStateMachine.syncAddOrUpdateNetwork(
   2552                     mWifiStateMachineChannel, configuration);
   2553             if (networkId == WifiConfiguration.INVALID_NETWORK_ID) {
   2554                 Slog.e(TAG, "Restore network failed: " + configuration.configKey());
   2555                 continue;
   2556             }
   2557             // Enable all networks restored.
   2558             mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, networkId, false);
   2559         }
   2560     }
   2561 
   2562     /**
   2563      * Restore state from the backed up data.
   2564      *
   2565      * @param data Raw byte stream of the backed up data.
   2566      */
   2567     @Override
   2568     public void restoreBackupData(byte[] data) {
   2569         enforceNetworkSettingsPermission();
   2570         mLog.trace("restoreBackupData uid=%").c(Binder.getCallingUid()).flush();
   2571         if (mWifiStateMachineChannel == null) {
   2572             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
   2573             return;
   2574         }
   2575 
   2576         Slog.d(TAG, "Restoring backup data");
   2577         List<WifiConfiguration> wifiConfigurations =
   2578                 mWifiBackupRestore.retrieveConfigurationsFromBackupData(data);
   2579         restoreNetworks(wifiConfigurations);
   2580         Slog.d(TAG, "Restored backup data");
   2581     }
   2582 
   2583     /**
   2584      * Restore state from the older supplicant back up data.
   2585      * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file.
   2586      *
   2587      * @param supplicantData Raw byte stream of wpa_supplicant.conf
   2588      * @param ipConfigData Raw byte stream of ipconfig.txt
   2589      */
   2590     public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
   2591         enforceNetworkSettingsPermission();
   2592         mLog.trace("restoreSupplicantBackupData uid=%").c(Binder.getCallingUid()).flush();
   2593         if (mWifiStateMachineChannel == null) {
   2594             Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
   2595             return;
   2596         }
   2597 
   2598         Slog.d(TAG, "Restoring supplicant backup data");
   2599         List<WifiConfiguration> wifiConfigurations =
   2600                 mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData(
   2601                         supplicantData, ipConfigData);
   2602         restoreNetworks(wifiConfigurations);
   2603         Slog.d(TAG, "Restored supplicant backup data");
   2604     }
   2605 }
   2606