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