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