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