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