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