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