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.content.pm.PackageManager.PERMISSION_GRANTED;
21 import static android.net.wifi.WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE;
22 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_FAILURE_REASON;
23 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
24 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
25 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
26 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
27 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL;
28 import static android.net.wifi.WifiManager.SAP_START_FAILURE_NO_CHANNEL;
29 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
30 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
31 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
32 import static android.net.wifi.WifiManager.WIFI_FEATURE_INFRA_5G;
33 
34 import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERROR;
35 import static com.android.server.wifi.WifiController.CMD_AIRPLANE_TOGGLED;
36 import static com.android.server.wifi.WifiController.CMD_EMERGENCY_CALL_STATE_CHANGED;
37 import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED;
38 import static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED;
39 import static com.android.server.wifi.WifiController.CMD_SET_AP;
40 import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED;
41 
42 import android.Manifest;
43 import android.annotation.CheckResult;
44 import android.app.ActivityManager;
45 import android.app.ActivityManager.RunningAppProcessInfo;
46 import android.app.AppOpsManager;
47 import android.app.admin.DeviceAdminInfo;
48 import android.app.admin.DevicePolicyManagerInternal;
49 import android.bluetooth.BluetoothAdapter;
50 import android.content.BroadcastReceiver;
51 import android.content.Context;
52 import android.content.Intent;
53 import android.content.IntentFilter;
54 import android.content.pm.ApplicationInfo;
55 import android.content.pm.PackageManager;
56 import android.content.pm.ParceledListSlice;
57 import android.database.ContentObserver;
58 import android.net.DhcpInfo;
59 import android.net.DhcpResults;
60 import android.net.Network;
61 import android.net.NetworkUtils;
62 import android.net.Uri;
63 import android.net.ip.IpClientUtil;
64 import android.net.wifi.IDppCallback;
65 import android.net.wifi.INetworkRequestMatchCallback;
66 import android.net.wifi.IOnWifiUsabilityStatsListener;
67 import android.net.wifi.ISoftApCallback;
68 import android.net.wifi.ITrafficStateCallback;
69 import android.net.wifi.ScanResult;
70 import android.net.wifi.WifiActivityEnergyInfo;
71 import android.net.wifi.WifiConfiguration;
72 import android.net.wifi.WifiInfo;
73 import android.net.wifi.WifiManager;
74 import android.net.wifi.WifiManager.DeviceMobilityState;
75 import android.net.wifi.WifiManager.LocalOnlyHotspotCallback;
76 import android.net.wifi.WifiNetworkSuggestion;
77 import android.net.wifi.WifiSsid;
78 import android.net.wifi.hotspot2.IProvisioningCallback;
79 import android.net.wifi.hotspot2.OsuProvider;
80 import android.net.wifi.hotspot2.PasspointConfiguration;
81 import android.os.AsyncTask;
82 import android.os.BatteryStats;
83 import android.os.Binder;
84 import android.os.Build;
85 import android.os.Bundle;
86 import android.os.Handler;
87 import android.os.HandlerThread;
88 import android.os.IBinder;
89 import android.os.Looper;
90 import android.os.Message;
91 import android.os.Messenger;
92 import android.os.PowerManager;
93 import android.os.Process;
94 import android.os.RemoteException;
95 import android.os.ResultReceiver;
96 import android.os.ShellCallback;
97 import android.os.UserHandle;
98 import android.os.UserManager;
99 import android.os.WorkSource;
100 import android.provider.Settings;
101 import android.telephony.TelephonyManager;
102 import android.text.TextUtils;
103 import android.util.Log;
104 import android.util.MutableInt;
105 import android.util.Slog;
106 
107 import com.android.internal.annotations.GuardedBy;
108 import com.android.internal.annotations.VisibleForTesting;
109 import com.android.internal.os.PowerProfile;
110 import com.android.internal.telephony.IccCardConstants;
111 import com.android.internal.telephony.PhoneConstants;
112 import com.android.internal.telephony.TelephonyIntents;
113 import com.android.internal.util.AsyncChannel;
114 import com.android.server.wifi.hotspot2.PasspointProvider;
115 import com.android.server.wifi.util.ExternalCallbackTracker;
116 import com.android.server.wifi.util.GeneralUtil.Mutable;
117 import com.android.server.wifi.util.WifiHandler;
118 import com.android.server.wifi.util.WifiPermissionsUtil;
119 
120 import java.io.BufferedReader;
121 import java.io.FileDescriptor;
122 import java.io.FileNotFoundException;
123 import java.io.FileReader;
124 import java.io.IOException;
125 import java.io.PrintWriter;
126 import java.net.Inet4Address;
127 import java.net.InetAddress;
128 import java.security.GeneralSecurityException;
129 import java.security.KeyStore;
130 import java.security.cert.CertPath;
131 import java.security.cert.CertPathValidator;
132 import java.security.cert.CertificateFactory;
133 import java.security.cert.PKIXParameters;
134 import java.security.cert.X509Certificate;
135 import java.util.ArrayList;
136 import java.util.Arrays;
137 import java.util.HashMap;
138 import java.util.Iterator;
139 import java.util.List;
140 import java.util.Map;
141 import java.util.concurrent.ConcurrentHashMap;
142 
143 /**
144  * WifiService handles remote WiFi operation requests by implementing
145  * the IWifiManager interface.
146  *
147  * @hide
148  */
149 public class WifiServiceImpl extends BaseWifiService {
150     private static final String TAG = "WifiService";
151     private static final boolean VDBG = false;
152 
153     // Default scan background throttling interval if not overriden in settings
154     private static final long DEFAULT_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
155 
156     // Apps with importance higher than this value is considered as background app.
157     private static final int BACKGROUND_IMPORTANCE_CUTOFF =
158             RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
159 
160     // Max wait time for posting blocking runnables
161     private static final int RUN_WITH_SCISSORS_TIMEOUT_MILLIS = 4000;
162 
163     final ClientModeImpl mClientModeImpl;
164     final ActiveModeWarden mActiveModeWarden;
165     final ScanRequestProxy mScanRequestProxy;
166 
167     private final Context mContext;
168     private final FrameworkFacade mFacade;
169     private final Clock mClock;
170 
171     private final PowerManager mPowerManager;
172     private final AppOpsManager mAppOps;
173     private final UserManager mUserManager;
174     private final ActivityManager mActivityManager;
175     private final WifiCountryCode mCountryCode;
176     // Debug counter tracking scan requests sent by WifiManager
177     private int scanRequestCounter = 0;
178 
179     /* Polls traffic stats and notifies clients */
180     private WifiTrafficPoller mWifiTrafficPoller;
181     /* Tracks the persisted states for wi-fi & airplane mode */
182     final WifiSettingsStore mSettingsStore;
183     /* Logs connection events and some general router and scan stats */
184     private final WifiMetrics mWifiMetrics;
185 
186     private final WifiInjector mWifiInjector;
187     /* Backup/Restore Module */
188     private final WifiBackupRestore mWifiBackupRestore;
189     private final WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
190 
191     private WifiLog mLog;
192     /**
193      * Verbose logging flag. Toggled by developer options.
194      */
195     private boolean mVerboseLoggingEnabled = false;
196 
197     /**
198      * Asynchronous channel to ClientModeImpl
199      */
200     @VisibleForTesting
201     AsyncChannel mClientModeImplChannel;
202 
203     private final FrameworkFacade mFrameworkFacade;
204 
205     private WifiPermissionsUtil mWifiPermissionsUtil;
206 
207     @GuardedBy("mLocalOnlyHotspotRequests")
208     private final HashMap<Integer, LocalOnlyHotspotRequestInfo> mLocalOnlyHotspotRequests;
209     @GuardedBy("mLocalOnlyHotspotRequests")
210     private WifiConfiguration mLocalOnlyHotspotConfig = null;
211     @GuardedBy("mLocalOnlyHotspotRequests")
212     private final ConcurrentHashMap<String, Integer> mIfaceIpModes;
213 
214     private final ExternalCallbackTracker<ISoftApCallback> mRegisteredSoftApCallbacks;
215 
216     /**
217      * One of:  {@link WifiManager#WIFI_AP_STATE_DISABLED},
218      *          {@link WifiManager#WIFI_AP_STATE_DISABLING},
219      *          {@link WifiManager#WIFI_AP_STATE_ENABLED},
220      *          {@link WifiManager#WIFI_AP_STATE_ENABLING},
221      *          {@link WifiManager#WIFI_AP_STATE_FAILED}
222      *
223      * Access/maintenance MUST be done on the wifi service thread
224      */
225     // TODO: (b/71714381) Remove mWifiApState and broadcast mechanism, keep mSoftApState as the only
226     //       field to store soft AP state. Then rename mSoftApState and mSoftApNumClients to
227     //       mWifiApState and mWifiApNumClients, to match the constants (i.e. WIFI_AP_STATE_*)
228     private int mWifiApState = WifiManager.WIFI_AP_STATE_DISABLED;
229     private int mSoftApState = WifiManager.WIFI_AP_STATE_DISABLED;
230     private int mSoftApNumClients = 0;
231 
232     /**
233      * Power profile
234      */
235     PowerProfile mPowerProfile;
236 
237     /**
238      * Callback for use with LocalOnlyHotspot to unregister requesting applications upon death.
239      *
240      * @hide
241      */
242     public final class LocalOnlyRequestorCallback
243             implements LocalOnlyHotspotRequestInfo.RequestingApplicationDeathCallback {
244         /**
245          * Called with requesting app has died.
246          */
247         @Override
onLocalOnlyHotspotRequestorDeath(LocalOnlyHotspotRequestInfo requestor)248         public void onLocalOnlyHotspotRequestorDeath(LocalOnlyHotspotRequestInfo requestor) {
249             unregisterCallingAppAndStopLocalOnlyHotspot(requestor);
250         };
251     }
252 
253     /**
254      * Handles client connections
255      */
256     private class AsyncChannelExternalClientHandler extends WifiHandler {
257 
AsyncChannelExternalClientHandler(String tag, Looper looper)258         AsyncChannelExternalClientHandler(String tag, Looper looper) {
259             super(tag, looper);
260         }
261 
262         @Override
handleMessage(Message msg)263         public void handleMessage(Message msg) {
264             super.handleMessage(msg);
265             switch (msg.what) {
266                 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
267                     AsyncChannel ac = mFrameworkFacade.makeWifiAsyncChannel(TAG);
268                     ac.connect(mContext, this, msg.replyTo);
269                     break;
270                 }
271                 case WifiManager.CONNECT_NETWORK: {
272                     if (checkPrivilegedPermissionsAndReplyIfNotAuthorized(
273                             msg, WifiManager.CONNECT_NETWORK_FAILED)) {
274                         WifiConfiguration config = (WifiConfiguration) msg.obj;
275                         int networkId = msg.arg1;
276                         Slog.d(TAG, "CONNECT "
277                                 + " nid=" + Integer.toString(networkId)
278                                 + " config=" + config
279                                 + " uid=" + msg.sendingUid
280                                 + " name="
281                                 + mContext.getPackageManager().getNameForUid(msg.sendingUid));
282                         if (config != null) {
283                             /* Command is forwarded to state machine */
284                             mClientModeImpl.sendMessage(Message.obtain(msg));
285                         } else if (config == null
286                                 && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
287                             mClientModeImpl.sendMessage(Message.obtain(msg));
288                         } else {
289                             Slog.e(TAG, "AsyncChannelExternalClientHandler.handleMessage "
290                                     + "ignoring invalid msg=" + msg);
291                             replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED,
292                                     WifiManager.INVALID_ARGS);
293                         }
294                     }
295                     break;
296                 }
297                 case WifiManager.SAVE_NETWORK: {
298                     if (checkPrivilegedPermissionsAndReplyIfNotAuthorized(
299                             msg, WifiManager.SAVE_NETWORK_FAILED)) {
300                         WifiConfiguration config = (WifiConfiguration) msg.obj;
301                         int networkId = msg.arg1;
302                         Slog.d(TAG, "SAVE"
303                                 + " nid=" + Integer.toString(networkId)
304                                 + " config=" + config
305                                 + " uid=" + msg.sendingUid
306                                 + " name="
307                                 + mContext.getPackageManager().getNameForUid(msg.sendingUid));
308                         if (config != null) {
309                             /* Command is forwarded to state machine */
310                             mClientModeImpl.sendMessage(Message.obtain(msg));
311                         } else {
312                             Slog.e(TAG, "AsyncChannelExternalClientHandler.handleMessage "
313                                     + "ignoring invalid msg=" + msg);
314                             replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED,
315                                     WifiManager.INVALID_ARGS);
316                         }
317                     }
318                     break;
319                 }
320                 case WifiManager.FORGET_NETWORK:
321                     if (checkPrivilegedPermissionsAndReplyIfNotAuthorized(
322                             msg, WifiManager.FORGET_NETWORK_FAILED)) {
323                         mClientModeImpl.sendMessage(Message.obtain(msg));
324                     }
325                     break;
326                 case WifiManager.DISABLE_NETWORK:
327                     if (checkPrivilegedPermissionsAndReplyIfNotAuthorized(
328                             msg, WifiManager.DISABLE_NETWORK_FAILED)) {
329                         mClientModeImpl.sendMessage(Message.obtain(msg));
330                     }
331                     break;
332                 case WifiManager.RSSI_PKTCNT_FETCH: {
333                     if (checkChangePermissionAndReplyIfNotAuthorized(
334                             msg, WifiManager.RSSI_PKTCNT_FETCH_FAILED)) {
335                         mClientModeImpl.sendMessage(Message.obtain(msg));
336                     }
337                     break;
338                 }
339                 default: {
340                     Slog.d(TAG, "AsyncChannelExternalClientHandler.handleMessage "
341                             + "ignoring msg=" + msg);
342                     break;
343                 }
344             }
345         }
346 
347         /**
348          * Helper method to check if the sender of the message holds the
349          * {@link Manifest.permission#CHANGE_WIFI_STATE} permission, and reply with a failure if it
350          * doesn't
351          *
352          * @param msg Incoming message.
353          * @param replyWhat Param to be filled in the {@link Message#what} field of the failure
354          *                  reply.
355          * @return true if the sender holds the permission, false otherwise.
356          */
checkChangePermissionAndReplyIfNotAuthorized(Message msg, int replyWhat)357         private boolean checkChangePermissionAndReplyIfNotAuthorized(Message msg, int replyWhat) {
358             if (!mWifiPermissionsUtil.checkChangePermission(msg.sendingUid)) {
359                 Slog.e(TAG, "AsyncChannelExternalClientHandler.handleMessage "
360                         + "ignoring unauthorized msg=" + msg);
361                 replyFailed(msg, replyWhat, WifiManager.NOT_AUTHORIZED);
362                 return false;
363             }
364             return true;
365         }
366 
367         /**
368          * Helper method to check if the sender of the message holds one of
369          * {@link Manifest.permission#NETWORK_SETTINGS},
370          * {@link Manifest.permission#NETWORK_SETUP_WIZARD} or
371          * {@link Manifest.permission#NETWORK_STACK} permission, and reply with a failure if it
372          * doesn't
373          *
374          * @param msg Incoming message.
375          * @param replyWhat Param to be filled in the {@link Message#what} field of the failure
376          *                  reply.
377          * @return true if the sender holds the permission, false otherwise.
378          */
checkPrivilegedPermissionsAndReplyIfNotAuthorized( Message msg, int replyWhat)379         private boolean checkPrivilegedPermissionsAndReplyIfNotAuthorized(
380                 Message msg, int replyWhat) {
381             if (!isPrivileged(-1, msg.sendingUid)) {
382                 Slog.e(TAG, "ClientHandler.handleMessage ignoring unauthorized msg=" + msg);
383                 replyFailed(msg, replyWhat, WifiManager.NOT_AUTHORIZED);
384                 return false;
385             }
386             return true;
387         }
388 
replyFailed(Message msg, int what, int why)389         private void replyFailed(Message msg, int what, int why) {
390             if (msg.replyTo == null) return;
391             Message reply = Message.obtain();
392             reply.what = what;
393             reply.arg1 = why;
394             try {
395                 msg.replyTo.send(reply);
396             } catch (RemoteException e) {
397                 // There's not much we can do if reply can't be sent!
398             }
399         }
400     }
401     private AsyncChannelExternalClientHandler mAsyncChannelExternalClientHandler;
402 
403     /**
404      * Handles interaction with ClientModeImpl
405      */
406     private class ClientModeImplHandler extends WifiHandler {
407         private AsyncChannel mCmiChannel;
408 
ClientModeImplHandler(String tag, Looper looper, AsyncChannel asyncChannel)409         ClientModeImplHandler(String tag, Looper looper, AsyncChannel asyncChannel) {
410             super(tag, looper);
411             mCmiChannel = asyncChannel;
412             mCmiChannel.connect(mContext, this, mClientModeImpl.getHandler());
413         }
414 
415         @Override
handleMessage(Message msg)416         public void handleMessage(Message msg) {
417             super.handleMessage(msg);
418             switch (msg.what) {
419                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
420                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
421                         mClientModeImplChannel = mCmiChannel;
422                     } else {
423                         Slog.e(TAG, "ClientModeImpl connection failure, error=" + msg.arg1);
424                         mClientModeImplChannel = null;
425                     }
426                     break;
427                 }
428                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
429                     Slog.e(TAG, "ClientModeImpl channel lost, msg.arg1 =" + msg.arg1);
430                     mClientModeImplChannel = null;
431                     //Re-establish connection to state machine
432                     mCmiChannel.connect(mContext, this, mClientModeImpl.getHandler());
433                     break;
434                 }
435                 default: {
436                     Slog.d(TAG, "ClientModeImplHandler.handleMessage ignoring msg=" + msg);
437                     break;
438                 }
439             }
440         }
441     }
442 
443     ClientModeImplHandler mClientModeImplHandler;
444     private WifiController mWifiController;
445     private final WifiLockManager mWifiLockManager;
446     private final WifiMulticastLockManager mWifiMulticastLockManager;
447     private final DppManager mDppManager;
448 
449     private WifiApConfigStore mWifiApConfigStore;
450 
WifiServiceImpl(Context context, WifiInjector wifiInjector, AsyncChannel asyncChannel)451     public WifiServiceImpl(Context context, WifiInjector wifiInjector, AsyncChannel asyncChannel) {
452         mContext = context;
453         mWifiInjector = wifiInjector;
454         mClock = wifiInjector.getClock();
455 
456         mFacade = mWifiInjector.getFrameworkFacade();
457         mWifiMetrics = mWifiInjector.getWifiMetrics();
458         mWifiTrafficPoller = mWifiInjector.getWifiTrafficPoller();
459         mUserManager = mWifiInjector.getUserManager();
460         mCountryCode = mWifiInjector.getWifiCountryCode();
461         mClientModeImpl = mWifiInjector.getClientModeImpl();
462         mActiveModeWarden = mWifiInjector.getActiveModeWarden();
463         mClientModeImpl.enableRssiPolling(true);
464         mScanRequestProxy = mWifiInjector.getScanRequestProxy();
465         mSettingsStore = mWifiInjector.getWifiSettingsStore();
466         mPowerManager = mContext.getSystemService(PowerManager.class);
467         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
468         mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
469         mWifiLockManager = mWifiInjector.getWifiLockManager();
470         mWifiMulticastLockManager = mWifiInjector.getWifiMulticastLockManager();
471         HandlerThread wifiServiceHandlerThread = mWifiInjector.getWifiServiceHandlerThread();
472         mAsyncChannelExternalClientHandler =
473                 new AsyncChannelExternalClientHandler(TAG, wifiServiceHandlerThread.getLooper());
474         mClientModeImplHandler = new ClientModeImplHandler(TAG,
475                 wifiServiceHandlerThread.getLooper(), asyncChannel);
476         mWifiController = mWifiInjector.getWifiController();
477         mWifiBackupRestore = mWifiInjector.getWifiBackupRestore();
478         mWifiApConfigStore = mWifiInjector.getWifiApConfigStore();
479         mWifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil();
480         mLog = mWifiInjector.makeLog(TAG);
481         mFrameworkFacade = wifiInjector.getFrameworkFacade();
482         mIfaceIpModes = new ConcurrentHashMap<>();
483         mLocalOnlyHotspotRequests = new HashMap<>();
484         enableVerboseLoggingInternal(getVerboseLoggingLevel());
485         mRegisteredSoftApCallbacks =
486                 new ExternalCallbackTracker<ISoftApCallback>(mClientModeImplHandler);
487 
488         mWifiInjector.getActiveModeWarden().registerSoftApCallback(new SoftApCallbackImpl());
489         mPowerProfile = mWifiInjector.getPowerProfile();
490         mWifiNetworkSuggestionsManager = mWifiInjector.getWifiNetworkSuggestionsManager();
491         mDppManager = mWifiInjector.getDppManager();
492     }
493 
494     /**
495      * Provide a way for unit tests to set valid log object in the WifiHandler
496      * @param log WifiLog object to assign to the clientHandler
497      */
498     @VisibleForTesting
setWifiHandlerLogForTest(WifiLog log)499     public void setWifiHandlerLogForTest(WifiLog log) {
500         mAsyncChannelExternalClientHandler.setWifiLog(log);
501     }
502 
503     /**
504      * Check if we are ready to start wifi.
505      *
506      * First check if we will be restarting system services to decrypt the device. If the device is
507      * not encrypted, check if Wi-Fi needs to be enabled and start if needed
508      *
509      * This function is used only at boot time.
510      */
checkAndStartWifi()511     public void checkAndStartWifi() {
512         // First check if we will end up restarting WifiService
513         if (mFrameworkFacade.inStorageManagerCryptKeeperBounce()) {
514             Log.d(TAG, "Device still encrypted. Need to restart SystemServer.  Do not start wifi.");
515             return;
516         }
517 
518         // Check if wi-fi needs to be enabled
519         boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled();
520         Slog.i(TAG, "WifiService starting up with Wi-Fi " +
521                 (wifiEnabled ? "enabled" : "disabled"));
522 
523         registerForScanModeChange();
524         mContext.registerReceiver(
525                 new BroadcastReceiver() {
526                     @Override
527                     public void onReceive(Context context, Intent intent) {
528                         if (mSettingsStore.handleAirplaneModeToggled()) {
529                             mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED);
530                         }
531                         if (mSettingsStore.isAirplaneModeOn()) {
532                             Log.d(TAG, "resetting country code because Airplane mode is ON");
533                             mCountryCode.airplaneModeEnabled();
534                         }
535                     }
536                 },
537                 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
538 
539         mContext.registerReceiver(
540                 new BroadcastReceiver() {
541                     @Override
542                     public void onReceive(Context context, Intent intent) {
543                         String state = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
544                         if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state)) {
545                             Log.d(TAG, "resetting networks because SIM was removed");
546                             mClientModeImpl.resetSimAuthNetworks(false);
547                         } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state)) {
548                             Log.d(TAG, "resetting networks because SIM was loaded");
549                             mClientModeImpl.resetSimAuthNetworks(true);
550                         }
551                     }
552                 },
553                 new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
554 
555         mContext.registerReceiver(
556                 new BroadcastReceiver() {
557                     @Override
558                     public void onReceive(Context context, Intent intent) {
559                         final int currState = intent.getIntExtra(EXTRA_WIFI_AP_STATE,
560                                                                     WIFI_AP_STATE_DISABLED);
561                         final int prevState = intent.getIntExtra(EXTRA_PREVIOUS_WIFI_AP_STATE,
562                                                                  WIFI_AP_STATE_DISABLED);
563                         final int errorCode = intent.getIntExtra(EXTRA_WIFI_AP_FAILURE_REASON,
564                                                                  HOTSPOT_NO_ERROR);
565                         final String ifaceName =
566                                 intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME);
567                         final int mode = intent.getIntExtra(EXTRA_WIFI_AP_MODE,
568                                                             WifiManager.IFACE_IP_MODE_UNSPECIFIED);
569                         handleWifiApStateChange(currState, prevState, errorCode, ifaceName, mode);
570                     }
571                 },
572                 new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION));
573 
574         // Adding optimizations of only receiving broadcasts when wifi is enabled
575         // can result in race conditions when apps toggle wifi in the background
576         // without active user involvement. Always receive broadcasts.
577         registerForBroadcasts();
578         mInIdleMode = mPowerManager.isDeviceIdleMode();
579 
580         if (!mClientModeImpl.syncInitialize(mClientModeImplChannel)) {
581             Log.wtf(TAG, "Failed to initialize ClientModeImpl");
582         }
583         mWifiController.start();
584 
585         // If we are already disabled (could be due to airplane mode), avoid changing persist
586         // state here
587         if (wifiEnabled) {
588             setWifiEnabled(mContext.getPackageName(), wifiEnabled);
589         }
590     }
591 
handleBootCompleted()592     public void handleBootCompleted() {
593         Log.d(TAG, "Handle boot completed");
594         mClientModeImpl.handleBootCompleted();
595     }
596 
handleUserSwitch(int userId)597     public void handleUserSwitch(int userId) {
598         Log.d(TAG, "Handle user switch " + userId);
599         mClientModeImpl.handleUserSwitch(userId);
600     }
601 
handleUserUnlock(int userId)602     public void handleUserUnlock(int userId) {
603         Log.d(TAG, "Handle user unlock " + userId);
604         mClientModeImpl.handleUserUnlock(userId);
605     }
606 
handleUserStop(int userId)607     public void handleUserStop(int userId) {
608         Log.d(TAG, "Handle user stop " + userId);
609         mClientModeImpl.handleUserStop(userId);
610     }
611 
612     /**
613      * See {@link android.net.wifi.WifiManager#startScan}
614      *
615      * @param packageName Package name of the app that requests wifi scan.
616      */
617     @Override
startScan(String packageName)618     public boolean startScan(String packageName) {
619         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
620             return false;
621         }
622 
623         int callingUid = Binder.getCallingUid();
624         long ident = Binder.clearCallingIdentity();
625         mLog.info("startScan uid=%").c(callingUid).flush();
626         synchronized (this) {
627             if (mInIdleMode) {
628                 // Need to send an immediate scan result broadcast in case the
629                 // caller is waiting for a result ..
630 
631                 // TODO: investigate if the logic to cancel scans when idle can move to
632                 // WifiScanningServiceImpl.  This will 1 - clean up WifiServiceImpl and 2 -
633                 // avoid plumbing an awkward path to report a cancelled/failed scan.  This will
634                 // be sent directly until b/31398592 is fixed.
635                 sendFailedScanBroadcast();
636                 mScanPending = true;
637                 return false;
638             }
639         }
640         try {
641             mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, callingUid);
642             Mutable<Boolean> scanSuccess = new Mutable<>();
643             boolean runWithScissorsSuccess = mWifiInjector.getClientModeImplHandler()
644                     .runWithScissors(() -> {
645                         scanSuccess.value = mScanRequestProxy.startScan(callingUid, packageName);
646                     }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
647             if (!runWithScissorsSuccess) {
648                 Log.e(TAG, "Failed to post runnable to start scan");
649                 sendFailedScanBroadcast();
650                 return false;
651             }
652             if (!scanSuccess.value) {
653                 Log.e(TAG, "Failed to start scan");
654                 return false;
655             }
656         } catch (SecurityException e) {
657             Slog.e(TAG, "Permission violation - startScan not allowed for"
658                     + " uid=" + callingUid + ", packageName=" + packageName + ", reason=" + e);
659             return false;
660         } finally {
661             Binder.restoreCallingIdentity(ident);
662         }
663         return true;
664     }
665 
666     // Send a failed scan broadcast to indicate the current scan request failed.
sendFailedScanBroadcast()667     private void sendFailedScanBroadcast() {
668         // clear calling identity to send broadcast
669         long callingIdentity = Binder.clearCallingIdentity();
670         try {
671             Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
672             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
673             intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
674             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
675         } finally {
676             // restore calling identity
677             Binder.restoreCallingIdentity(callingIdentity);
678         }
679 
680     }
681 
682     /**
683      * WPS support in Client mode is deprecated.  Return null.
684      */
685     @Override
getCurrentNetworkWpsNfcConfigurationToken()686     public String getCurrentNetworkWpsNfcConfigurationToken() {
687         // while CLs are in flight, return null here, will be removed (b/72423090)
688         enforceConnectivityInternalPermission();
689         if (mVerboseLoggingEnabled) {
690             mLog.info("getCurrentNetworkWpsNfcConfigurationToken uid=%")
691                     .c(Binder.getCallingUid()).flush();
692         }
693         return null;
694     }
695 
696     boolean mInIdleMode;
697     boolean mScanPending;
698 
handleIdleModeChanged()699     void handleIdleModeChanged() {
700         boolean doScan = false;
701         synchronized (this) {
702             boolean idle = mPowerManager.isDeviceIdleMode();
703             if (mInIdleMode != idle) {
704                 mInIdleMode = idle;
705                 if (!idle) {
706                     if (mScanPending) {
707                         mScanPending = false;
708                         doScan = true;
709                     }
710                 }
711             }
712         }
713         if (doScan) {
714             // Someone requested a scan while we were idle; do a full scan now.
715             // A security check of the caller's identity was made when the request arrived via
716             // Binder. Now we'll pass the current process's identity to startScan().
717             startScan(mContext.getOpPackageName());
718         }
719     }
720 
checkNetworkSettingsPermission(int pid, int uid)721     private boolean checkNetworkSettingsPermission(int pid, int uid) {
722         return mContext.checkPermission(android.Manifest.permission.NETWORK_SETTINGS, pid, uid)
723                 == PERMISSION_GRANTED;
724     }
725 
checkNetworkSetupWizardPermission(int pid, int uid)726     private boolean checkNetworkSetupWizardPermission(int pid, int uid) {
727         return mContext.checkPermission(android.Manifest.permission.NETWORK_SETUP_WIZARD, pid, uid)
728                 == PackageManager.PERMISSION_GRANTED;
729     }
730 
checkNetworkStackPermission(int pid, int uid)731     private boolean checkNetworkStackPermission(int pid, int uid) {
732         return mContext.checkPermission(android.Manifest.permission.NETWORK_STACK, pid, uid)
733                 == PackageManager.PERMISSION_GRANTED;
734     }
735 
checkNetworkManagedProvisioningPermission(int pid, int uid)736     private boolean checkNetworkManagedProvisioningPermission(int pid, int uid) {
737         return mContext.checkPermission(android.Manifest.permission.NETWORK_MANAGED_PROVISIONING,
738                 pid, uid) == PackageManager.PERMISSION_GRANTED;
739     }
740 
741     // Helper method to check if the entity initiating the binder call has any of the signature only
742     // permissions.
isPrivileged(int pid, int uid)743     private boolean isPrivileged(int pid, int uid) {
744         return checkNetworkSettingsPermission(pid, uid)
745                 || checkNetworkSetupWizardPermission(pid, uid)
746                 || checkNetworkStackPermission(pid, uid)
747                 || checkNetworkManagedProvisioningPermission(pid, uid);
748     }
749 
750     // Helper method to check if the entity initiating the binder call has setup wizard or settings
751     // permissions.
isSettingsOrSuw(int pid, int uid)752     private boolean isSettingsOrSuw(int pid, int uid) {
753         return checkNetworkSettingsPermission(pid, uid)
754                 || checkNetworkSetupWizardPermission(pid, uid);
755     }
756 
757     // Helper method to check if the entity initiating the binder call is a system app.
isSystem(String packageName)758     private boolean isSystem(String packageName) {
759         long ident = Binder.clearCallingIdentity();
760         try {
761             ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(packageName, 0);
762             return info.isSystemApp() || info.isUpdatedSystemApp();
763         } catch (PackageManager.NameNotFoundException e) {
764             // In case of exception, assume unknown app (more strict checking)
765             // Note: This case will never happen since checkPackage is
766             // called to verify validity before checking App's version.
767         } finally {
768             Binder.restoreCallingIdentity(ident);
769         }
770         return false;
771     }
772 
773     // Helper method to check if the entity initiating the binder call is a DO/PO app.
isDeviceOrProfileOwner(int uid)774     private boolean isDeviceOrProfileOwner(int uid) {
775         final DevicePolicyManagerInternal dpmi =
776                 mWifiInjector.getWifiPermissionsWrapper().getDevicePolicyManagerInternal();
777         if (dpmi == null) return false;
778         return dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER)
779                 || dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
780     }
781 
enforceNetworkSettingsPermission()782     private void enforceNetworkSettingsPermission() {
783         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS,
784                 "WifiService");
785     }
786 
enforceNetworkStackPermission()787     private void enforceNetworkStackPermission() {
788         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK,
789                 "WifiService");
790     }
791 
enforceAccessPermission()792     private void enforceAccessPermission() {
793         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
794                 "WifiService");
795     }
796 
797     /**
798      * Checks whether the caller can change the wifi state.
799      * Possible results:
800      * 1. Operation is allowed. No exception thrown, and AppOpsManager.MODE_ALLOWED returned.
801      * 2. Operation is not allowed, and caller must be told about this. SecurityException is thrown.
802      * 3. Operation is not allowed, and caller must not be told about this (i.e. must silently
803      * ignore the operation). No exception is thrown, and AppOpsManager.MODE_IGNORED returned.
804      */
805     @CheckResult
enforceChangePermission(String callingPackage)806     private int enforceChangePermission(String callingPackage) {
807         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
808         if (checkNetworkSettingsPermission(Binder.getCallingPid(), Binder.getCallingUid())) {
809             return MODE_ALLOWED;
810         }
811         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
812                 "WifiService");
813 
814         return mAppOps.noteOp(
815                 AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Binder.getCallingUid(), callingPackage);
816     }
817 
enforceLocationHardwarePermission()818     private void enforceLocationHardwarePermission() {
819         mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE,
820                 "LocationHardware");
821     }
822 
enforceReadCredentialPermission()823     private void enforceReadCredentialPermission() {
824         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL,
825                                                 "WifiService");
826     }
827 
enforceWorkSourcePermission()828     private void enforceWorkSourcePermission() {
829         mContext.enforceCallingPermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
830                 "WifiService");
831 
832     }
833 
enforceMulticastChangePermission()834     private void enforceMulticastChangePermission() {
835         mContext.enforceCallingOrSelfPermission(
836                 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
837                 "WifiService");
838     }
839 
enforceConnectivityInternalPermission()840     private void enforceConnectivityInternalPermission() {
841         mContext.enforceCallingOrSelfPermission(
842                 android.Manifest.permission.CONNECTIVITY_INTERNAL,
843                 "ConnectivityService");
844     }
845 
enforceLocationPermission(String pkgName, int uid)846     private void enforceLocationPermission(String pkgName, int uid) {
847         mWifiPermissionsUtil.enforceLocationPermission(pkgName, uid);
848     }
849 
850     /**
851      * Helper method to check if the app is allowed to access public API's deprecated in
852      * {@link Build.VERSION_CODES.Q}.
853      * Note: Invoke mAppOps.checkPackage(uid, packageName) before to ensure correct package name.
854      */
isTargetSdkLessThanQOrPrivileged(String packageName, int pid, int uid)855     private boolean isTargetSdkLessThanQOrPrivileged(String packageName, int pid, int uid) {
856         return mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q)
857                 || isPrivileged(pid, uid)
858                 // DO/PO apps should be able to add/modify saved networks.
859                 || isDeviceOrProfileOwner(uid)
860                 // TODO: Remove this system app bypass once Q is released.
861                 || isSystem(packageName)
862                 || mWifiPermissionsUtil.checkSystemAlertWindowPermission(uid, packageName);
863     }
864 
865     /**
866      * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
867      * @param enable {@code true} to enable, {@code false} to disable.
868      * @return {@code true} if the enable/disable operation was
869      *         started or is already in the queue.
870      */
871     @Override
setWifiEnabled(String packageName, boolean enable)872     public synchronized boolean setWifiEnabled(String packageName, boolean enable) {
873         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
874             return false;
875         }
876         boolean isPrivileged = isPrivileged(Binder.getCallingPid(), Binder.getCallingUid());
877         if (!isPrivileged
878                 && !mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q)) {
879             mLog.info("setWifiEnabled not allowed for uid=%")
880                     .c(Binder.getCallingUid()).flush();
881             return false;
882         }
883         // If Airplane mode is enabled, only privileged apps are allowed to toggle Wifi
884         if (mSettingsStore.isAirplaneModeOn() && !isPrivileged) {
885             mLog.err("setWifiEnabled in Airplane mode: only Settings can toggle wifi").flush();
886             return false;
887         }
888 
889         // If SoftAp is enabled, only privileged apps are allowed to toggle wifi
890         boolean apEnabled = mWifiApState == WifiManager.WIFI_AP_STATE_ENABLED;
891         if (apEnabled && !isPrivileged) {
892             mLog.err("setWifiEnabled SoftAp enabled: only Settings can toggle wifi").flush();
893             return false;
894         }
895 
896         mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName)
897                 .c(Binder.getCallingUid()).c(enable).flush();
898         long ident = Binder.clearCallingIdentity();
899         try {
900             if (!mSettingsStore.handleWifiToggled(enable)) {
901                 // Nothing to do if wifi cannot be toggled
902                 return true;
903             }
904         } finally {
905             Binder.restoreCallingIdentity(ident);
906         }
907         mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable);
908         mWifiController.sendMessage(CMD_WIFI_TOGGLED);
909         return true;
910     }
911 
912     /**
913      * see {@link WifiManager#getWifiState()}
914      * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
915      *         {@link WifiManager#WIFI_STATE_DISABLING},
916      *         {@link WifiManager#WIFI_STATE_ENABLED},
917      *         {@link WifiManager#WIFI_STATE_ENABLING},
918      *         {@link WifiManager#WIFI_STATE_UNKNOWN}
919      */
920     @Override
getWifiEnabledState()921     public int getWifiEnabledState() {
922         enforceAccessPermission();
923         if (mVerboseLoggingEnabled) {
924             mLog.info("getWifiEnabledState uid=%").c(Binder.getCallingUid()).flush();
925         }
926         return mClientModeImpl.syncGetWifiState();
927     }
928 
929     /**
930      * see {@link WifiManager#getWifiApState()}
931      * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
932      *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
933      *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
934      *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
935      *         {@link WifiManager#WIFI_AP_STATE_FAILED}
936      */
937     @Override
getWifiApEnabledState()938     public int getWifiApEnabledState() {
939         enforceAccessPermission();
940         if (mVerboseLoggingEnabled) {
941             mLog.info("getWifiApEnabledState uid=%").c(Binder.getCallingUid()).flush();
942         }
943 
944         // hand off work to our handler thread
945         MutableInt apState = new MutableInt(WifiManager.WIFI_AP_STATE_DISABLED);
946         mWifiInjector.getClientModeImplHandler().runWithScissors(() -> {
947             apState.value = mWifiApState;
948         }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
949         return apState.value;
950     }
951 
952     /**
953      * see {@link android.net.wifi.WifiManager#updateInterfaceIpState(String, int)}
954      *
955      * The possible modes include: {@link WifiManager#IFACE_IP_MODE_TETHERED},
956      *                             {@link WifiManager#IFACE_IP_MODE_LOCAL_ONLY},
957      *                             {@link WifiManager#IFACE_IP_MODE_CONFIGURATION_ERROR}
958      *
959      * @param ifaceName String name of the updated interface
960      * @param mode new operating mode of the interface
961      *
962      * @throws SecurityException if the caller does not have permission to call update
963      */
964     @Override
updateInterfaceIpState(String ifaceName, int mode)965     public void updateInterfaceIpState(String ifaceName, int mode) {
966         // NETWORK_STACK is a signature only permission.
967         enforceNetworkStackPermission();
968         mLog.info("updateInterfaceIpState uid=%").c(Binder.getCallingUid()).flush();
969 
970         // hand off the work to our handler thread
971         mWifiInjector.getClientModeImplHandler().post(() -> {
972             updateInterfaceIpStateInternal(ifaceName, mode);
973         });
974     }
975 
updateInterfaceIpStateInternal(String ifaceName, int mode)976     private void updateInterfaceIpStateInternal(String ifaceName, int mode) {
977         // update interface IP state related to tethering and hotspot
978         synchronized (mLocalOnlyHotspotRequests) {
979             // update the mode tracker here - we clear out state below
980             Integer previousMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
981             if (ifaceName != null) {
982                 previousMode = mIfaceIpModes.put(ifaceName, mode);
983             }
984             Slog.d(TAG, "updateInterfaceIpState: ifaceName=" + ifaceName + " mode=" + mode
985                     + " previous mode= " + previousMode);
986 
987             switch (mode) {
988                 case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
989                     // first make sure we have registered requests..  otherwise clean up
990                     if (mLocalOnlyHotspotRequests.isEmpty()) {
991                         // we don't have requests...  stop the hotspot
992                         stopSoftAp();
993                         updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
994                         return;
995                     }
996                     // LOHS is ready to go!  Call our registered requestors!
997                     sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked();
998                     break;
999                 case WifiManager.IFACE_IP_MODE_TETHERED:
1000                     if (!isConcurrentLohsAndTetheringSupported()) {
1001                         /* We have tethered an interface. We don't really act on this now other than
1002                          * if we have LOHS requests, and this is an issue. Return incompatible mode
1003                          * for onFailed for the registered requestors since this can result from a
1004                          * race between a tether request and a hotspot request (tethering wins). */
1005                         sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
1006                                 LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE);
1007                     }
1008                     break;
1009                 case WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR:
1010                     Slog.d(TAG, "IP mode config error - need to clean up");
1011                     if (mLocalOnlyHotspotRequests.isEmpty()) {
1012                         Slog.d(TAG, "no LOHS requests, stop softap");
1013                         stopSoftAp();
1014                     } else {
1015                         Slog.d(TAG, "we have LOHS requests, clean them up");
1016                         // there was an error setting up the hotspot...  trigger onFailed for the
1017                         // registered LOHS requestors
1018                         sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
1019                                 LocalOnlyHotspotCallback.ERROR_GENERIC);
1020                     }
1021                     updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
1022                     break;
1023                 case WifiManager.IFACE_IP_MODE_UNSPECIFIED:
1024                     if (ifaceName == null) {
1025                         // interface name is null, this is due to softap teardown.  clear all
1026                         // entries for now.
1027                         // TODO: Deal with individual interfaces when we receive updates for them
1028                         mIfaceIpModes.clear();
1029                         return;
1030                     }
1031                     break;
1032                 default:
1033                     mLog.warn("updateInterfaceIpStateInternal: unknown mode %").c(mode).flush();
1034             }
1035         }
1036     }
1037 
1038     /**
1039      * see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)}
1040      * @param wifiConfig SSID, security and channel details as part of WifiConfiguration
1041      * @return {@code true} if softap start was triggered
1042      * @throws SecurityException if the caller does not have permission to start softap
1043      */
1044     @Override
startSoftAp(WifiConfiguration wifiConfig)1045     public boolean startSoftAp(WifiConfiguration wifiConfig) {
1046         // NETWORK_STACK is a signature only permission.
1047         enforceNetworkStackPermission();
1048 
1049         mLog.info("startSoftAp uid=%").c(Binder.getCallingUid()).flush();
1050 
1051         synchronized (mLocalOnlyHotspotRequests) {
1052             // If a tethering request comes in while we have an existing tethering session, return
1053             // error.
1054             if (mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_TETHERED)) {
1055                 mLog.err("Tethering is already active.").flush();
1056                 return false;
1057             }
1058             // If a tethering request comes in while we have LOHS running (or requested), call stop
1059             // for softap mode and restart softap with the tethering config.
1060             if (!isConcurrentLohsAndTetheringSupported() && !mLocalOnlyHotspotRequests.isEmpty()) {
1061                 stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
1062             }
1063             return startSoftApInternal(wifiConfig, WifiManager.IFACE_IP_MODE_TETHERED);
1064         }
1065     }
1066 
1067     /**
1068      * Internal method to start softap mode. Callers of this method should have already checked
1069      * proper permissions beyond the NetworkStack permission.
1070      */
startSoftApInternal(WifiConfiguration wifiConfig, int mode)1071     private boolean startSoftApInternal(WifiConfiguration wifiConfig, int mode) {
1072         mLog.trace("startSoftApInternal uid=% mode=%")
1073                 .c(Binder.getCallingUid()).c(mode).flush();
1074 
1075         // null wifiConfig is a meaningful input for CMD_SET_AP
1076         if (wifiConfig == null || WifiApConfigStore.validateApWifiConfiguration(wifiConfig)) {
1077             SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
1078             mWifiController.sendMessage(CMD_SET_AP, 1, 0, softApConfig);
1079             return true;
1080         }
1081         Slog.e(TAG, "Invalid WifiConfiguration");
1082         return false;
1083     }
1084 
1085     /**
1086      * see {@link android.net.wifi.WifiManager#stopSoftAp()}
1087      * @return {@code true} if softap stop was triggered
1088      * @throws SecurityException if the caller does not have permission to stop softap
1089      */
1090     @Override
stopSoftAp()1091     public boolean stopSoftAp() {
1092         // NETWORK_STACK is a signature only permission.
1093         enforceNetworkStackPermission();
1094 
1095         // only permitted callers are allowed to this point - they must have gone through
1096         // connectivity service since this method is protected with the NETWORK_STACK PERMISSION
1097 
1098         mLog.info("stopSoftAp uid=%").c(Binder.getCallingUid()).flush();
1099 
1100         synchronized (mLocalOnlyHotspotRequests) {
1101             // If a tethering request comes in while we have LOHS running (or requested), call stop
1102             // for softap mode and restart softap with the tethering config.
1103             if (!mLocalOnlyHotspotRequests.isEmpty()) {
1104                 // This shouldn't affect devices that support concurrent LOHS and tethering
1105                 mLog.trace("Call to stop Tethering while LOHS is active,"
1106                         + " Registered LOHS callers will be updated when softap stopped.").flush();
1107             }
1108 
1109             return stopSoftApInternal(WifiManager.IFACE_IP_MODE_TETHERED);
1110         }
1111     }
1112 
1113     /**
1114      * Internal method to stop softap mode.  Callers of this method should have already checked
1115      * proper permissions beyond the NetworkStack permission.
1116      */
stopSoftApInternal(int mode)1117     private boolean stopSoftApInternal(int mode) {
1118         mLog.trace("stopSoftApInternal uid=%").c(Binder.getCallingUid()).flush();
1119 
1120         mWifiController.sendMessage(CMD_SET_AP, 0, mode);
1121         return true;
1122     }
1123 
1124     /**
1125      * Callback to use with ClientModeImpl to receive events from ClientModeImpl
1126      *
1127      * @hide
1128      */
1129     private final class SoftApCallbackImpl implements WifiManager.SoftApCallback {
1130         /**
1131          * Called when soft AP state changes.
1132          *
1133          * @param state new new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
1134          *        {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
1135          *        {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
1136          * @param failureReason reason when in failed state. One of
1137          *        {@link #SAP_START_FAILURE_GENERAL}, {@link #SAP_START_FAILURE_NO_CHANNEL}
1138          */
1139         @Override
onStateChanged(int state, int failureReason)1140         public void onStateChanged(int state, int failureReason) {
1141             mSoftApState = state;
1142 
1143             Iterator<ISoftApCallback> iterator =
1144                     mRegisteredSoftApCallbacks.getCallbacks().iterator();
1145             while (iterator.hasNext()) {
1146                 ISoftApCallback callback = iterator.next();
1147                 try {
1148                     callback.onStateChanged(state, failureReason);
1149                 } catch (RemoteException e) {
1150                     Log.e(TAG, "onStateChanged: remote exception -- " + e);
1151                     iterator.remove();
1152                 }
1153             }
1154         }
1155 
1156         /**
1157          * Called when number of connected clients to soft AP changes.
1158          *
1159          * @param numClients number of connected clients to soft AP
1160          */
1161         @Override
onNumClientsChanged(int numClients)1162         public void onNumClientsChanged(int numClients) {
1163             mSoftApNumClients = numClients;
1164 
1165             Iterator<ISoftApCallback> iterator =
1166                     mRegisteredSoftApCallbacks.getCallbacks().iterator();
1167             while (iterator.hasNext()) {
1168                 ISoftApCallback callback = iterator.next();
1169                 try {
1170                     callback.onNumClientsChanged(numClients);
1171                 } catch (RemoteException e) {
1172                     Log.e(TAG, "onNumClientsChanged: remote exception -- " + e);
1173                     iterator.remove();
1174                 }
1175             }
1176         }
1177     }
1178 
1179     /**
1180      * see {@link android.net.wifi.WifiManager#registerSoftApCallback(SoftApCallback, Handler)}
1181      *
1182      * @param binder IBinder instance to allow cleanup if the app dies
1183      * @param callback Soft AP callback to register
1184      * @param callbackIdentifier Unique ID of the registering callback. This ID will be used to
1185      *        unregister the callback. See {@link unregisterSoftApCallback(int)}
1186      *
1187      * @throws SecurityException if the caller does not have permission to register a callback
1188      * @throws RemoteException if remote exception happens
1189      * @throws IllegalArgumentException if the arguments are null or invalid
1190      */
1191     @Override
registerSoftApCallback(IBinder binder, ISoftApCallback callback, int callbackIdentifier)1192     public void registerSoftApCallback(IBinder binder, ISoftApCallback callback,
1193             int callbackIdentifier) {
1194         // verify arguments
1195         if (binder == null) {
1196             throw new IllegalArgumentException("Binder must not be null");
1197         }
1198         if (callback == null) {
1199             throw new IllegalArgumentException("Callback must not be null");
1200         }
1201 
1202         enforceNetworkSettingsPermission();
1203         if (mVerboseLoggingEnabled) {
1204             mLog.info("registerSoftApCallback uid=%").c(Binder.getCallingUid()).flush();
1205         }
1206 
1207         // post operation to handler thread
1208         mWifiInjector.getClientModeImplHandler().post(() -> {
1209             if (!mRegisteredSoftApCallbacks.add(binder, callback, callbackIdentifier)) {
1210                 Log.e(TAG, "registerSoftApCallback: Failed to add callback");
1211                 return;
1212             }
1213             // Update the client about the current state immediately after registering the callback
1214             try {
1215                 callback.onStateChanged(mSoftApState, 0);
1216                 callback.onNumClientsChanged(mSoftApNumClients);
1217             } catch (RemoteException e) {
1218                 Log.e(TAG, "registerSoftApCallback: remote exception -- " + e);
1219             }
1220 
1221         });
1222     }
1223 
1224     /**
1225      * see {@link android.net.wifi.WifiManager#unregisterSoftApCallback(SoftApCallback)}
1226      *
1227      * @param callbackIdentifier Unique ID of the callback to be unregistered.
1228      *
1229      * @throws SecurityException if the caller does not have permission to register a callback
1230      */
1231     @Override
unregisterSoftApCallback(int callbackIdentifier)1232     public void unregisterSoftApCallback(int callbackIdentifier) {
1233 
1234         enforceNetworkSettingsPermission();
1235         if (mVerboseLoggingEnabled) {
1236             mLog.info("unregisterSoftApCallback uid=%").c(Binder.getCallingUid()).flush();
1237         }
1238 
1239         // post operation to handler thread
1240         mWifiInjector.getClientModeImplHandler().post(() -> {
1241             mRegisteredSoftApCallbacks.remove(callbackIdentifier);
1242         });
1243     }
1244 
1245     /**
1246      * Private method to handle SoftAp state changes
1247      *
1248      * <p> MUST be called from the ClientModeImpl thread.
1249      */
handleWifiApStateChange( int currentState, int previousState, int errorCode, String ifaceName, int mode)1250     private void handleWifiApStateChange(
1251             int currentState, int previousState, int errorCode, String ifaceName, int mode) {
1252         // The AP state update from ClientModeImpl for softap
1253         Slog.d(TAG, "handleWifiApStateChange: currentState=" + currentState
1254                 + " previousState=" + previousState + " errorCode= " + errorCode
1255                 + " ifaceName=" + ifaceName + " mode=" + mode);
1256 
1257         // update the tracking ap state variable
1258         mWifiApState = currentState;
1259 
1260         // check if we have a failure - since it is possible (worst case scenario where
1261         // WifiController and ClientModeImpl are out of sync wrt modes) to get two FAILED
1262         // notifications in a row, we need to handle this first.
1263         if (currentState == WIFI_AP_STATE_FAILED) {
1264             // update registered LOHS callbacks if we see a failure
1265             synchronized (mLocalOnlyHotspotRequests) {
1266                 int errorToReport = ERROR_GENERIC;
1267                 if (errorCode == SAP_START_FAILURE_NO_CHANNEL) {
1268                     errorToReport = ERROR_NO_CHANNEL;
1269                 }
1270                 // holding the required lock: send message to requestors and clear the list
1271                 sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
1272                         errorToReport);
1273                 // also need to clear interface ip state - send null for now since we don't know
1274                 // what interface (and we have one anyway)
1275                 updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
1276             }
1277             return;
1278         }
1279 
1280         if (currentState == WIFI_AP_STATE_DISABLING || currentState == WIFI_AP_STATE_DISABLED) {
1281             // softap is shutting down or is down...  let requestors know via the onStopped call
1282             synchronized (mLocalOnlyHotspotRequests) {
1283                 // if we are currently in hotspot mode, then trigger onStopped for registered
1284                 // requestors, otherwise something odd happened and we should clear state
1285                 if (mIfaceIpModes.getOrDefault(ifaceName, WifiManager.IFACE_IP_MODE_UNSPECIFIED)
1286                         == WifiManager.IFACE_IP_MODE_LOCAL_ONLY) {
1287                     // holding the required lock: send message to requestors and clear the list
1288                     sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked();
1289                 } else if (!isConcurrentLohsAndTetheringSupported()) {
1290                     // LOHS not active: report an error (still holding the required lock)
1291                     sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(ERROR_GENERIC);
1292                 }
1293                 // also clear interface ip state - send null for now since we don't know what
1294                 // interface (and we only have one anyway)
1295                 updateInterfaceIpState(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
1296             }
1297             return;
1298         }
1299 
1300         // remaining states are enabling or enabled...  those are not used for the callbacks
1301     }
1302 
1303     /**
1304      * Helper method to send a HOTSPOT_FAILED message to all registered LocalOnlyHotspotRequest
1305      * callers and clear the registrations.
1306      *
1307      * Callers should already hold the mLocalOnlyHotspotRequests lock.
1308      */
1309     @GuardedBy("mLocalOnlyHotspotRequests")
sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(int arg1)1310     private void sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(int arg1) {
1311         for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
1312             try {
1313                 requestor.sendHotspotFailedMessage(arg1);
1314                 requestor.unlinkDeathRecipient();
1315             } catch (RemoteException e) {
1316                 // This will be cleaned up by binder death handling
1317             }
1318         }
1319 
1320         // Since all callers were notified, now clear the registrations.
1321         mLocalOnlyHotspotRequests.clear();
1322     }
1323 
1324     /**
1325      * Helper method to send a HOTSPOT_STOPPED message to all registered LocalOnlyHotspotRequest
1326      * callers and clear the registrations.
1327      *
1328      * Callers should already hold the mLocalOnlyHotspotRequests lock.
1329      */
1330     @GuardedBy("mLocalOnlyHotspotRequests")
sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked()1331     private void sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked() {
1332         for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
1333             try {
1334                 requestor.sendHotspotStoppedMessage();
1335                 requestor.unlinkDeathRecipient();
1336             } catch (RemoteException e) {
1337                 // This will be cleaned up by binder death handling
1338             }
1339         }
1340 
1341         // Since all callers were notified, now clear the registrations.
1342         mLocalOnlyHotspotRequests.clear();
1343     }
1344 
1345     /**
1346      * Helper method to send a HOTSPOT_STARTED message to all registered LocalOnlyHotspotRequest
1347      * callers.
1348      *
1349      * Callers should already hold the mLocalOnlyHotspotRequests lock.
1350      */
1351     @GuardedBy("mLocalOnlyHotspotRequests")
sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked()1352     private void sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked() {
1353         for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
1354             try {
1355                 requestor.sendHotspotStartedMessage(mLocalOnlyHotspotConfig);
1356             } catch (RemoteException e) {
1357                 // This will be cleaned up by binder death handling
1358             }
1359         }
1360     }
1361 
1362     /**
1363      * Temporary method used for testing while startLocalOnlyHotspot is not fully implemented.  This
1364      * method allows unit tests to register callbacks directly for testing mechanisms triggered by
1365      * softap mode changes.
1366      */
1367     @VisibleForTesting
registerLOHSForTest(int pid, LocalOnlyHotspotRequestInfo request)1368     void registerLOHSForTest(int pid, LocalOnlyHotspotRequestInfo request) {
1369         mLocalOnlyHotspotRequests.put(pid, request);
1370     }
1371 
1372     /**
1373      * Method to start LocalOnlyHotspot.  In this method, permissions, settings and modes are
1374      * checked to verify that we can enter softapmode.  This method returns
1375      * {@link LocalOnlyHotspotCallback#REQUEST_REGISTERED} if we will attempt to start, otherwise,
1376      * possible startup erros may include tethering being disallowed failure reason {@link
1377      * LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED} or an incompatible mode failure reason
1378      * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE}.
1379      *
1380      * see {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback)}
1381      *
1382      * @param messenger Messenger to send messages to the corresponding WifiManager.
1383      * @param binder IBinder instance to allow cleanup if the app dies
1384      * @param packageName String name of the calling package
1385      *
1386      * @return int return code for attempt to start LocalOnlyHotspot.
1387      *
1388      * @throws SecurityException if the caller does not have permission to start a Local Only
1389      * Hotspot.
1390      * @throws IllegalStateException if the caller attempts to start the LocalOnlyHotspot while they
1391      * have an outstanding request.
1392      */
1393     @Override
startLocalOnlyHotspot(Messenger messenger, IBinder binder, String packageName)1394     public int startLocalOnlyHotspot(Messenger messenger, IBinder binder, String packageName) {
1395         // first check if the caller has permission to start a local only hotspot
1396         // need to check for WIFI_STATE_CHANGE and location permission
1397         final int uid = Binder.getCallingUid();
1398         final int pid = Binder.getCallingPid();
1399 
1400         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
1401             return LocalOnlyHotspotCallback.ERROR_GENERIC;
1402         }
1403         enforceLocationPermission(packageName, uid);
1404         long ident = Binder.clearCallingIdentity();
1405         try {
1406             // also need to verify that Locations services are enabled.
1407             if (!mWifiPermissionsUtil.isLocationModeEnabled()) {
1408                 throw new SecurityException("Location mode is not enabled.");
1409             }
1410         } finally {
1411             Binder.restoreCallingIdentity(ident);
1412         }
1413 
1414         // verify that tethering is not disabled
1415         if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
1416             return LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED;
1417         }
1418 
1419         // the app should be in the foreground
1420         if (!mFrameworkFacade.isAppForeground(uid)) {
1421             return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
1422         }
1423 
1424         mLog.info("startLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush();
1425 
1426         synchronized (mLocalOnlyHotspotRequests) {
1427             // check if we are currently tethering
1428             // TODO(b/123227116): handle all interface combinations just by changing the HAL.
1429             if (!isConcurrentLohsAndTetheringSupported()
1430                     && mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_TETHERED)) {
1431                 // Tethering is enabled, cannot start LocalOnlyHotspot
1432                 mLog.info("Cannot start localOnlyHotspot when WiFi Tethering is active.").flush();
1433                 return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
1434             }
1435 
1436             // does this caller already have a request?
1437             LocalOnlyHotspotRequestInfo request = mLocalOnlyHotspotRequests.get(pid);
1438             if (request != null) {
1439                 mLog.trace("caller already has an active request").flush();
1440                 throw new IllegalStateException(
1441                         "Caller already has an active LocalOnlyHotspot request");
1442             }
1443 
1444             // now create the new LOHS request info object
1445             request = new LocalOnlyHotspotRequestInfo(binder, messenger,
1446                     new LocalOnlyRequestorCallback());
1447 
1448             // check current operating state and take action if needed
1449             if (mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_LOCAL_ONLY)) {
1450                 // LOHS is already active, send out what is running
1451                 try {
1452                     mLog.trace("LOHS already up, trigger onStarted callback").flush();
1453                     request.sendHotspotStartedMessage(mLocalOnlyHotspotConfig);
1454                 } catch (RemoteException e) {
1455                     return LocalOnlyHotspotCallback.ERROR_GENERIC;
1456                 }
1457             } else if (mLocalOnlyHotspotRequests.isEmpty()) {
1458                 // this is the first request, then set up our config and start LOHS
1459                 boolean is5Ghz = hasAutomotiveFeature(mContext)
1460                         && mContext.getResources().getBoolean(
1461                         com.android.internal.R.bool.config_wifi_local_only_hotspot_5ghz)
1462                         && is5GhzSupported();
1463 
1464                 mLocalOnlyHotspotConfig = WifiApConfigStore.generateLocalOnlyHotspotConfig(mContext,
1465                         is5Ghz ? WifiConfiguration.AP_BAND_5GHZ : WifiConfiguration.AP_BAND_2GHZ);
1466 
1467                 startSoftApInternal(mLocalOnlyHotspotConfig, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
1468             }
1469 
1470             mLocalOnlyHotspotRequests.put(pid, request);
1471             return LocalOnlyHotspotCallback.REQUEST_REGISTERED;
1472         }
1473     }
1474 
1475     /**
1476      * see {@link WifiManager#stopLocalOnlyHotspot()}
1477      *
1478      * @throws SecurityException if the caller does not have permission to stop a Local Only
1479      * Hotspot.
1480      */
1481     @Override
stopLocalOnlyHotspot()1482     public void stopLocalOnlyHotspot() {
1483         // don't do a permission check here. if the app's permission to change the wifi state is
1484         // revoked, we still want them to be able to stop a previously created hotspot (otherwise
1485         // it could cost the user money). When the app created the hotspot, its permission was
1486         // checked.
1487         final int uid = Binder.getCallingUid();
1488         final int pid = Binder.getCallingPid();
1489 
1490         mLog.info("stopLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush();
1491 
1492         synchronized (mLocalOnlyHotspotRequests) {
1493             // was the caller already registered?  check request tracker - return false if not
1494             LocalOnlyHotspotRequestInfo requestInfo = mLocalOnlyHotspotRequests.get(pid);
1495             if (requestInfo == null) {
1496                 return;
1497             }
1498             requestInfo.unlinkDeathRecipient();
1499             unregisterCallingAppAndStopLocalOnlyHotspot(requestInfo);
1500         } // end synchronized
1501     }
1502 
1503     /**
1504      * Helper method to unregister LocalOnlyHotspot requestors and stop the hotspot if needed.
1505      */
unregisterCallingAppAndStopLocalOnlyHotspot(LocalOnlyHotspotRequestInfo request)1506     private void unregisterCallingAppAndStopLocalOnlyHotspot(LocalOnlyHotspotRequestInfo request) {
1507         mLog.trace("unregisterCallingAppAndStopLocalOnlyHotspot pid=%").c(request.getPid()).flush();
1508 
1509         synchronized (mLocalOnlyHotspotRequests) {
1510             if (mLocalOnlyHotspotRequests.remove(request.getPid()) == null) {
1511                 mLog.trace("LocalOnlyHotspotRequestInfo not found to remove").flush();
1512                 return;
1513             }
1514 
1515             if (mLocalOnlyHotspotRequests.isEmpty()) {
1516                 mLocalOnlyHotspotConfig = null;
1517                 updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
1518                 // if that was the last caller, then call stopSoftAp as WifiService
1519                 long identity = Binder.clearCallingIdentity();
1520                 try {
1521                     stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
1522                 } finally {
1523                     Binder.restoreCallingIdentity(identity);
1524                 }
1525             }
1526         }
1527     }
1528 
1529     /**
1530      * see {@link WifiManager#watchLocalOnlyHotspot(LocalOnlyHotspotObserver)}
1531      *
1532      * This call requires the android.permission.NETWORK_SETTINGS permission.
1533      *
1534      * @param messenger Messenger to send messages to the corresponding WifiManager.
1535      * @param binder IBinder instance to allow cleanup if the app dies
1536      *
1537      * @throws SecurityException if the caller does not have permission to watch Local Only Hotspot
1538      * status updates.
1539      * @throws IllegalStateException if the caller attempts to watch LocalOnlyHotspot updates with
1540      * an existing subscription.
1541      */
1542     @Override
startWatchLocalOnlyHotspot(Messenger messenger, IBinder binder)1543     public void startWatchLocalOnlyHotspot(Messenger messenger, IBinder binder) {
1544         // NETWORK_SETTINGS is a signature only permission.
1545         enforceNetworkSettingsPermission();
1546 
1547         throw new UnsupportedOperationException("LocalOnlyHotspot is still in development");
1548     }
1549 
1550     /**
1551      * see {@link WifiManager#unregisterLocalOnlyHotspotObserver()}
1552      */
1553     @Override
stopWatchLocalOnlyHotspot()1554     public void stopWatchLocalOnlyHotspot() {
1555         // NETWORK_STACK is a signature only permission.
1556         enforceNetworkSettingsPermission();
1557         throw new UnsupportedOperationException("LocalOnlyHotspot is still in development");
1558     }
1559 
1560     /**
1561      * see {@link WifiManager#getWifiApConfiguration()}
1562      * @return soft access point configuration
1563      * @throws SecurityException if the caller does not have permission to retrieve the softap
1564      * config
1565      */
1566     @Override
getWifiApConfiguration()1567     public WifiConfiguration getWifiApConfiguration() {
1568         enforceAccessPermission();
1569         int uid = Binder.getCallingUid();
1570         // only allow Settings UI to get the saved SoftApConfig
1571         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {
1572             // random apps should not be allowed to read the user specified config
1573             throw new SecurityException("App not allowed to read or update stored WiFi Ap config "
1574                     + "(uid = " + uid + ")");
1575         }
1576         mLog.info("getWifiApConfiguration uid=%").c(uid).flush();
1577 
1578         // hand off work to the ClientModeImpl handler thread to sync work between calls
1579         // and SoftApManager starting up softap
1580         final Mutable<WifiConfiguration> config = new Mutable();
1581         boolean success = mWifiInjector.getClientModeImplHandler().runWithScissors(() -> {
1582             config.value = mWifiApConfigStore.getApConfiguration();
1583         }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
1584         if (success) {
1585             return config.value;
1586         }
1587         Log.e(TAG, "Failed to post runnable to fetch ap config");
1588         return new WifiConfiguration();
1589     }
1590 
1591     /**
1592      * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
1593      * @param wifiConfig WifiConfiguration details for soft access point
1594      * @return boolean indicating success or failure of the operation
1595      * @throws SecurityException if the caller does not have permission to write the softap config
1596      */
1597     @Override
setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName)1598     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName) {
1599         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
1600             return false;
1601         }
1602         int uid = Binder.getCallingUid();
1603         // only allow Settings UI to write the stored SoftApConfig
1604         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {
1605             // random apps should not be allowed to read the user specified config
1606             throw new SecurityException("App not allowed to read or update stored WiFi AP config "
1607                     + "(uid = " + uid + ")");
1608         }
1609         mLog.info("setWifiApConfiguration uid=%").c(uid).flush();
1610         if (wifiConfig == null)
1611             return false;
1612         if (WifiApConfigStore.validateApWifiConfiguration(wifiConfig)) {
1613             mClientModeImplHandler.post(() -> {
1614                 mWifiApConfigStore.setApConfiguration(wifiConfig);
1615             });
1616             return true;
1617         } else {
1618             Slog.e(TAG, "Invalid WifiConfiguration");
1619             return false;
1620         }
1621     }
1622 
1623     /**
1624      * Method used to inform user of Ap Configuration conversion due to hardware.
1625      */
1626     @Override
notifyUserOfApBandConversion(String packageName)1627     public void notifyUserOfApBandConversion(String packageName) {
1628         enforceNetworkSettingsPermission();
1629 
1630         if (mVerboseLoggingEnabled) {
1631             mLog.info("notifyUserOfApBandConversion uid=% packageName=%")
1632                     .c(Binder.getCallingUid()).c(packageName).flush();
1633         }
1634 
1635         mWifiApConfigStore.notifyUserOfApBandConversion(packageName);
1636     }
1637 
1638     /**
1639      * see {@link android.net.wifi.WifiManager#isScanAlwaysAvailable()}
1640      */
1641     @Override
isScanAlwaysAvailable()1642     public boolean isScanAlwaysAvailable() {
1643         enforceAccessPermission();
1644         if (mVerboseLoggingEnabled) {
1645             mLog.info("isScanAlwaysAvailable uid=%").c(Binder.getCallingUid()).flush();
1646         }
1647         return mSettingsStore.isScanAlwaysAvailable();
1648     }
1649 
1650     /**
1651      * see {@link android.net.wifi.WifiManager#disconnect()}
1652      */
1653     @Override
disconnect(String packageName)1654     public boolean disconnect(String packageName) {
1655         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
1656             return false;
1657         }
1658         if (!isTargetSdkLessThanQOrPrivileged(
1659                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
1660             mLog.info("disconnect not allowed for uid=%")
1661                     .c(Binder.getCallingUid()).flush();
1662             return false;
1663         }
1664         mLog.info("disconnect uid=%").c(Binder.getCallingUid()).flush();
1665         mClientModeImpl.disconnectCommand();
1666         return true;
1667     }
1668 
1669     /**
1670      * see {@link android.net.wifi.WifiManager#reconnect()}
1671      */
1672     @Override
reconnect(String packageName)1673     public boolean reconnect(String packageName) {
1674         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
1675             return false;
1676         }
1677         if (!isTargetSdkLessThanQOrPrivileged(
1678                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
1679             mLog.info("reconnect not allowed for uid=%")
1680                     .c(Binder.getCallingUid()).flush();
1681             return false;
1682         }
1683         mLog.info("reconnect uid=%").c(Binder.getCallingUid()).flush();
1684         mClientModeImpl.reconnectCommand(new WorkSource(Binder.getCallingUid()));
1685         return true;
1686     }
1687 
1688     /**
1689      * see {@link android.net.wifi.WifiManager#reassociate()}
1690      */
1691     @Override
reassociate(String packageName)1692     public boolean reassociate(String packageName) {
1693         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
1694             return false;
1695         }
1696         if (!isTargetSdkLessThanQOrPrivileged(
1697                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
1698             mLog.info("reassociate not allowed for uid=%")
1699                     .c(Binder.getCallingUid()).flush();
1700             return false;
1701         }
1702         mLog.info("reassociate uid=%").c(Binder.getCallingUid()).flush();
1703         mClientModeImpl.reassociateCommand();
1704         return true;
1705     }
1706 
1707     /**
1708      * see {@link android.net.wifi.WifiManager#getSupportedFeatures}
1709      */
1710     @Override
getSupportedFeatures()1711     public long getSupportedFeatures() {
1712         enforceAccessPermission();
1713         if (mVerboseLoggingEnabled) {
1714             mLog.info("getSupportedFeatures uid=%").c(Binder.getCallingUid()).flush();
1715         }
1716         return getSupportedFeaturesInternal();
1717     }
1718 
1719     @Override
requestActivityInfo(ResultReceiver result)1720     public void requestActivityInfo(ResultReceiver result) {
1721         Bundle bundle = new Bundle();
1722         if (mVerboseLoggingEnabled) {
1723             mLog.info("requestActivityInfo uid=%").c(Binder.getCallingUid()).flush();
1724         }
1725         bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, reportActivityInfo());
1726         result.send(0, bundle);
1727     }
1728 
1729     /**
1730      * see {@link android.net.wifi.WifiManager#getControllerActivityEnergyInfo(int)}
1731      */
1732     @Override
reportActivityInfo()1733     public WifiActivityEnergyInfo reportActivityInfo() {
1734         enforceAccessPermission();
1735         if (mVerboseLoggingEnabled) {
1736             mLog.info("reportActivityInfo uid=%").c(Binder.getCallingUid()).flush();
1737         }
1738         if ((getSupportedFeatures() & WifiManager.WIFI_FEATURE_LINK_LAYER_STATS) == 0) {
1739             return null;
1740         }
1741         WifiLinkLayerStats stats;
1742         WifiActivityEnergyInfo energyInfo = null;
1743         if (mClientModeImplChannel != null) {
1744             stats = mClientModeImpl.syncGetLinkLayerStats(mClientModeImplChannel);
1745             if (stats != null) {
1746                 final double rxIdleCurrent = mPowerProfile.getAveragePower(
1747                     PowerProfile.POWER_WIFI_CONTROLLER_IDLE);
1748                 final double rxCurrent = mPowerProfile.getAveragePower(
1749                     PowerProfile.POWER_WIFI_CONTROLLER_RX);
1750                 final double txCurrent = mPowerProfile.getAveragePower(
1751                     PowerProfile.POWER_WIFI_CONTROLLER_TX);
1752                 final double voltage = mPowerProfile.getAveragePower(
1753                     PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
1754                 final long rxIdleTime = stats.on_time - stats.tx_time - stats.rx_time;
1755                 final long[] txTimePerLevel;
1756                 if (stats.tx_time_per_level != null) {
1757                     txTimePerLevel = new long[stats.tx_time_per_level.length];
1758                     for (int i = 0; i < txTimePerLevel.length; i++) {
1759                         txTimePerLevel[i] = stats.tx_time_per_level[i];
1760                         // TODO(b/27227497): Need to read the power consumed per level from config
1761                     }
1762                 } else {
1763                     // This will happen if the HAL get link layer API returned null.
1764                     txTimePerLevel = new long[0];
1765                 }
1766                 final long energyUsed = (long)((stats.tx_time * txCurrent +
1767                         stats.rx_time * rxCurrent +
1768                         rxIdleTime * rxIdleCurrent) * voltage);
1769                 if (VDBG || rxIdleTime < 0 || stats.on_time < 0 || stats.tx_time < 0 ||
1770                         stats.rx_time < 0 || stats.on_time_scan < 0 || energyUsed < 0) {
1771                     StringBuilder sb = new StringBuilder();
1772                     sb.append(" rxIdleCur=" + rxIdleCurrent);
1773                     sb.append(" rxCur=" + rxCurrent);
1774                     sb.append(" txCur=" + txCurrent);
1775                     sb.append(" voltage=" + voltage);
1776                     sb.append(" on_time=" + stats.on_time);
1777                     sb.append(" tx_time=" + stats.tx_time);
1778                     sb.append(" tx_time_per_level=" + Arrays.toString(txTimePerLevel));
1779                     sb.append(" rx_time=" + stats.rx_time);
1780                     sb.append(" rxIdleTime=" + rxIdleTime);
1781                     sb.append(" scan_time=" + stats.on_time_scan);
1782                     sb.append(" energy=" + energyUsed);
1783                     Log.d(TAG, " reportActivityInfo: " + sb.toString());
1784                 }
1785 
1786                 // Convert the LinkLayerStats into EnergyActivity
1787                 energyInfo = new WifiActivityEnergyInfo(mClock.getElapsedSinceBootMillis(),
1788                         WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE, stats.tx_time,
1789                         txTimePerLevel, stats.rx_time, stats.on_time_scan, rxIdleTime, energyUsed);
1790             }
1791             if (energyInfo != null && energyInfo.isValid()) {
1792                 return energyInfo;
1793             } else {
1794                 return null;
1795             }
1796         } else {
1797             Slog.e(TAG, "mClientModeImplChannel is not initialized");
1798             return null;
1799         }
1800     }
1801 
1802     /**
1803      * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
1804      *
1805      * @param packageName String name of the calling package
1806      * @return the list of configured networks
1807      */
1808     @Override
getConfiguredNetworks(String packageName)1809     public ParceledListSlice<WifiConfiguration> getConfiguredNetworks(String packageName) {
1810         enforceAccessPermission();
1811         int callingUid = Binder.getCallingUid();
1812         // bypass shell: can get varioud pkg name
1813         if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
1814             long ident = Binder.clearCallingIdentity();
1815             try {
1816                 mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, callingUid);
1817             } catch (SecurityException e) {
1818                 Slog.e(TAG, "Permission violation - getConfiguredNetworks not allowed for uid="
1819                         + callingUid + ", packageName=" + packageName + ", reason=" + e);
1820                 return new ParceledListSlice<>(new ArrayList<>());
1821             } finally {
1822                 Binder.restoreCallingIdentity(ident);
1823             }
1824         }
1825         boolean isTargetSdkLessThanQOrPrivileged = isTargetSdkLessThanQOrPrivileged(
1826                 packageName, Binder.getCallingPid(), callingUid);
1827         boolean isCarrierApp = mWifiInjector.makeTelephonyManager()
1828                 .checkCarrierPrivilegesForPackageAnyPhone(packageName)
1829                 == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
1830         if (!isTargetSdkLessThanQOrPrivileged && !isCarrierApp) {
1831             mLog.info("getConfiguredNetworks not allowed for uid=%")
1832                     .c(callingUid).flush();
1833             return new ParceledListSlice<>(new ArrayList<>());
1834         }
1835         if (mVerboseLoggingEnabled) {
1836             mLog.info("getConfiguredNetworks uid=%").c(callingUid).flush();
1837         }
1838 
1839         int targetConfigUid = Process.INVALID_UID; // don't expose any MAC addresses
1840         if (isPrivileged(getCallingPid(), callingUid) || isDeviceOrProfileOwner(callingUid)) {
1841             targetConfigUid = Process.WIFI_UID; // expose all MAC addresses
1842         } else if (isCarrierApp) {
1843             targetConfigUid = callingUid; // expose only those configs created by the Carrier App
1844         }
1845 
1846         if (mClientModeImplChannel != null) {
1847             List<WifiConfiguration> configs = mClientModeImpl.syncGetConfiguredNetworks(
1848                     callingUid, mClientModeImplChannel, targetConfigUid);
1849             if (configs != null) {
1850                 if (isTargetSdkLessThanQOrPrivileged) {
1851                     return new ParceledListSlice<WifiConfiguration>(configs);
1852                 } else { // Carrier app: should only get its own configs
1853                     List<WifiConfiguration> creatorConfigs = new ArrayList<>();
1854                     for (WifiConfiguration config : configs) {
1855                         if (config.creatorUid == callingUid) {
1856                             creatorConfigs.add(config);
1857                         }
1858                     }
1859                     return new ParceledListSlice<WifiConfiguration>(creatorConfigs);
1860                 }
1861             }
1862         } else {
1863             Slog.e(TAG, "mClientModeImplChannel is not initialized");
1864         }
1865         return null;
1866     }
1867 
1868     /**
1869      * see {@link android.net.wifi.WifiManager#getPrivilegedConfiguredNetworks()}
1870      *
1871      * @param packageName String name of the calling package
1872      * @return the list of configured networks with real preSharedKey
1873      */
1874     @Override
1875     public ParceledListSlice<WifiConfiguration>
getPrivilegedConfiguredNetworks(String packageName)1876             getPrivilegedConfiguredNetworks(String packageName) {
1877         enforceReadCredentialPermission();
1878         enforceAccessPermission();
1879         int callingUid = Binder.getCallingUid();
1880         long ident = Binder.clearCallingIdentity();
1881         try {
1882             mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, callingUid);
1883         } catch (SecurityException e) {
1884             Slog.e(TAG, "Permission violation - getPrivilegedConfiguredNetworks not allowed for"
1885                     + " uid=" + callingUid + ", packageName=" + packageName + ", reason=" + e);
1886             return null;
1887         } finally {
1888             Binder.restoreCallingIdentity(ident);
1889         }
1890         if (mVerboseLoggingEnabled) {
1891             mLog.info("getPrivilegedConfiguredNetworks uid=%").c(callingUid).flush();
1892         }
1893         if (mClientModeImplChannel != null) {
1894             List<WifiConfiguration> configs =
1895                     mClientModeImpl.syncGetPrivilegedConfiguredNetwork(mClientModeImplChannel);
1896             if (configs != null) {
1897                 return new ParceledListSlice<WifiConfiguration>(configs);
1898             }
1899         } else {
1900             Slog.e(TAG, "mClientModeImplChannel is not initialized");
1901         }
1902         return null;
1903     }
1904 
1905     /**
1906      * Returns the list of FQDN (Fully Qualified Domain Name) to installed Passpoint configurations.
1907      *
1908      * Return the map of all matching configurations with corresponding scanResults (or an empty map
1909      * if none).
1910      *
1911      * @param scanResults The list of scan results
1912      * @return Map that consists of FQDN (Fully Qualified Domain Name) and corresponding
1913      * scanResults per network type({@link WifiManager#PASSPOINT_HOME_NETWORK} and {@link
1914      * WifiManager#PASSPOINT_ROAMING_NETWORK}).
1915      */
1916     @Override
getAllMatchingFqdnsForScanResults( List<ScanResult> scanResults)1917     public Map<String, Map<Integer, List<ScanResult>>> getAllMatchingFqdnsForScanResults(
1918             List<ScanResult> scanResults) {
1919         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
1920             throw new SecurityException(TAG + ": Permission denied");
1921         }
1922         if (mVerboseLoggingEnabled) {
1923             mLog.info("getMatchingPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush();
1924         }
1925         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT)) {
1926             return new HashMap<>();
1927         }
1928         return mClientModeImpl.syncGetAllMatchingFqdnsForScanResults(scanResults,
1929                 mClientModeImplChannel);
1930     }
1931 
1932     /**
1933      * Returns list of OSU (Online Sign-Up) providers associated with the given list of ScanResult.
1934      *
1935      * @param scanResults a list of ScanResult that has Passpoint APs.
1936      * @return Map that consists of {@link OsuProvider} and a matching list of {@link ScanResult}.
1937      */
1938     @Override
getMatchingOsuProviders( List<ScanResult> scanResults)1939     public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
1940             List<ScanResult> scanResults) {
1941         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
1942             throw new SecurityException(TAG + ": Permission denied");
1943         }
1944         if (mVerboseLoggingEnabled) {
1945             mLog.info("getMatchingOsuProviders uid=%").c(Binder.getCallingUid()).flush();
1946         }
1947         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT)) {
1948             return new HashMap<>();
1949         }
1950         return mClientModeImpl.syncGetMatchingOsuProviders(scanResults, mClientModeImplChannel);
1951     }
1952 
1953     /**
1954      * Returns the matching Passpoint configurations for given OSU(Online Sign-Up) providers.
1955      *
1956      * @param osuProviders a list of {@link OsuProvider}
1957      * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}.
1958      */
1959     @Override
getMatchingPasspointConfigsForOsuProviders( List<OsuProvider> osuProviders)1960     public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
1961             List<OsuProvider> osuProviders) {
1962         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
1963             throw new SecurityException(TAG + ": Permission denied");
1964         }
1965         if (mVerboseLoggingEnabled) {
1966             mLog.info("getMatchingPasspointConfigsForOsuProviders uid=%").c(
1967                     Binder.getCallingUid()).flush();
1968         }
1969         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT)) {
1970             return new HashMap<>();
1971         }
1972         if (osuProviders == null) {
1973             Log.e(TAG, "Attempt to retrieve Passpoint configuration with null osuProviders");
1974             return new HashMap<>();
1975         }
1976         return mClientModeImpl.syncGetMatchingPasspointConfigsForOsuProviders(osuProviders,
1977                 mClientModeImplChannel);
1978     }
1979 
1980     /**
1981      * Returns the corresponding wifi configurations for given FQDN (Fully Qualified Domain Name)
1982      * list.
1983      *
1984      * An empty list will be returned when no match is found.
1985      *
1986      * @param fqdnList a list of FQDN
1987      * @return List of {@link WifiConfiguration} converted from {@link PasspointProvider}
1988      */
1989     @Override
getWifiConfigsForPasspointProfiles(List<String> fqdnList)1990     public List<WifiConfiguration> getWifiConfigsForPasspointProfiles(List<String> fqdnList) {
1991         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
1992             throw new SecurityException(TAG + ": Permission denied");
1993         }
1994         if (mVerboseLoggingEnabled) {
1995             mLog.info("getWifiConfigsForPasspointProfiles uid=%").c(
1996                     Binder.getCallingUid()).flush();
1997         }
1998         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT)) {
1999             return new ArrayList<>();
2000         }
2001         if (fqdnList == null) {
2002             Log.e(TAG, "Attempt to retrieve WifiConfiguration with null fqdn List");
2003             return new ArrayList<>();
2004         }
2005         return mClientModeImpl.syncGetWifiConfigsForPasspointProfiles(fqdnList,
2006                 mClientModeImplChannel);
2007     }
2008 
2009     /**
2010      * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
2011      * @return the supplicant-assigned identifier for the new or updated
2012      * network if the operation succeeds, or {@code -1} if it fails
2013      */
2014     @Override
addOrUpdateNetwork(WifiConfiguration config, String packageName)2015     public int addOrUpdateNetwork(WifiConfiguration config, String packageName) {
2016         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2017             return -1;
2018         }
2019         if (!isTargetSdkLessThanQOrPrivileged(
2020                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
2021             mLog.info("addOrUpdateNetwork not allowed for uid=%")
2022                     .c(Binder.getCallingUid()).flush();
2023             return -1;
2024         }
2025         mLog.info("addOrUpdateNetwork uid=%").c(Binder.getCallingUid()).flush();
2026 
2027         if (config == null) {
2028             Slog.e(TAG, "bad network configuration");
2029             return -1;
2030         }
2031         mWifiMetrics.incrementNumAddOrUpdateNetworkCalls();
2032 
2033         // Previously, this API is overloaded for installing Passpoint profiles.  Now
2034         // that we have a dedicated API for doing it, redirect the call to the dedicated API.
2035         if (config.isPasspoint()) {
2036             PasspointConfiguration passpointConfig =
2037                     PasspointProvider.convertFromWifiConfig(config);
2038             if (passpointConfig.getCredential() == null) {
2039                 Slog.e(TAG, "Missing credential for Passpoint profile");
2040                 return -1;
2041             }
2042 
2043             // Copy over certificates and keys.
2044             X509Certificate[] x509Certificates = null;
2045             if (config.enterpriseConfig.getCaCertificate() != null) {
2046                 x509Certificates =
2047                         new X509Certificate[]{config.enterpriseConfig.getCaCertificate()};
2048             }
2049             passpointConfig.getCredential().setCaCertificates(x509Certificates);
2050             passpointConfig.getCredential().setClientCertificateChain(
2051                     config.enterpriseConfig.getClientCertificateChain());
2052             passpointConfig.getCredential().setClientPrivateKey(
2053                     config.enterpriseConfig.getClientPrivateKey());
2054             if (!addOrUpdatePasspointConfiguration(passpointConfig, packageName)) {
2055                 Slog.e(TAG, "Failed to add Passpoint profile");
2056                 return -1;
2057             }
2058             // There is no network ID associated with a Passpoint profile.
2059             return 0;
2060         }
2061 
2062         //TODO: pass the Uid the ClientModeImpl as a message parameter
2063         Slog.i("addOrUpdateNetwork", " uid = " + Integer.toString(Binder.getCallingUid())
2064                 + " SSID " + config.SSID
2065                 + " nid=" + Integer.toString(config.networkId));
2066         if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
2067             config.creatorUid = Binder.getCallingUid();
2068         } else {
2069             config.lastUpdateUid = Binder.getCallingUid();
2070         }
2071         if (mClientModeImplChannel != null) {
2072             return mClientModeImpl.syncAddOrUpdateNetwork(mClientModeImplChannel, config);
2073         } else {
2074             Slog.e(TAG, "mClientModeImplChannel is not initialized");
2075             return -1;
2076         }
2077     }
2078 
verifyCert(X509Certificate caCert)2079     public static void verifyCert(X509Certificate caCert)
2080             throws GeneralSecurityException, IOException {
2081         CertificateFactory factory = CertificateFactory.getInstance("X.509");
2082         CertPathValidator validator =
2083                 CertPathValidator.getInstance(CertPathValidator.getDefaultType());
2084         CertPath path = factory.generateCertPath(
2085                 Arrays.asList(caCert));
2086         KeyStore ks = KeyStore.getInstance("AndroidCAStore");
2087         ks.load(null, null);
2088         PKIXParameters params = new PKIXParameters(ks);
2089         params.setRevocationEnabled(false);
2090         validator.validate(path, params);
2091     }
2092 
2093     /**
2094      * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
2095      * @param netId the integer that identifies the network configuration
2096      * to the supplicant
2097      * @return {@code true} if the operation succeeded
2098      */
2099     @Override
removeNetwork(int netId, String packageName)2100     public boolean removeNetwork(int netId, String packageName) {
2101         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2102             return false;
2103         }
2104         if (!isTargetSdkLessThanQOrPrivileged(
2105                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
2106             mLog.info("removeNetwork not allowed for uid=%")
2107                     .c(Binder.getCallingUid()).flush();
2108             return false;
2109         }
2110         mLog.info("removeNetwork uid=%").c(Binder.getCallingUid()).flush();
2111         // TODO Add private logging for netId b/33807876
2112         if (mClientModeImplChannel != null) {
2113             return mClientModeImpl.syncRemoveNetwork(mClientModeImplChannel, netId);
2114         } else {
2115             Slog.e(TAG, "mClientModeImplChannel is not initialized");
2116             return false;
2117         }
2118     }
2119 
2120     /**
2121      * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
2122      * @param netId the integer that identifies the network configuration
2123      * to the supplicant
2124      * @param disableOthers if true, disable all other networks.
2125      * @return {@code true} if the operation succeeded
2126      */
2127     @Override
enableNetwork(int netId, boolean disableOthers, String packageName)2128     public boolean enableNetwork(int netId, boolean disableOthers, String packageName) {
2129         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2130             return false;
2131         }
2132         if (!isTargetSdkLessThanQOrPrivileged(
2133                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
2134             mLog.info("enableNetwork not allowed for uid=%")
2135                     .c(Binder.getCallingUid()).flush();
2136             return false;
2137         }
2138         // TODO b/33807876 Log netId
2139         mLog.info("enableNetwork uid=% disableOthers=%")
2140                 .c(Binder.getCallingUid())
2141                 .c(disableOthers).flush();
2142 
2143         mWifiMetrics.incrementNumEnableNetworkCalls();
2144         if (mClientModeImplChannel != null) {
2145             return mClientModeImpl.syncEnableNetwork(mClientModeImplChannel, netId,
2146                     disableOthers);
2147         } else {
2148             Slog.e(TAG, "mClientModeImplChannel is not initialized");
2149             return false;
2150         }
2151     }
2152 
2153     /**
2154      * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
2155      * @param netId the integer that identifies the network configuration
2156      * to the supplicant
2157      * @return {@code true} if the operation succeeded
2158      */
2159     @Override
disableNetwork(int netId, String packageName)2160     public boolean disableNetwork(int netId, String packageName) {
2161         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2162             return false;
2163         }
2164         if (!isTargetSdkLessThanQOrPrivileged(
2165                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
2166             mLog.info("disableNetwork not allowed for uid=%")
2167                     .c(Binder.getCallingUid()).flush();
2168             return false;
2169         }
2170         // TODO b/33807876 Log netId
2171         mLog.info("disableNetwork uid=%").c(Binder.getCallingUid()).flush();
2172 
2173         if (mClientModeImplChannel != null) {
2174             return mClientModeImpl.syncDisableNetwork(mClientModeImplChannel, netId);
2175         } else {
2176             Slog.e(TAG, "mClientModeImplChannel is not initialized");
2177             return false;
2178         }
2179     }
2180 
2181     /**
2182      * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
2183      * @return the Wi-Fi information, contained in {@link WifiInfo}.
2184      */
2185     @Override
getConnectionInfo(String callingPackage)2186     public WifiInfo getConnectionInfo(String callingPackage) {
2187         enforceAccessPermission();
2188         int uid = Binder.getCallingUid();
2189         if (mVerboseLoggingEnabled) {
2190             mLog.info("getConnectionInfo uid=%").c(uid).flush();
2191         }
2192         long ident = Binder.clearCallingIdentity();
2193         try {
2194             WifiInfo result = mClientModeImpl.syncRequestConnectionInfo();
2195             boolean hideDefaultMacAddress = true;
2196             boolean hideBssidSsidAndNetworkId = true;
2197 
2198             try {
2199                 if (mWifiInjector.getWifiPermissionsWrapper().getLocalMacAddressPermission(uid)
2200                         == PERMISSION_GRANTED) {
2201                     hideDefaultMacAddress = false;
2202                 }
2203                 mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, uid);
2204                 hideBssidSsidAndNetworkId = false;
2205             } catch (RemoteException e) {
2206                 Log.e(TAG, "Error checking receiver permission", e);
2207             } catch (SecurityException e) {
2208             }
2209             if (hideDefaultMacAddress) {
2210                 result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
2211             }
2212             if (hideBssidSsidAndNetworkId) {
2213                 result.setBSSID(WifiInfo.DEFAULT_MAC_ADDRESS);
2214                 result.setSSID(WifiSsid.createFromHex(null));
2215                 result.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
2216             }
2217             if (mVerboseLoggingEnabled && (hideBssidSsidAndNetworkId || hideDefaultMacAddress)) {
2218                 mLog.v("getConnectionInfo: hideBssidSsidAndNetworkId="
2219                         + hideBssidSsidAndNetworkId
2220                         + ", hideDefaultMacAddress="
2221                         + hideDefaultMacAddress);
2222             }
2223             return result;
2224         } finally {
2225             Binder.restoreCallingIdentity(ident);
2226         }
2227     }
2228 
2229     /**
2230      * Return the results of the most recent access point scan, in the form of
2231      * a list of {@link ScanResult} objects.
2232      * @return the list of results
2233      */
2234     @Override
getScanResults(String callingPackage)2235     public List<ScanResult> getScanResults(String callingPackage) {
2236         enforceAccessPermission();
2237         int uid = Binder.getCallingUid();
2238         long ident = Binder.clearCallingIdentity();
2239         if (mVerboseLoggingEnabled) {
2240             mLog.info("getScanResults uid=%").c(uid).flush();
2241         }
2242         try {
2243             mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, uid);
2244             final List<ScanResult> scanResults = new ArrayList<>();
2245             boolean success = mWifiInjector.getClientModeImplHandler().runWithScissors(() -> {
2246                 scanResults.addAll(mScanRequestProxy.getScanResults());
2247             }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
2248             if (!success) {
2249                 Log.e(TAG, "Failed to post runnable to fetch scan results");
2250                 return new ArrayList<ScanResult>();
2251             }
2252             return scanResults;
2253         } catch (SecurityException e) {
2254             Slog.e(TAG, "Permission violation - getScanResults not allowed for uid="
2255                     + uid + ", packageName=" + callingPackage + ", reason=" + e);
2256             return new ArrayList<ScanResult>();
2257         } finally {
2258             Binder.restoreCallingIdentity(ident);
2259         }
2260     }
2261 
2262     /**
2263      * Add or update a Passpoint configuration.
2264      *
2265      * @param config The Passpoint configuration to be added
2266      * @return true on success or false on failure
2267      */
2268     @Override
addOrUpdatePasspointConfiguration( PasspointConfiguration config, String packageName)2269     public boolean addOrUpdatePasspointConfiguration(
2270             PasspointConfiguration config, String packageName) {
2271         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2272             return false;
2273         }
2274         mLog.info("addorUpdatePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush();
2275         if (!mContext.getPackageManager().hasSystemFeature(
2276                 PackageManager.FEATURE_WIFI_PASSPOINT)) {
2277             return false;
2278         }
2279         return mClientModeImpl.syncAddOrUpdatePasspointConfig(mClientModeImplChannel, config,
2280                 Binder.getCallingUid(), packageName);
2281     }
2282 
2283     /**
2284      * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
2285      *
2286      * @param fqdn The FQDN of the Passpoint configuration to be removed
2287      * @return true on success or false on failure
2288      */
2289     @Override
removePasspointConfiguration(String fqdn, String packageName)2290     public boolean removePasspointConfiguration(String fqdn, String packageName) {
2291         final int uid = Binder.getCallingUid();
2292         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
2293                 && !mWifiPermissionsUtil.checkNetworkCarrierProvisioningPermission(uid)) {
2294             if (mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q)) {
2295                 return false;
2296             }
2297             throw new SecurityException(TAG + ": Permission denied");
2298         }
2299         mLog.info("removePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush();
2300         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT)) {
2301             return false;
2302         }
2303         return mClientModeImpl.syncRemovePasspointConfig(mClientModeImplChannel, fqdn);
2304     }
2305 
2306     /**
2307      * Return the list of the installed Passpoint configurations.
2308      *
2309      * An empty list will be returned when no configuration is installed.
2310      * @param packageName String name of the calling package
2311      * @return A list of {@link PasspointConfiguration}.
2312      */
2313     @Override
getPasspointConfigurations(String packageName)2314     public List<PasspointConfiguration> getPasspointConfigurations(String packageName) {
2315         final int uid = Binder.getCallingUid();
2316         mAppOps.checkPackage(uid, packageName);
2317         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
2318                 && !mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)) {
2319             if (mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q)) {
2320                 return new ArrayList<>();
2321             }
2322             throw new SecurityException(TAG + ": Permission denied");
2323         }
2324         if (mVerboseLoggingEnabled) {
2325             mLog.info("getPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush();
2326         }
2327         if (!mContext.getPackageManager().hasSystemFeature(
2328                 PackageManager.FEATURE_WIFI_PASSPOINT)) {
2329             return new ArrayList<>();
2330         }
2331         return mClientModeImpl.syncGetPasspointConfigs(mClientModeImplChannel);
2332     }
2333 
2334     /**
2335      * Query for a Hotspot 2.0 release 2 OSU icon
2336      * @param bssid The BSSID of the AP
2337      * @param fileName Icon file name
2338      */
2339     @Override
queryPasspointIcon(long bssid, String fileName)2340     public void queryPasspointIcon(long bssid, String fileName) {
2341         enforceAccessPermission();
2342         mLog.info("queryPasspointIcon uid=%").c(Binder.getCallingUid()).flush();
2343         if (!mContext.getPackageManager().hasSystemFeature(
2344                 PackageManager.FEATURE_WIFI_PASSPOINT)) {
2345             throw new UnsupportedOperationException("Passpoint not enabled");
2346         }
2347         mClientModeImpl.syncQueryPasspointIcon(mClientModeImplChannel, bssid, fileName);
2348     }
2349 
2350     /**
2351      * Match the currently associated network against the SP matching the given FQDN
2352      * @param fqdn FQDN of the SP
2353      * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
2354      */
2355     @Override
matchProviderWithCurrentNetwork(String fqdn)2356     public int matchProviderWithCurrentNetwork(String fqdn) {
2357         mLog.info("matchProviderWithCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
2358         return mClientModeImpl.matchProviderWithCurrentNetwork(mClientModeImplChannel, fqdn);
2359     }
2360 
2361     /**
2362      * Deauthenticate and set the re-authentication hold off time for the current network
2363      * @param holdoff hold off time in milliseconds
2364      * @param ess set if the hold off pertains to an ESS rather than a BSS
2365      */
2366     @Override
deauthenticateNetwork(long holdoff, boolean ess)2367     public void deauthenticateNetwork(long holdoff, boolean ess) {
2368         mLog.info("deauthenticateNetwork uid=%").c(Binder.getCallingUid()).flush();
2369         mClientModeImpl.deauthenticateNetwork(mClientModeImplChannel, holdoff, ess);
2370     }
2371 
2372     /**
2373      * Set the country code
2374      * @param countryCode ISO 3166 country code.
2375      *
2376      */
2377     @Override
setCountryCode(String countryCode)2378     public void setCountryCode(String countryCode) {
2379         Slog.i(TAG, "WifiService trying to set country code to " + countryCode);
2380         enforceConnectivityInternalPermission();
2381         mLog.info("setCountryCode uid=%").c(Binder.getCallingUid()).flush();
2382         final long token = Binder.clearCallingIdentity();
2383         mCountryCode.setCountryCode(countryCode);
2384         Binder.restoreCallingIdentity(token);
2385     }
2386 
2387      /**
2388      * Get the country code
2389      * @return Get the best choice country code for wifi, regardless of if it was set or
2390      * not.
2391      * Returns null when there is no country code available.
2392      */
2393     @Override
getCountryCode()2394     public String getCountryCode() {
2395         enforceConnectivityInternalPermission();
2396         if (mVerboseLoggingEnabled) {
2397             mLog.info("getCountryCode uid=%").c(Binder.getCallingUid()).flush();
2398         }
2399         String country = mCountryCode.getCountryCode();
2400         return country;
2401     }
2402 
2403     @Override
isDualBandSupported()2404     public boolean isDualBandSupported() {
2405         //TODO (b/123227116): pull it from the HAL
2406         if (mVerboseLoggingEnabled) {
2407             mLog.info("isDualBandSupported uid=%").c(Binder.getCallingUid()).flush();
2408         }
2409 
2410         return mContext.getResources().getBoolean(
2411                 com.android.internal.R.bool.config_wifi_dual_band_support);
2412     }
2413 
getMaxApInterfacesCount()2414     private int getMaxApInterfacesCount() {
2415         //TODO (b/123227116): pull it from the HAL
2416         return mContext.getResources().getInteger(
2417                 com.android.internal.R.integer.config_wifi_max_ap_interfaces);
2418     }
2419 
isConcurrentLohsAndTetheringSupported()2420     private boolean isConcurrentLohsAndTetheringSupported() {
2421         // TODO(b/110697252): handle all configurations in the wifi stack (just by changing the HAL)
2422         return getMaxApInterfacesCount() >= 2;
2423     }
2424 
2425     /**
2426      * Method allowing callers with NETWORK_SETTINGS permission to check if this is a dual mode
2427      * capable device (STA+AP).
2428      *
2429      * @return true if a dual mode capable device
2430      */
2431     @Override
needs5GHzToAnyApBandConversion()2432     public boolean needs5GHzToAnyApBandConversion() {
2433         enforceNetworkSettingsPermission();
2434 
2435         if (mVerboseLoggingEnabled) {
2436             mLog.info("needs5GHzToAnyApBandConversion uid=%").c(Binder.getCallingUid()).flush();
2437         }
2438         return mContext.getResources().getBoolean(
2439                 com.android.internal.R.bool.config_wifi_convert_apband_5ghz_to_any);
2440     }
2441 
2442     /**
2443      * Return the DHCP-assigned addresses from the last successful DHCP request,
2444      * if any.
2445      * @return the DHCP information
2446      * @deprecated
2447      */
2448     @Override
2449     @Deprecated
getDhcpInfo()2450     public DhcpInfo getDhcpInfo() {
2451         enforceAccessPermission();
2452         if (mVerboseLoggingEnabled) {
2453             mLog.info("getDhcpInfo uid=%").c(Binder.getCallingUid()).flush();
2454         }
2455         DhcpResults dhcpResults = mClientModeImpl.syncGetDhcpResults();
2456 
2457         DhcpInfo info = new DhcpInfo();
2458 
2459         if (dhcpResults.ipAddress != null &&
2460                 dhcpResults.ipAddress.getAddress() instanceof Inet4Address) {
2461             info.ipAddress = NetworkUtils.inetAddressToInt(
2462                     (Inet4Address) dhcpResults.ipAddress.getAddress());
2463         }
2464 
2465         if (dhcpResults.gateway != null) {
2466             info.gateway = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.gateway);
2467         }
2468 
2469         int dnsFound = 0;
2470         for (InetAddress dns : dhcpResults.dnsServers) {
2471             if (dns instanceof Inet4Address) {
2472                 if (dnsFound == 0) {
2473                     info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
2474                 } else {
2475                     info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
2476                 }
2477                 if (++dnsFound > 1) break;
2478             }
2479         }
2480         Inet4Address serverAddress = dhcpResults.serverAddress;
2481         if (serverAddress != null) {
2482             info.serverAddress = NetworkUtils.inetAddressToInt(serverAddress);
2483         }
2484         info.leaseDuration = dhcpResults.leaseDuration;
2485 
2486         return info;
2487     }
2488 
2489     /**
2490      * enable TDLS for the local NIC to remote NIC
2491      * The APPs don't know the remote MAC address to identify NIC though,
2492      * so we need to do additional work to find it from remote IP address
2493      */
2494 
2495     class TdlsTaskParams {
2496         public String remoteIpAddress;
2497         public boolean enable;
2498     }
2499 
2500     class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> {
2501         @Override
doInBackground(TdlsTaskParams... params)2502         protected Integer doInBackground(TdlsTaskParams... params) {
2503 
2504             // Retrieve parameters for the call
2505             TdlsTaskParams param = params[0];
2506             String remoteIpAddress = param.remoteIpAddress.trim();
2507             boolean enable = param.enable;
2508 
2509             // Get MAC address of Remote IP
2510             String macAddress = null;
2511 
2512             BufferedReader reader = null;
2513 
2514             try {
2515                 reader = new BufferedReader(new FileReader("/proc/net/arp"));
2516 
2517                 // Skip over the line bearing colum titles
2518                 String line = reader.readLine();
2519 
2520                 while ((line = reader.readLine()) != null) {
2521                     String[] tokens = line.split("[ ]+");
2522                     if (tokens.length < 6) {
2523                         continue;
2524                     }
2525 
2526                     // ARP column format is
2527                     // Address HWType HWAddress Flags Mask IFace
2528                     String ip = tokens[0];
2529                     String mac = tokens[3];
2530 
2531                     if (remoteIpAddress.equals(ip)) {
2532                         macAddress = mac;
2533                         break;
2534                     }
2535                 }
2536 
2537                 if (macAddress == null) {
2538                     Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " +
2539                             "/proc/net/arp");
2540                 } else {
2541                     enableTdlsWithMacAddress(macAddress, enable);
2542                 }
2543 
2544             } catch (FileNotFoundException e) {
2545                 Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address");
2546             } catch (IOException e) {
2547                 Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address");
2548             } finally {
2549                 try {
2550                     if (reader != null) {
2551                         reader.close();
2552                     }
2553                 }
2554                 catch (IOException e) {
2555                     // Do nothing
2556                 }
2557             }
2558 
2559             return 0;
2560         }
2561     }
2562 
2563     @Override
enableTdls(String remoteAddress, boolean enable)2564     public void enableTdls(String remoteAddress, boolean enable) {
2565         if (remoteAddress == null) {
2566           throw new IllegalArgumentException("remoteAddress cannot be null");
2567         }
2568         mLog.info("enableTdls uid=% enable=%").c(Binder.getCallingUid()).c(enable).flush();
2569         TdlsTaskParams params = new TdlsTaskParams();
2570         params.remoteIpAddress = remoteAddress;
2571         params.enable = enable;
2572         new TdlsTask().execute(params);
2573     }
2574 
2575 
2576     @Override
enableTdlsWithMacAddress(String remoteMacAddress, boolean enable)2577     public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
2578         mLog.info("enableTdlsWithMacAddress uid=% enable=%")
2579                 .c(Binder.getCallingUid())
2580                 .c(enable)
2581                 .flush();
2582         if (remoteMacAddress == null) {
2583           throw new IllegalArgumentException("remoteMacAddress cannot be null");
2584         }
2585 
2586         mClientModeImpl.enableTdls(remoteMacAddress, enable);
2587     }
2588 
2589     /**
2590      * Get a reference to handler. This is used by a client to establish
2591      * an AsyncChannel communication with WifiService
2592      */
2593     @Override
getWifiServiceMessenger(String packageName)2594     public Messenger getWifiServiceMessenger(String packageName) {
2595         enforceAccessPermission();
2596         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2597             // We don't have a good way of creating a fake Messenger, and returning null would
2598             // immediately break callers.
2599             throw new SecurityException("Could not create wifi service messenger");
2600         }
2601         mLog.info("getWifiServiceMessenger uid=%").c(Binder.getCallingUid()).flush();
2602         return new Messenger(mAsyncChannelExternalClientHandler);
2603     }
2604 
2605     /**
2606      * Disable an ephemeral network, i.e. network that is created thru a WiFi Scorer
2607      */
2608     @Override
disableEphemeralNetwork(String SSID, String packageName)2609     public void disableEphemeralNetwork(String SSID, String packageName) {
2610         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
2611                 "WifiService");
2612         if (!isPrivileged(Binder.getCallingPid(), Binder.getCallingUid())) {
2613             mLog.info("disableEphemeralNetwork not allowed for uid=%")
2614                     .c(Binder.getCallingUid()).flush();
2615             return;
2616         }
2617         mLog.info("disableEphemeralNetwork uid=%").c(Binder.getCallingUid()).flush();
2618         mClientModeImpl.disableEphemeralNetwork(SSID);
2619     }
2620 
2621     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
2622         @Override
2623         public void onReceive(Context context, Intent intent) {
2624             String action = intent.getAction();
2625             if (action.equals(Intent.ACTION_USER_REMOVED)) {
2626                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
2627                 mClientModeImpl.removeUserConfigs(userHandle);
2628             } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
2629                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
2630                         BluetoothAdapter.STATE_DISCONNECTED);
2631                 mClientModeImpl.sendBluetoothAdapterStateChange(state);
2632             } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
2633                 boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false);
2634                 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0);
2635             } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED)) {
2636                 boolean inCall = intent.getBooleanExtra(PhoneConstants.PHONE_IN_EMERGENCY_CALL, false);
2637                 mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, inCall ? 1 : 0, 0);
2638             } else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
2639                 handleIdleModeChanged();
2640             }
2641         }
2642     };
2643 
2644     /**
2645      * Observes settings changes to scan always mode.
2646      */
registerForScanModeChange()2647     private void registerForScanModeChange() {
2648         ContentObserver contentObserver = new ContentObserver(null) {
2649             @Override
2650             public void onChange(boolean selfChange) {
2651                 mSettingsStore.handleWifiScanAlwaysAvailableToggled();
2652                 mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED);
2653             }
2654         };
2655         mFrameworkFacade.registerContentObserver(mContext,
2656                 Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE),
2657                 false, contentObserver);
2658 
2659     }
2660 
registerForBroadcasts()2661     private void registerForBroadcasts() {
2662         IntentFilter intentFilter = new IntentFilter();
2663         intentFilter.addAction(Intent.ACTION_USER_PRESENT);
2664         intentFilter.addAction(Intent.ACTION_USER_REMOVED);
2665         intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
2666         intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
2667         intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
2668 
2669         boolean trackEmergencyCallState = mContext.getResources().getBoolean(
2670                 com.android.internal.R.bool.config_wifi_turn_off_during_emergency_call);
2671         if (trackEmergencyCallState) {
2672             intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED);
2673         }
2674         mContext.registerReceiver(mReceiver, intentFilter);
2675 
2676         intentFilter = new IntentFilter();
2677         intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
2678         intentFilter.addDataScheme("package");
2679         mContext.registerReceiver(new BroadcastReceiver() {
2680             @Override
2681             public void onReceive(Context context, Intent intent) {
2682                 String action = intent.getAction();
2683                 if (action.equals(Intent.ACTION_PACKAGE_FULLY_REMOVED)) {
2684                     int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
2685                     Uri uri = intent.getData();
2686                     if (uid == -1 || uri == null) {
2687                         return;
2688                     }
2689                     String pkgName = uri.getSchemeSpecificPart();
2690                     mClientModeImpl.removeAppConfigs(pkgName, uid);
2691 
2692                     // Call the method in ClientModeImpl thread.
2693                     mWifiInjector.getClientModeImplHandler().post(() -> {
2694                         mScanRequestProxy.clearScanRequestTimestampsForApp(pkgName, uid);
2695 
2696                         // Remove all suggestions from the package.
2697                         mWifiNetworkSuggestionsManager.removeApp(pkgName);
2698                         mClientModeImpl.removeNetworkRequestUserApprovedAccessPointsForApp(pkgName);
2699 
2700                         // Remove all Passpoint profiles from package.
2701                         mWifiInjector.getPasspointManager().removePasspointProviderWithPackage(
2702                                 pkgName);
2703 
2704                     });
2705                 }
2706             }
2707         }, intentFilter);
2708     }
2709 
2710     @Override
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)2711     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
2712             String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
2713         (new WifiShellCommand(mWifiInjector)).exec(this, in, out, err,
2714                 args, callback, resultReceiver);
2715     }
2716 
2717     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)2718     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2719         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2720                 != PERMISSION_GRANTED) {
2721             pw.println("Permission Denial: can't dump WifiService from from pid="
2722                     + Binder.getCallingPid()
2723                     + ", uid=" + Binder.getCallingUid());
2724             return;
2725         }
2726         if (args != null && args.length > 0 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])) {
2727             // WifiMetrics proto bytes were requested. Dump only these.
2728             mClientModeImpl.updateWifiMetrics();
2729             mWifiMetrics.dump(fd, pw, args);
2730         } else if (args != null && args.length > 0 && IpClientUtil.DUMP_ARG.equals(args[0])) {
2731             // IpClient dump was requested. Pass it along and take no further action.
2732             String[] ipClientArgs = new String[args.length - 1];
2733             System.arraycopy(args, 1, ipClientArgs, 0, ipClientArgs.length);
2734             mClientModeImpl.dumpIpClient(fd, pw, ipClientArgs);
2735         } else if (args != null && args.length > 0 && WifiScoreReport.DUMP_ARG.equals(args[0])) {
2736             WifiScoreReport wifiScoreReport = mClientModeImpl.getWifiScoreReport();
2737             if (wifiScoreReport != null) wifiScoreReport.dump(fd, pw, args);
2738         } else if (args != null && args.length > 0 && WifiScoreCard.DUMP_ARG.equals(args[0])) {
2739             mWifiInjector.getClientModeImplHandler().runWithScissors(() -> {
2740                 WifiScoreCard wifiScoreCard = mWifiInjector.getWifiScoreCard();
2741                 if (wifiScoreCard != null) {
2742                     pw.println(wifiScoreCard.getNetworkListBase64(true));
2743                 }
2744             }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
2745         } else {
2746             // Polls link layer stats and RSSI. This allows the stats to show up in
2747             // WifiScoreReport's dump() output when taking a bug report even if the screen is off.
2748             mClientModeImpl.updateLinkLayerStatsRssiAndScoreReport();
2749             pw.println("Wi-Fi is " + mClientModeImpl.syncGetWifiStateByName());
2750             pw.println("Verbose logging is " + (mVerboseLoggingEnabled ? "on" : "off"));
2751             pw.println("Stay-awake conditions: " +
2752                     mFacade.getIntegerSetting(mContext,
2753                             Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
2754             pw.println("mInIdleMode " + mInIdleMode);
2755             pw.println("mScanPending " + mScanPending);
2756             mWifiController.dump(fd, pw, args);
2757             mSettingsStore.dump(fd, pw, args);
2758             mWifiTrafficPoller.dump(fd, pw, args);
2759             pw.println();
2760             pw.println("Locks held:");
2761             mWifiLockManager.dump(pw);
2762             pw.println();
2763             mWifiMulticastLockManager.dump(pw);
2764             pw.println();
2765             mActiveModeWarden.dump(fd, pw, args);
2766             pw.println();
2767             mClientModeImpl.dump(fd, pw, args);
2768             pw.println();
2769             mWifiInjector.getClientModeImplHandler().runWithScissors(() -> {
2770                 WifiScoreCard wifiScoreCard = mWifiInjector.getWifiScoreCard();
2771                 if (wifiScoreCard != null) {
2772                     pw.println("WifiScoreCard:");
2773                     pw.println(wifiScoreCard.getNetworkListBase64(true));
2774                 }
2775             }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
2776             mClientModeImpl.updateWifiMetrics();
2777             mWifiMetrics.dump(fd, pw, args);
2778             pw.println();
2779             mWifiInjector.getClientModeImplHandler().runWithScissors(() -> {
2780                 mWifiNetworkSuggestionsManager.dump(fd, pw, args);
2781                 pw.println();
2782             }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
2783             mWifiBackupRestore.dump(fd, pw, args);
2784             pw.println();
2785             pw.println("ScoringParams: settings put global " + Settings.Global.WIFI_SCORE_PARAMS
2786                        + " " + mWifiInjector.getScoringParams());
2787             pw.println();
2788             WifiScoreReport wifiScoreReport = mClientModeImpl.getWifiScoreReport();
2789             if (wifiScoreReport != null) {
2790                 pw.println("WifiScoreReport:");
2791                 wifiScoreReport.dump(fd, pw, args);
2792             }
2793             pw.println();
2794             SarManager sarManager = mWifiInjector.getSarManager();
2795             if (sarManager != null) {
2796                 sarManager.dump(fd, pw, args);
2797             }
2798             pw.println();
2799         }
2800     }
2801 
2802     @Override
acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws)2803     public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
2804         mLog.info("acquireWifiLock uid=% lockMode=%")
2805                 .c(Binder.getCallingUid())
2806                 .c(lockMode).flush();
2807 
2808         // Check on permission to make this call
2809         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
2810 
2811         // If no UID is provided in worksource, use the calling UID
2812         WorkSource updatedWs = (ws == null || ws.isEmpty())
2813                 ? new WorkSource(Binder.getCallingUid()) : ws;
2814 
2815         Mutable<Boolean> lockSuccess = new Mutable<>();
2816         boolean runWithScissorsSuccess = mWifiInjector.getClientModeImplHandler().runWithScissors(
2817                 () -> {
2818                     lockSuccess.value = mWifiLockManager.acquireWifiLock(
2819                             lockMode, tag, binder, updatedWs);
2820                 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
2821         if (!runWithScissorsSuccess) {
2822             Log.e(TAG, "Failed to post runnable to acquireWifiLock");
2823             return false;
2824         }
2825 
2826         return lockSuccess.value;
2827     }
2828 
2829     @Override
updateWifiLockWorkSource(IBinder binder, WorkSource ws)2830     public void updateWifiLockWorkSource(IBinder binder, WorkSource ws) {
2831         mLog.info("updateWifiLockWorkSource uid=%").c(Binder.getCallingUid()).flush();
2832 
2833         // Check on permission to make this call
2834         mContext.enforceCallingOrSelfPermission(
2835                 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
2836 
2837         // If no UID is provided in worksource, use the calling UID
2838         WorkSource updatedWs = (ws == null || ws.isEmpty())
2839                 ? new WorkSource(Binder.getCallingUid()) : ws;
2840 
2841         boolean runWithScissorsSuccess = mWifiInjector.getClientModeImplHandler().runWithScissors(
2842                 () -> {
2843                     mWifiLockManager.updateWifiLockWorkSource(binder, updatedWs);
2844                 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
2845         if (!runWithScissorsSuccess) {
2846             Log.e(TAG, "Failed to post runnable to updateWifiLockWorkSource");
2847         }
2848     }
2849 
2850     @Override
releaseWifiLock(IBinder binder)2851     public boolean releaseWifiLock(IBinder binder) {
2852         mLog.info("releaseWifiLock uid=%").c(Binder.getCallingUid()).flush();
2853 
2854         // Check on permission to make this call
2855         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
2856         Mutable<Boolean> lockSuccess = new Mutable<>();
2857         boolean runWithScissorsSuccess = mWifiInjector.getClientModeImplHandler().runWithScissors(
2858                 () -> {
2859                     lockSuccess.value = mWifiLockManager.releaseWifiLock(binder);
2860                 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
2861         if (!runWithScissorsSuccess) {
2862             Log.e(TAG, "Failed to post runnable to releaseWifiLock");
2863             return false;
2864         }
2865         return lockSuccess.value;
2866     }
2867 
2868     @Override
initializeMulticastFiltering()2869     public void initializeMulticastFiltering() {
2870         enforceMulticastChangePermission();
2871         mLog.info("initializeMulticastFiltering uid=%").c(Binder.getCallingUid()).flush();
2872         mWifiMulticastLockManager.initializeFiltering();
2873     }
2874 
2875     @Override
acquireMulticastLock(IBinder binder, String tag)2876     public void acquireMulticastLock(IBinder binder, String tag) {
2877         enforceMulticastChangePermission();
2878         mLog.info("acquireMulticastLock uid=%").c(Binder.getCallingUid()).flush();
2879         mWifiMulticastLockManager.acquireLock(binder, tag);
2880     }
2881 
2882     @Override
releaseMulticastLock(String tag)2883     public void releaseMulticastLock(String tag) {
2884         enforceMulticastChangePermission();
2885         mLog.info("releaseMulticastLock uid=%").c(Binder.getCallingUid()).flush();
2886         mWifiMulticastLockManager.releaseLock(tag);
2887     }
2888 
2889     @Override
isMulticastEnabled()2890     public boolean isMulticastEnabled() {
2891         enforceAccessPermission();
2892         if (mVerboseLoggingEnabled) {
2893             mLog.info("isMulticastEnabled uid=%").c(Binder.getCallingUid()).flush();
2894         }
2895         return mWifiMulticastLockManager.isMulticastEnabled();
2896     }
2897 
2898     @Override
enableVerboseLogging(int verbose)2899     public void enableVerboseLogging(int verbose) {
2900         enforceAccessPermission();
2901         enforceNetworkSettingsPermission();
2902         mLog.info("enableVerboseLogging uid=% verbose=%")
2903                 .c(Binder.getCallingUid())
2904                 .c(verbose).flush();
2905         mFacade.setIntegerSetting(
2906                 mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, verbose);
2907         enableVerboseLoggingInternal(verbose);
2908     }
2909 
enableVerboseLoggingInternal(int verbose)2910     void enableVerboseLoggingInternal(int verbose) {
2911         mVerboseLoggingEnabled = verbose > 0;
2912         mClientModeImpl.enableVerboseLogging(verbose);
2913         mWifiLockManager.enableVerboseLogging(verbose);
2914         mWifiMulticastLockManager.enableVerboseLogging(verbose);
2915         mWifiInjector.enableVerboseLogging(verbose);
2916     }
2917 
2918     @Override
getVerboseLoggingLevel()2919     public int getVerboseLoggingLevel() {
2920         if (mVerboseLoggingEnabled) {
2921             mLog.info("getVerboseLoggingLevel uid=%").c(Binder.getCallingUid()).flush();
2922         }
2923         return mFacade.getIntegerSetting(
2924                 mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0);
2925     }
2926 
2927     @Override
factoryReset(String packageName)2928     public void factoryReset(String packageName) {
2929         enforceConnectivityInternalPermission();
2930         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2931             return;
2932         }
2933         mLog.info("factoryReset uid=%").c(Binder.getCallingUid()).flush();
2934         if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
2935             return;
2936         }
2937 
2938         if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
2939             // Turn mobile hotspot off
2940             stopSoftApInternal(WifiManager.IFACE_IP_MODE_UNSPECIFIED);
2941         }
2942 
2943         if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI)) {
2944             if (mClientModeImplChannel != null) {
2945                 // Delete all Wifi SSIDs
2946                 List<WifiConfiguration> networks = mClientModeImpl.syncGetConfiguredNetworks(
2947                         Binder.getCallingUid(), mClientModeImplChannel, Process.WIFI_UID);
2948                 if (networks != null) {
2949                     for (WifiConfiguration config : networks) {
2950                         removeNetwork(config.networkId, packageName);
2951                     }
2952                 }
2953 
2954                 // Delete all Passpoint configurations
2955                 if (mContext.getPackageManager().hasSystemFeature(
2956                         PackageManager.FEATURE_WIFI_PASSPOINT)) {
2957                     List<PasspointConfiguration> configs = mClientModeImpl.syncGetPasspointConfigs(
2958                             mClientModeImplChannel);
2959                     if (configs != null) {
2960                         for (PasspointConfiguration config : configs) {
2961                             removePasspointConfiguration(config.getHomeSp().getFqdn(), packageName);
2962                         }
2963                     }
2964                 }
2965             }
2966 
2967             mWifiInjector.getClientModeImplHandler().post(() -> {
2968                 mWifiInjector.getWifiConfigManager().clearDeletedEphemeralNetworks();
2969                 mClientModeImpl.clearNetworkRequestUserApprovedAccessPoints();
2970                 mWifiNetworkSuggestionsManager.clear();
2971                 mWifiInjector.getWifiScoreCard().clear();
2972             });
2973         }
2974     }
2975 
2976     /* private methods */
logAndReturnFalse(String s)2977     static boolean logAndReturnFalse(String s) {
2978         Log.d(TAG, s);
2979         return false;
2980     }
2981 
2982     @Override
getCurrentNetwork()2983     public Network getCurrentNetwork() {
2984         enforceAccessPermission();
2985         if (mVerboseLoggingEnabled) {
2986             mLog.info("getCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
2987         }
2988         return mClientModeImpl.getCurrentNetwork();
2989     }
2990 
toHexString(String s)2991     public static String toHexString(String s) {
2992         if (s == null) {
2993             return "null";
2994         }
2995         StringBuilder sb = new StringBuilder();
2996         sb.append('\'').append(s).append('\'');
2997         for (int n = 0; n < s.length(); n++) {
2998             sb.append(String.format(" %02x", s.charAt(n) & 0xffff));
2999         }
3000         return sb.toString();
3001     }
3002 
3003     /**
3004      * Enable/disable WifiConnectivityManager at runtime
3005      *
3006      * @param enabled true-enable; false-disable
3007      */
3008     @Override
enableWifiConnectivityManager(boolean enabled)3009     public void enableWifiConnectivityManager(boolean enabled) {
3010         enforceConnectivityInternalPermission();
3011         mLog.info("enableWifiConnectivityManager uid=% enabled=%")
3012                 .c(Binder.getCallingUid())
3013                 .c(enabled).flush();
3014         mClientModeImpl.enableWifiConnectivityManager(enabled);
3015     }
3016 
3017     /**
3018      * Retrieve the data to be backed to save the current state.
3019      *
3020      * @return  Raw byte stream of the data to be backed up.
3021      */
3022     @Override
retrieveBackupData()3023     public byte[] retrieveBackupData() {
3024         enforceNetworkSettingsPermission();
3025         mLog.info("retrieveBackupData uid=%").c(Binder.getCallingUid()).flush();
3026         if (mClientModeImplChannel == null) {
3027             Slog.e(TAG, "mClientModeImplChannel is not initialized");
3028             return null;
3029         }
3030 
3031         Slog.d(TAG, "Retrieving backup data");
3032         List<WifiConfiguration> wifiConfigurations =
3033                 mClientModeImpl.syncGetPrivilegedConfiguredNetwork(mClientModeImplChannel);
3034         byte[] backupData =
3035                 mWifiBackupRestore.retrieveBackupDataFromConfigurations(wifiConfigurations);
3036         Slog.d(TAG, "Retrieved backup data");
3037         return backupData;
3038     }
3039 
3040     /**
3041      * Helper method to restore networks retrieved from backup data.
3042      *
3043      * @param configurations list of WifiConfiguration objects parsed from the backup data.
3044      */
restoreNetworks(List<WifiConfiguration> configurations)3045     private void restoreNetworks(List<WifiConfiguration> configurations) {
3046         if (configurations == null) {
3047             Slog.e(TAG, "Backup data parse failed");
3048             return;
3049         }
3050         for (WifiConfiguration configuration : configurations) {
3051             int networkId = mClientModeImpl.syncAddOrUpdateNetwork(
3052                     mClientModeImplChannel, configuration);
3053             if (networkId == WifiConfiguration.INVALID_NETWORK_ID) {
3054                 Slog.e(TAG, "Restore network failed: " + configuration.configKey());
3055                 continue;
3056             }
3057             // Enable all networks restored.
3058             mClientModeImpl.syncEnableNetwork(mClientModeImplChannel, networkId, false);
3059         }
3060     }
3061 
3062     /**
3063      * Restore state from the backed up data.
3064      *
3065      * @param data Raw byte stream of the backed up data.
3066      */
3067     @Override
restoreBackupData(byte[] data)3068     public void restoreBackupData(byte[] data) {
3069         enforceNetworkSettingsPermission();
3070         mLog.info("restoreBackupData uid=%").c(Binder.getCallingUid()).flush();
3071         if (mClientModeImplChannel == null) {
3072             Slog.e(TAG, "mClientModeImplChannel is not initialized");
3073             return;
3074         }
3075 
3076         Slog.d(TAG, "Restoring backup data");
3077         List<WifiConfiguration> wifiConfigurations =
3078                 mWifiBackupRestore.retrieveConfigurationsFromBackupData(data);
3079         restoreNetworks(wifiConfigurations);
3080         Slog.d(TAG, "Restored backup data");
3081     }
3082 
3083     /**
3084      * Restore state from the older supplicant back up data.
3085      * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file.
3086      *
3087      * @param supplicantData Raw byte stream of wpa_supplicant.conf
3088      * @param ipConfigData Raw byte stream of ipconfig.txt
3089      */
restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData)3090     public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
3091         enforceNetworkSettingsPermission();
3092         mLog.trace("restoreSupplicantBackupData uid=%").c(Binder.getCallingUid()).flush();
3093         if (mClientModeImplChannel == null) {
3094             Slog.e(TAG, "mClientModeImplChannel is not initialized");
3095             return;
3096         }
3097 
3098         Slog.d(TAG, "Restoring supplicant backup data");
3099         List<WifiConfiguration> wifiConfigurations =
3100                 mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData(
3101                         supplicantData, ipConfigData);
3102         restoreNetworks(wifiConfigurations);
3103         Slog.d(TAG, "Restored supplicant backup data");
3104     }
3105 
3106     /**
3107      * Starts subscription provisioning with a provider.
3108      *
3109      * @param provider {@link OsuProvider} the provider to provision with
3110      * @param callback {@link IProvisioningCallback} the callback object to inform status
3111      */
3112     @Override
startSubscriptionProvisioning(OsuProvider provider, IProvisioningCallback callback)3113     public void startSubscriptionProvisioning(OsuProvider provider,
3114             IProvisioningCallback callback) {
3115         if (provider == null) {
3116             throw new IllegalArgumentException("Provider must not be null");
3117         }
3118         if (callback == null) {
3119             throw new IllegalArgumentException("Callback must not be null");
3120         }
3121         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
3122             throw new SecurityException(TAG + ": Permission denied");
3123         }
3124         if (!mContext.getPackageManager().hasSystemFeature(
3125                 PackageManager.FEATURE_WIFI_PASSPOINT)) {
3126             throw new UnsupportedOperationException("Passpoint not enabled");
3127         }
3128         final int uid = Binder.getCallingUid();
3129         mLog.trace("startSubscriptionProvisioning uid=%").c(uid).flush();
3130         if (mClientModeImpl.syncStartSubscriptionProvisioning(uid, provider,
3131                 callback, mClientModeImplChannel)) {
3132             mLog.trace("Subscription provisioning started with %")
3133                     .c(provider.toString()).flush();
3134         }
3135     }
3136 
3137     /**
3138      * see {@link android.net.wifi.WifiManager#registerTrafficStateCallback(
3139      * WifiManager.TrafficStateCallback, Handler)}
3140      *
3141      * @param binder IBinder instance to allow cleanup if the app dies
3142      * @param callback Traffic State callback to register
3143      * @param callbackIdentifier Unique ID of the registering callback. This ID will be used to
3144      *        unregister the callback. See {@link unregisterTrafficStateCallback(int)}
3145      *
3146      * @throws SecurityException if the caller does not have permission to register a callback
3147      * @throws RemoteException if remote exception happens
3148      * @throws IllegalArgumentException if the arguments are null or invalid
3149      */
3150     @Override
registerTrafficStateCallback(IBinder binder, ITrafficStateCallback callback, int callbackIdentifier)3151     public void registerTrafficStateCallback(IBinder binder, ITrafficStateCallback callback,
3152                                              int callbackIdentifier) {
3153         // verify arguments
3154         if (binder == null) {
3155             throw new IllegalArgumentException("Binder must not be null");
3156         }
3157         if (callback == null) {
3158             throw new IllegalArgumentException("Callback must not be null");
3159         }
3160         enforceNetworkSettingsPermission();
3161         if (mVerboseLoggingEnabled) {
3162             mLog.info("registerTrafficStateCallback uid=%").c(Binder.getCallingUid()).flush();
3163         }
3164         // Post operation to handler thread
3165         mWifiInjector.getClientModeImplHandler().post(() -> {
3166             mWifiTrafficPoller.addCallback(binder, callback, callbackIdentifier);
3167         });
3168     }
3169 
3170     /**
3171      * see {@link android.net.wifi.WifiManager#unregisterTrafficStateCallback(
3172      * WifiManager.TrafficStateCallback)}
3173      *
3174      * @param callbackIdentifier Unique ID of the callback to be unregistered.
3175      *
3176      * @throws SecurityException if the caller does not have permission to register a callback
3177      */
3178     @Override
unregisterTrafficStateCallback(int callbackIdentifier)3179     public void unregisterTrafficStateCallback(int callbackIdentifier) {
3180         enforceNetworkSettingsPermission();
3181         if (mVerboseLoggingEnabled) {
3182             mLog.info("unregisterTrafficStateCallback uid=%").c(Binder.getCallingUid()).flush();
3183         }
3184         // Post operation to handler thread
3185         mWifiInjector.getClientModeImplHandler().post(() -> {
3186             mWifiTrafficPoller.removeCallback(callbackIdentifier);
3187         });
3188     }
3189 
is5GhzSupported()3190     private boolean is5GhzSupported() {
3191         return (getSupportedFeaturesInternal() & WIFI_FEATURE_INFRA_5G) == WIFI_FEATURE_INFRA_5G;
3192     }
3193 
getSupportedFeaturesInternal()3194     private long getSupportedFeaturesInternal() {
3195         final AsyncChannel channel = mClientModeImplChannel;
3196         if (channel != null) {
3197             return mClientModeImpl.syncGetSupportedFeatures(channel);
3198         } else {
3199             Slog.e(TAG, "mClientModeImplChannel is not initialized");
3200             return 0;
3201         }
3202     }
3203 
hasAutomotiveFeature(Context context)3204     private static boolean hasAutomotiveFeature(Context context) {
3205         return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
3206     }
3207 
3208     /**
3209      * see {@link android.net.wifi.WifiManager#registerNetworkRequestMatchCallback(
3210      * WifiManager.NetworkRequestMatchCallback, Handler)} (
3211      *
3212      * @param binder IBinder instance to allow cleanup if the app dies
3213      * @param callback Network Request Match callback to register
3214      * @param callbackIdentifier Unique ID of the registering callback. This ID will be used to
3215      *                           unregister the callback.
3216      *                           See {@link #unregisterNetworkRequestMatchCallback(int)} (int)}
3217      *
3218      * @throws SecurityException if the caller does not have permission to register a callback
3219      * @throws RemoteException if remote exception happens
3220      * @throws IllegalArgumentException if the arguments are null or invalid
3221      */
3222     @Override
registerNetworkRequestMatchCallback(IBinder binder, INetworkRequestMatchCallback callback, int callbackIdentifier)3223     public void registerNetworkRequestMatchCallback(IBinder binder,
3224                                                     INetworkRequestMatchCallback callback,
3225                                                     int callbackIdentifier) {
3226         // verify arguments
3227         if (binder == null) {
3228             throw new IllegalArgumentException("Binder must not be null");
3229         }
3230         if (callback == null) {
3231             throw new IllegalArgumentException("Callback must not be null");
3232         }
3233         enforceNetworkSettingsPermission();
3234         if (mVerboseLoggingEnabled) {
3235             mLog.info("registerNetworkRequestMatchCallback uid=%")
3236                     .c(Binder.getCallingUid()).flush();
3237         }
3238         // Post operation to handler thread
3239         mWifiInjector.getClientModeImplHandler().post(() -> {
3240             mClientModeImpl.addNetworkRequestMatchCallback(binder, callback, callbackIdentifier);
3241         });
3242     }
3243 
3244     /**
3245      * see {@link android.net.wifi.WifiManager#unregisterNetworkRequestMatchCallback(
3246      * WifiManager.NetworkRequestMatchCallback)}
3247      *
3248      * @param callbackIdentifier Unique ID of the callback to be unregistered.
3249      *
3250      * @throws SecurityException if the caller does not have permission to register a callback
3251      */
3252     @Override
unregisterNetworkRequestMatchCallback(int callbackIdentifier)3253     public void unregisterNetworkRequestMatchCallback(int callbackIdentifier) {
3254         enforceNetworkSettingsPermission();
3255         if (mVerboseLoggingEnabled) {
3256             mLog.info("unregisterNetworkRequestMatchCallback uid=%")
3257                     .c(Binder.getCallingUid()).flush();
3258         }
3259         // Post operation to handler thread
3260         mWifiInjector.getClientModeImplHandler().post(() -> {
3261             mClientModeImpl.removeNetworkRequestMatchCallback(callbackIdentifier);
3262         });
3263     }
3264 
3265     /**
3266      * See {@link android.net.wifi.WifiManager#addNetworkSuggestions(List)}
3267      *
3268      * @param networkSuggestions List of network suggestions to be added.
3269      * @param callingPackageName Package Name of the app adding the suggestions.
3270      * @throws SecurityException if the caller does not have permission.
3271      * @return One of status codes from {@link WifiManager.NetworkSuggestionsStatusCode}.
3272      */
3273     @Override
addNetworkSuggestions( List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName)3274     public int addNetworkSuggestions(
3275             List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) {
3276         if (enforceChangePermission(callingPackageName) != MODE_ALLOWED) {
3277             return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED;
3278         }
3279         if (mVerboseLoggingEnabled) {
3280             mLog.info("addNetworkSuggestions uid=%").c(Binder.getCallingUid()).flush();
3281         }
3282         int callingUid = Binder.getCallingUid();
3283         Mutable<Integer> success = new Mutable<>();
3284         boolean runWithScissorsSuccess = mWifiInjector.getClientModeImplHandler().runWithScissors(
3285                 () -> {
3286                     success.value = mWifiNetworkSuggestionsManager.add(
3287                             networkSuggestions, callingUid, callingPackageName);
3288                 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
3289         if (!runWithScissorsSuccess) {
3290             Log.e(TAG, "Failed to post runnable to add network suggestions");
3291             return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL;
3292         }
3293         if (success.value != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
3294             Log.e(TAG, "Failed to add network suggestions");
3295         }
3296         return success.value;
3297     }
3298 
3299     /**
3300      * See {@link android.net.wifi.WifiManager#removeNetworkSuggestions(List)}
3301      *
3302      * @param networkSuggestions List of network suggestions to be removed.
3303      * @param callingPackageName Package Name of the app removing the suggestions.
3304      * @throws SecurityException if the caller does not have permission.
3305      * @return One of status codes from {@link WifiManager.NetworkSuggestionsStatusCode}.
3306      */
3307     @Override
removeNetworkSuggestions( List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName)3308     public int removeNetworkSuggestions(
3309             List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) {
3310         if (enforceChangePermission(callingPackageName) != MODE_ALLOWED) {
3311             return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED;
3312         }
3313         if (mVerboseLoggingEnabled) {
3314             mLog.info("removeNetworkSuggestions uid=%").c(Binder.getCallingUid()).flush();
3315         }
3316         Mutable<Integer> success = new Mutable<>();
3317         boolean runWithScissorsSuccess = mWifiInjector.getClientModeImplHandler().runWithScissors(
3318                 () -> {
3319                     success.value = mWifiNetworkSuggestionsManager.remove(
3320                             networkSuggestions, callingPackageName);
3321                 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
3322         if (!runWithScissorsSuccess) {
3323             Log.e(TAG, "Failed to post runnable to remove network suggestions");
3324             return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL;
3325         }
3326         if (success.value != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
3327             Log.e(TAG, "Failed to remove network suggestions");
3328         }
3329         return success.value;
3330     }
3331 
3332     /**
3333      * Gets the factory Wi-Fi MAC addresses.
3334      * @throws SecurityException if the caller does not have permission.
3335      * @return Array of String representing Wi-Fi MAC addresses, or null if failed.
3336      */
3337     @Override
getFactoryMacAddresses()3338     public String[] getFactoryMacAddresses() {
3339         final int uid = Binder.getCallingUid();
3340         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
3341             throw new SecurityException("App not allowed to get Wi-Fi factory MAC address "
3342                     + "(uid = " + uid + ")");
3343         }
3344         final List<String> result = new ArrayList<>();
3345         boolean success = mWifiInjector.getClientModeImplHandler().runWithScissors(() -> {
3346             final String mac = mClientModeImpl.getFactoryMacAddress();
3347             if (mac != null) {
3348                 result.add(mac);
3349             }
3350         }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
3351         if (success) {
3352             return result.isEmpty() ? null : result.stream().toArray(String[]::new);
3353         }
3354         return null;
3355     }
3356 
3357     /**
3358      * Sets the current device mobility state.
3359      * @param state the new device mobility state
3360      */
3361     @Override
setDeviceMobilityState(@eviceMobilityState int state)3362     public void setDeviceMobilityState(@DeviceMobilityState int state) {
3363         mContext.enforceCallingPermission(
3364                 android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE, "WifiService");
3365 
3366         if (mVerboseLoggingEnabled) {
3367             mLog.info("setDeviceMobilityState uid=% state=%")
3368                     .c(Binder.getCallingUid())
3369                     .c(state)
3370                     .flush();
3371         }
3372         // Post operation to handler thread
3373         mWifiInjector.getClientModeImplHandler().post(
3374                 () -> mClientModeImpl.setDeviceMobilityState(state));
3375     }
3376 
3377     /**
3378      * Proxy for the final native call of the parent class. Enables mocking of
3379      * the function.
3380      */
getMockableCallingUid()3381     public int getMockableCallingUid() {
3382         return getCallingUid();
3383     }
3384 
3385     /**
3386      * Start DPP in Configurator-Initiator role. The current device will initiate DPP bootstrapping
3387      * with a peer, and send the SSID and password of the selected network.
3388      *
3389      * @param binder Caller's binder context
3390      * @param enrolleeUri URI of the Enrollee obtained externally (e.g. QR code scanning)
3391      * @param selectedNetworkId Selected network ID to be sent to the peer
3392      * @param netRole The network role of the enrollee
3393      * @param callback Callback for status updates
3394      */
3395     @Override
startDppAsConfiguratorInitiator(IBinder binder, String enrolleeUri, int selectedNetworkId, int netRole, IDppCallback callback)3396     public void startDppAsConfiguratorInitiator(IBinder binder, String enrolleeUri,
3397             int selectedNetworkId, int netRole, IDppCallback callback) {
3398         // verify arguments
3399         if (binder == null) {
3400             throw new IllegalArgumentException("Binder must not be null");
3401         }
3402         if (TextUtils.isEmpty(enrolleeUri)) {
3403             throw new IllegalArgumentException("Enrollee URI must not be null or empty");
3404         }
3405         if (selectedNetworkId < 0) {
3406             throw new IllegalArgumentException("Selected network ID invalid");
3407         }
3408         if (callback == null) {
3409             throw new IllegalArgumentException("Callback must not be null");
3410         }
3411 
3412         final int uid = getMockableCallingUid();
3413 
3414         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
3415             throw new SecurityException(TAG + ": Permission denied");
3416         }
3417 
3418         mDppManager.mHandler.post(() -> {
3419             mDppManager.startDppAsConfiguratorInitiator(uid, binder, enrolleeUri,
3420                     selectedNetworkId, netRole, callback);
3421         });
3422     }
3423 
3424     /**
3425      * Start DPP in Enrollee-Initiator role. The current device will initiate DPP bootstrapping
3426      * with a peer, and receive the SSID and password from the peer configurator.
3427      *
3428      * @param binder Caller's binder context
3429      * @param configuratorUri URI of the Configurator obtained externally (e.g. QR code scanning)
3430      * @param callback Callback for status updates
3431      */
3432     @Override
startDppAsEnrolleeInitiator(IBinder binder, String configuratorUri, IDppCallback callback)3433     public void startDppAsEnrolleeInitiator(IBinder binder, String configuratorUri,
3434             IDppCallback callback) {
3435         // verify arguments
3436         if (binder == null) {
3437             throw new IllegalArgumentException("Binder must not be null");
3438         }
3439         if (TextUtils.isEmpty(configuratorUri)) {
3440             throw new IllegalArgumentException("Enrollee URI must not be null or empty");
3441         }
3442         if (callback == null) {
3443             throw new IllegalArgumentException("Callback must not be null");
3444         }
3445 
3446         final int uid = getMockableCallingUid();
3447 
3448         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
3449             throw new SecurityException(TAG + ": Permission denied");
3450         }
3451 
3452         mDppManager.mHandler.post(() -> {
3453             mDppManager.startDppAsEnrolleeInitiator(uid, binder, configuratorUri, callback);
3454         });
3455     }
3456 
3457     /**
3458      * Stop or abort a current DPP session.
3459      */
3460     @Override
stopDppSession()3461     public void stopDppSession() throws android.os.RemoteException {
3462         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
3463             throw new SecurityException(TAG + ": Permission denied");
3464         }
3465         final int uid = getMockableCallingUid();
3466 
3467         mDppManager.mHandler.post(() -> {
3468             mDppManager.stopDppSession(uid);
3469         });
3470     }
3471 
3472     /**
3473      * see {@link android.net.wifi.WifiManager#addOnWifiUsabilityStatsListener(Executor,
3474      * OnWifiUsabilityStatsListener)}
3475      *
3476      * @param binder IBinder instance to allow cleanup if the app dies
3477      * @param listener WifiUsabilityStatsEntry listener to add
3478      * @param listenerIdentifier Unique ID of the adding listener. This ID will be used to
3479      *        remove the listener. See {@link removeOnWifiUsabilityStatsListener(int)}
3480      *
3481      * @throws SecurityException if the caller does not have permission to add a listener
3482      * @throws RemoteException if remote exception happens
3483      * @throws IllegalArgumentException if the arguments are null or invalid
3484      */
3485     @Override
addOnWifiUsabilityStatsListener(IBinder binder, IOnWifiUsabilityStatsListener listener, int listenerIdentifier)3486     public void addOnWifiUsabilityStatsListener(IBinder binder,
3487             IOnWifiUsabilityStatsListener listener, int listenerIdentifier) {
3488         // verify arguments
3489         if (binder == null) {
3490             throw new IllegalArgumentException("Binder must not be null");
3491         }
3492         if (listener == null) {
3493             throw new IllegalArgumentException("Listener must not be null");
3494         }
3495         mContext.enforceCallingPermission(
3496                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
3497         if (mVerboseLoggingEnabled) {
3498             mLog.info("addOnWifiUsabilityStatsListener uid=%")
3499                 .c(Binder.getCallingUid()).flush();
3500         }
3501         // Post operation to handler thread
3502         mWifiInjector.getClientModeImplHandler().post(() -> {
3503             mWifiMetrics.addOnWifiUsabilityListener(binder, listener, listenerIdentifier);
3504         });
3505     }
3506 
3507     /**
3508      * see {@link android.net.wifi.WifiManager#removeOnWifiUsabilityStatsListener(
3509      * OnWifiUsabilityStatsListener)}
3510      *
3511      * @param listenerIdentifier Unique ID of the listener to be removed.
3512      *
3513      * @throws SecurityException if the caller does not have permission to add a listener
3514      */
3515     @Override
removeOnWifiUsabilityStatsListener(int listenerIdentifier)3516     public void removeOnWifiUsabilityStatsListener(int listenerIdentifier) {
3517         mContext.enforceCallingPermission(
3518                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
3519         if (mVerboseLoggingEnabled) {
3520             mLog.info("removeOnWifiUsabilityStatsListener uid=%")
3521                     .c(Binder.getCallingUid()).flush();
3522         }
3523         // Post operation to handler thread
3524         mWifiInjector.getClientModeImplHandler().post(() -> {
3525             mWifiMetrics.removeOnWifiUsabilityListener(listenerIdentifier);
3526         });
3527     }
3528 
3529     /**
3530      * Updates the Wi-Fi usability score.
3531      * @param seqNum Sequence number of the Wi-Fi usability score.
3532      * @param score The Wi-Fi usability score.
3533      * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second.
3534      */
3535     @Override
updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec)3536     public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
3537         mContext.enforceCallingPermission(
3538                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
3539 
3540         if (mVerboseLoggingEnabled) {
3541             mLog.info("updateWifiUsabilityScore uid=% seqNum=% score=% predictionHorizonSec=%")
3542                     .c(Binder.getCallingUid())
3543                     .c(seqNum)
3544                     .c(score)
3545                     .c(predictionHorizonSec)
3546                     .flush();
3547         }
3548         // Post operation to handler thread
3549         mWifiInjector.getClientModeImplHandler().post(
3550                 () -> mClientModeImpl.updateWifiUsabilityScore(seqNum, score,
3551                         predictionHorizonSec));
3552     }
3553 }
3554