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