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