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