WifiServiceImpl.java revision a8647b8cb29de22765062714cb265247234c3d32
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        validator.validate(path, params);
869    }
870
871    /**
872     * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
873     * @param netId the integer that identifies the network configuration
874     * to the supplicant
875     * @return {@code true} if the operation succeeded
876     */
877    public boolean removeNetwork(int netId) {
878        enforceChangePermission();
879
880        if (!isOwner(Binder.getCallingUid())) {
881            Slog.e(TAG, "Remove is not authorized for user");
882            return false;
883        }
884
885        if (mWifiStateMachineChannel != null) {
886            return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
887        } else {
888            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
889            return false;
890        }
891    }
892
893    /**
894     * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
895     * @param netId the integer that identifies the network configuration
896     * to the supplicant
897     * @param disableOthers if true, disable all other networks.
898     * @return {@code true} if the operation succeeded
899     */
900    public boolean enableNetwork(int netId, boolean disableOthers) {
901        enforceChangePermission();
902        if (mWifiStateMachineChannel != null) {
903            return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
904                    disableOthers);
905        } else {
906            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
907            return false;
908        }
909    }
910
911    /**
912     * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
913     * @param netId the integer that identifies the network configuration
914     * to the supplicant
915     * @return {@code true} if the operation succeeded
916     */
917    public boolean disableNetwork(int netId) {
918        enforceChangePermission();
919        if (mWifiStateMachineChannel != null) {
920            return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
921        } else {
922            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
923            return false;
924        }
925    }
926
927    /**
928     * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
929     * @return the Wi-Fi information, contained in {@link WifiInfo}.
930     */
931    public WifiInfo getConnectionInfo() {
932        enforceAccessPermission();
933        /*
934         * Make sure we have the latest information, by sending
935         * a status request to the supplicant.
936         */
937        return mWifiStateMachine.syncRequestConnectionInfo();
938    }
939
940    /**
941     * Return the results of the most recent access point scan, in the form of
942     * a list of {@link ScanResult} objects.
943     * @return the list of results
944     */
945    public List<ScanResult> getScanResults(String callingPackage) {
946        enforceAccessPermission();
947        int userId = UserHandle.getCallingUserId();
948        int uid = Binder.getCallingUid();
949        boolean isSystemProcess = (UserHandle.getAppId(uid) == android.os.Process.SYSTEM_UID);
950        boolean hasInteractUsersFull = checkInteractAcrossUsersFull();
951        long ident = Binder.clearCallingIdentity();
952        if (!isSystemProcess && !isLocationEnabled()) {
953            return new ArrayList<ScanResult>();
954        }
955        try {
956            if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
957                    != AppOpsManager.MODE_ALLOWED) {
958                return new ArrayList<ScanResult>();
959            }
960            if (!isCurrentProfile(userId) && !hasInteractUsersFull) {
961                return new ArrayList<ScanResult>();
962            }
963            if (!isSystemProcess && !checkCallerHasLocationPermission(callingPackage, uid)) {
964                return new ArrayList<ScanResult>();
965            }
966            return mWifiStateMachine.syncGetScanResultsList();
967        } finally {
968            Binder.restoreCallingIdentity(ident);
969        }
970    }
971
972    private boolean isLocationEnabled() {
973        return Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.LOCATION_MODE,
974                Settings.Secure.LOCATION_MODE_OFF) != Settings.Secure.LOCATION_MODE_OFF;
975    }
976
977    /**
978     * Returns true if the caller holds INTERACT_ACROSS_USERS_FULL.
979     */
980    private boolean checkInteractAcrossUsersFull() {
981        return mContext.checkCallingOrSelfPermission(
982                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
983                == PackageManager.PERMISSION_GRANTED;
984    }
985
986    /**
987     * Returns true if the calling user is the current one or a profile of the
988     * current user..
989     */
990    private boolean isCurrentProfile(int userId) {
991        int currentUser = ActivityManager.getCurrentUser();
992        if (userId == currentUser) {
993            return true;
994        }
995        List<UserInfo> profiles = mUserManager.getProfiles(currentUser);
996        for (UserInfo user : profiles) {
997            if (userId == user.id) {
998                return true;
999            }
1000        }
1001        return false;
1002    }
1003
1004    /**
1005     * Returns true if uid is an application running under the owner or a profile of the owner.
1006     *
1007     * Note: Should not be called if identity is cleared.
1008     */
1009    private boolean isOwner(int uid) {
1010        long ident = Binder.clearCallingIdentity();
1011        int userId = UserHandle.getUserId(uid);
1012        try {
1013            int ownerUser = UserHandle.USER_OWNER;
1014            if (userId == ownerUser) {
1015                return true;
1016            }
1017            List<UserInfo> profiles = mUserManager.getProfiles(ownerUser);
1018            for (UserInfo profile : profiles) {
1019                if (userId == profile.id) {
1020                    return true;
1021                }
1022            }
1023            return false;
1024        }
1025        finally {
1026            Binder.restoreCallingIdentity(ident);
1027        }
1028    }
1029
1030
1031    /**
1032     * Tell the supplicant to persist the current list of configured networks.
1033     * @return {@code true} if the operation succeeded
1034     *
1035     * TODO: deprecate this
1036     */
1037    public boolean saveConfiguration() {
1038        boolean result = true;
1039        enforceChangePermission();
1040        if (mWifiStateMachineChannel != null) {
1041            return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
1042        } else {
1043            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1044            return false;
1045        }
1046    }
1047
1048    /**
1049     * Set the country code
1050     * @param countryCode ISO 3166 country code.
1051     * @param persist {@code true} if the setting should be remembered.
1052     *
1053     * The persist behavior exists so that wifi can fall back to the last
1054     * persisted country code on a restart, when the locale information is
1055     * not available from telephony.
1056     */
1057    public void setCountryCode(String countryCode, boolean persist) {
1058        Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
1059                " with persist set to " + persist);
1060        enforceConnectivityInternalPermission();
1061        final long token = Binder.clearCallingIdentity();
1062        try {
1063            mWifiStateMachine.setCountryCode(countryCode, persist);
1064        } finally {
1065            Binder.restoreCallingIdentity(token);
1066        }
1067    }
1068
1069     /**
1070     * Get the country code
1071     * @return ISO 3166 country code.
1072     */
1073    public String getCountryCode() {
1074        enforceConnectivityInternalPermission();
1075        String country = mWifiStateMachine.getCountryCode();
1076        return country;
1077    }
1078    /**
1079     * Set the operational frequency band
1080     * @param band One of
1081     *     {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
1082     *     {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
1083     *     {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
1084     * @param persist {@code true} if the setting should be remembered.
1085     *
1086     */
1087    public void setFrequencyBand(int band, boolean persist) {
1088        enforceChangePermission();
1089        if (!isDualBandSupported()) return;
1090        Slog.i(TAG, "WifiService trying to set frequency band to " + band +
1091                " with persist set to " + persist);
1092        final long token = Binder.clearCallingIdentity();
1093        try {
1094            mWifiStateMachine.setFrequencyBand(band, persist);
1095        } finally {
1096            Binder.restoreCallingIdentity(token);
1097        }
1098    }
1099
1100
1101    /**
1102     * Get the operational frequency band
1103     */
1104    public int getFrequencyBand() {
1105        enforceAccessPermission();
1106        return mWifiStateMachine.getFrequencyBand();
1107    }
1108
1109    public boolean isDualBandSupported() {
1110        //TODO: Should move towards adding a driver API that checks at runtime
1111        return mContext.getResources().getBoolean(
1112                com.android.internal.R.bool.config_wifi_dual_band_support);
1113    }
1114
1115    /**
1116     * Return the DHCP-assigned addresses from the last successful DHCP request,
1117     * if any.
1118     * @return the DHCP information
1119     * @deprecated
1120     */
1121    public DhcpInfo getDhcpInfo() {
1122        enforceAccessPermission();
1123        DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults();
1124
1125        DhcpInfo info = new DhcpInfo();
1126
1127        if (dhcpResults.ipAddress != null &&
1128                dhcpResults.ipAddress.getAddress() instanceof Inet4Address) {
1129            info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.ipAddress.getAddress());
1130        }
1131
1132        if (dhcpResults.gateway != null) {
1133            info.gateway = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.gateway);
1134        }
1135
1136        int dnsFound = 0;
1137        for (InetAddress dns : dhcpResults.dnsServers) {
1138            if (dns instanceof Inet4Address) {
1139                if (dnsFound == 0) {
1140                    info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1141                } else {
1142                    info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1143                }
1144                if (++dnsFound > 1) break;
1145            }
1146        }
1147        InetAddress serverAddress = dhcpResults.serverAddress;
1148        if (serverAddress instanceof Inet4Address) {
1149            info.serverAddress = NetworkUtils.inetAddressToInt((Inet4Address)serverAddress);
1150        }
1151        info.leaseDuration = dhcpResults.leaseDuration;
1152
1153        return info;
1154    }
1155
1156    /**
1157     * see {@link android.net.wifi.WifiManager#startWifi}
1158     *
1159     */
1160    public void startWifi() {
1161        enforceConnectivityInternalPermission();
1162        /* TODO: may be add permissions for access only to connectivity service
1163         * TODO: if a start issued, keep wifi alive until a stop issued irrespective
1164         * of WifiLock & device idle status unless wifi enabled status is toggled
1165         */
1166
1167        mWifiStateMachine.setDriverStart(true);
1168        mWifiStateMachine.reconnectCommand();
1169    }
1170
1171    /**
1172     * see {@link android.net.wifi.WifiManager#stopWifi}
1173     *
1174     */
1175    public void stopWifi() {
1176        enforceConnectivityInternalPermission();
1177        /*
1178         * TODO: if a stop is issued, wifi is brought up only by startWifi
1179         * unless wifi enabled status is toggled
1180         */
1181        mWifiStateMachine.setDriverStart(false);
1182    }
1183
1184    /**
1185     * see {@link android.net.wifi.WifiManager#addToBlacklist}
1186     *
1187     */
1188    public void addToBlacklist(String bssid) {
1189        enforceChangePermission();
1190
1191        mWifiStateMachine.addToBlacklist(bssid);
1192    }
1193
1194    /**
1195     * see {@link android.net.wifi.WifiManager#clearBlacklist}
1196     *
1197     */
1198    public void clearBlacklist() {
1199        enforceChangePermission();
1200
1201        mWifiStateMachine.clearBlacklist();
1202    }
1203
1204    /**
1205     * enable TDLS for the local NIC to remote NIC
1206     * The APPs don't know the remote MAC address to identify NIC though,
1207     * so we need to do additional work to find it from remote IP address
1208     */
1209
1210    class TdlsTaskParams {
1211        public String remoteIpAddress;
1212        public boolean enable;
1213    }
1214
1215    class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> {
1216        @Override
1217        protected Integer doInBackground(TdlsTaskParams... params) {
1218
1219            // Retrieve parameters for the call
1220            TdlsTaskParams param = params[0];
1221            String remoteIpAddress = param.remoteIpAddress.trim();
1222            boolean enable = param.enable;
1223
1224            // Get MAC address of Remote IP
1225            String macAddress = null;
1226
1227            BufferedReader reader = null;
1228
1229            try {
1230                reader = new BufferedReader(new FileReader("/proc/net/arp"));
1231
1232                // Skip over the line bearing colum titles
1233                String line = reader.readLine();
1234
1235                while ((line = reader.readLine()) != null) {
1236                    String[] tokens = line.split("[ ]+");
1237                    if (tokens.length < 6) {
1238                        continue;
1239                    }
1240
1241                    // ARP column format is
1242                    // Address HWType HWAddress Flags Mask IFace
1243                    String ip = tokens[0];
1244                    String mac = tokens[3];
1245
1246                    if (remoteIpAddress.equals(ip)) {
1247                        macAddress = mac;
1248                        break;
1249                    }
1250                }
1251
1252                if (macAddress == null) {
1253                    Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " +
1254                            "/proc/net/arp");
1255                } else {
1256                    enableTdlsWithMacAddress(macAddress, enable);
1257                }
1258
1259            } catch (FileNotFoundException e) {
1260                Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address");
1261            } catch (IOException e) {
1262                Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address");
1263            } finally {
1264                try {
1265                    if (reader != null) {
1266                        reader.close();
1267                    }
1268                }
1269                catch (IOException e) {
1270                    // Do nothing
1271                }
1272            }
1273
1274            return 0;
1275        }
1276    }
1277
1278    public void enableTdls(String remoteAddress, boolean enable) {
1279        if (remoteAddress == null) {
1280          throw new IllegalArgumentException("remoteAddress cannot be null");
1281        }
1282
1283        TdlsTaskParams params = new TdlsTaskParams();
1284        params.remoteIpAddress = remoteAddress;
1285        params.enable = enable;
1286        new TdlsTask().execute(params);
1287    }
1288
1289
1290    public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
1291        if (remoteMacAddress == null) {
1292          throw new IllegalArgumentException("remoteMacAddress cannot be null");
1293        }
1294
1295        mWifiStateMachine.enableTdls(remoteMacAddress, enable);
1296    }
1297
1298    /**
1299     * Get a reference to handler. This is used by a client to establish
1300     * an AsyncChannel communication with WifiService
1301     */
1302    public Messenger getWifiServiceMessenger() {
1303        enforceAccessPermission();
1304        enforceChangePermission();
1305        return new Messenger(mClientHandler);
1306    }
1307
1308    /**
1309     * Disable an ephemeral network, i.e. network that is created thru a WiFi Scorer
1310     */
1311    public void disableEphemeralNetwork(String SSID) {
1312        enforceAccessPermission();
1313        enforceChangePermission();
1314        mWifiStateMachine.disableEphemeralNetwork(SSID);
1315    }
1316
1317    /**
1318     * Get the IP and proxy configuration file
1319     */
1320    public String getConfigFile() {
1321        enforceAccessPermission();
1322        return mWifiStateMachine.getConfigFile();
1323    }
1324
1325    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1326        @Override
1327        public void onReceive(Context context, Intent intent) {
1328            String action = intent.getAction();
1329            if (action.equals(Intent.ACTION_SCREEN_ON)) {
1330                mWifiController.sendMessage(CMD_SCREEN_ON);
1331            } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1332                mWifiController.sendMessage(CMD_USER_PRESENT);
1333            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1334                mWifiController.sendMessage(CMD_SCREEN_OFF);
1335            } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
1336                int pluggedType = intent.getIntExtra("plugged", 0);
1337                mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null);
1338            } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
1339                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
1340                        BluetoothAdapter.STATE_DISCONNECTED);
1341                mWifiStateMachine.sendBluetoothAdapterStateChange(state);
1342            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
1343                boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false);
1344                mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0);
1345            } else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
1346                handleIdleModeChanged();
1347            }
1348        }
1349    };
1350
1351    /**
1352     * Observes settings changes to scan always mode.
1353     */
1354    private void registerForScanModeChange() {
1355        ContentObserver contentObserver = new ContentObserver(null) {
1356            @Override
1357            public void onChange(boolean selfChange) {
1358                mSettingsStore.handleWifiScanAlwaysAvailableToggled();
1359                mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED);
1360            }
1361        };
1362
1363        mContext.getContentResolver().registerContentObserver(
1364                Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE),
1365                false, contentObserver);
1366    }
1367
1368    private void registerForBroadcasts() {
1369        IntentFilter intentFilter = new IntentFilter();
1370        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
1371        intentFilter.addAction(Intent.ACTION_USER_PRESENT);
1372        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
1373        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
1374        intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
1375        intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
1376        intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
1377        intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
1378        mContext.registerReceiver(mReceiver, intentFilter);
1379    }
1380
1381    private void registerForPackageOrUserRemoval() {
1382        IntentFilter intentFilter = new IntentFilter();
1383        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1384        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
1385        mContext.registerReceiverAsUser(new BroadcastReceiver() {
1386            @Override
1387            public void onReceive(Context context, Intent intent) {
1388                switch (intent.getAction()) {
1389                    case Intent.ACTION_PACKAGE_REMOVED: {
1390                        if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1391                            return;
1392                        }
1393                        int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
1394                        Uri uri = intent.getData();
1395                        if (uid == -1 || uri == null) {
1396                            return;
1397                        }
1398                        String pkgName = uri.getSchemeSpecificPart();
1399                        mWifiStateMachine.removeAppConfigs(pkgName, uid);
1400                        break;
1401                    }
1402                    case Intent.ACTION_USER_REMOVED: {
1403                        int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
1404                        mWifiStateMachine.removeUserConfigs(userHandle);
1405                        break;
1406                    }
1407                }
1408            }
1409        }, UserHandle.ALL, intentFilter, null, null);
1410    }
1411
1412    @Override
1413    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1414        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1415                != PackageManager.PERMISSION_GRANTED) {
1416            pw.println("Permission Denial: can't dump WifiService from from pid="
1417                    + Binder.getCallingPid()
1418                    + ", uid=" + Binder.getCallingUid());
1419            return;
1420        }
1421        pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
1422        pw.println("Stay-awake conditions: " +
1423                Settings.Global.getInt(mContext.getContentResolver(),
1424                                       Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
1425        pw.println("mMulticastEnabled " + mMulticastEnabled);
1426        pw.println("mMulticastDisabled " + mMulticastDisabled);
1427        pw.println("mInIdleMode " + mInIdleMode);
1428        pw.println("mScanPending " + mScanPending);
1429        mWifiController.dump(fd, pw, args);
1430        mSettingsStore.dump(fd, pw, args);
1431        mNotificationController.dump(fd, pw, args);
1432        mTrafficPoller.dump(fd, pw, args);
1433
1434        pw.println("Latest scan results:");
1435        List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
1436        long nowMs = System.currentTimeMillis();
1437        if (scanResults != null && scanResults.size() != 0) {
1438            pw.println("    BSSID              Frequency  RSSI    Age      SSID " +
1439                    "                                Flags");
1440            for (ScanResult r : scanResults) {
1441                long ageSec = 0;
1442                long ageMilli = 0;
1443                if (nowMs > r.seen && r.seen > 0) {
1444                    ageSec = (nowMs - r.seen) / 1000;
1445                    ageMilli = (nowMs - r.seen) % 1000;
1446                }
1447                String candidate = " ";
1448                if (r.isAutoJoinCandidate > 0) candidate = "+";
1449                pw.printf("  %17s  %9d  %5d  %3d.%03d%s   %-32s  %s\n",
1450                                         r.BSSID,
1451                                         r.frequency,
1452                                         r.level,
1453                                         ageSec, ageMilli,
1454                                         candidate,
1455                                         r.SSID == null ? "" : r.SSID,
1456                                         r.capabilities);
1457            }
1458        }
1459        pw.println();
1460        pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
1461                mFullHighPerfLocksAcquired + " full high perf, " +
1462                mScanLocksAcquired + " scan");
1463        pw.println("Locks released: " + mFullLocksReleased + " full, " +
1464                mFullHighPerfLocksReleased + " full high perf, " +
1465                mScanLocksReleased + " scan");
1466        pw.println();
1467        pw.println("Locks held:");
1468        mLocks.dump(pw);
1469
1470        pw.println("Multicast Locks held:");
1471        for (Multicaster l : mMulticasters) {
1472            pw.print("    ");
1473            pw.println(l);
1474        }
1475
1476        mWifiWatchdogStateMachine.dump(fd, pw, args);
1477        pw.println();
1478        mWifiStateMachine.dump(fd, pw, args);
1479        pw.println();
1480    }
1481
1482    private class WifiLock extends DeathRecipient {
1483        WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
1484            super(lockMode, tag, binder, ws);
1485        }
1486
1487        public void binderDied() {
1488            synchronized (mLocks) {
1489                releaseWifiLockLocked(mBinder);
1490            }
1491        }
1492
1493        public String toString() {
1494            return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
1495        }
1496    }
1497
1498    class LockList {
1499        private List<WifiLock> mList;
1500
1501        private LockList() {
1502            mList = new ArrayList<WifiLock>();
1503        }
1504
1505        synchronized boolean hasLocks() {
1506            return !mList.isEmpty();
1507        }
1508
1509        synchronized int getStrongestLockMode() {
1510            if (mList.isEmpty()) {
1511                return WifiManager.WIFI_MODE_FULL;
1512            }
1513
1514            if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
1515                return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
1516            }
1517
1518            if (mFullLocksAcquired > mFullLocksReleased) {
1519                return WifiManager.WIFI_MODE_FULL;
1520            }
1521
1522            return WifiManager.WIFI_MODE_SCAN_ONLY;
1523        }
1524
1525        synchronized void updateWorkSource(WorkSource ws) {
1526            for (int i = 0; i < mLocks.mList.size(); i++) {
1527                ws.add(mLocks.mList.get(i).mWorkSource);
1528            }
1529        }
1530
1531        private void addLock(WifiLock lock) {
1532            if (findLockByBinder(lock.mBinder) < 0) {
1533                mList.add(lock);
1534            }
1535        }
1536
1537        private WifiLock removeLock(IBinder binder) {
1538            int index = findLockByBinder(binder);
1539            if (index >= 0) {
1540                WifiLock ret = mList.remove(index);
1541                ret.unlinkDeathRecipient();
1542                return ret;
1543            } else {
1544                return null;
1545            }
1546        }
1547
1548        private int findLockByBinder(IBinder binder) {
1549            int size = mList.size();
1550            for (int i = size - 1; i >= 0; i--) {
1551                if (mList.get(i).mBinder == binder)
1552                    return i;
1553            }
1554            return -1;
1555        }
1556
1557        private void dump(PrintWriter pw) {
1558            for (WifiLock l : mList) {
1559                pw.print("    ");
1560                pw.println(l);
1561            }
1562        }
1563    }
1564
1565    void enforceWakeSourcePermission(int uid, int pid) {
1566        if (uid == android.os.Process.myUid()) {
1567            return;
1568        }
1569        mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
1570                pid, uid, null);
1571    }
1572
1573    public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
1574        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1575        if (lockMode != WifiManager.WIFI_MODE_FULL &&
1576                lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
1577                lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
1578            Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
1579            if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
1580            return false;
1581        }
1582        if (ws != null && ws.size() == 0) {
1583            ws = null;
1584        }
1585        if (ws != null) {
1586            enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
1587        }
1588        if (ws == null) {
1589            ws = new WorkSource(Binder.getCallingUid());
1590        }
1591        WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
1592        synchronized (mLocks) {
1593            return acquireWifiLockLocked(wifiLock);
1594        }
1595    }
1596
1597    private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
1598        switch(wifiLock.mMode) {
1599            case WifiManager.WIFI_MODE_FULL:
1600            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1601            case WifiManager.WIFI_MODE_SCAN_ONLY:
1602                mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
1603                break;
1604        }
1605    }
1606
1607    private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
1608        switch(wifiLock.mMode) {
1609            case WifiManager.WIFI_MODE_FULL:
1610            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1611            case WifiManager.WIFI_MODE_SCAN_ONLY:
1612                mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
1613                break;
1614        }
1615    }
1616
1617    private boolean acquireWifiLockLocked(WifiLock wifiLock) {
1618        if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
1619
1620        mLocks.addLock(wifiLock);
1621
1622        long ident = Binder.clearCallingIdentity();
1623        try {
1624            noteAcquireWifiLock(wifiLock);
1625            switch(wifiLock.mMode) {
1626            case WifiManager.WIFI_MODE_FULL:
1627                ++mFullLocksAcquired;
1628                break;
1629            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1630                ++mFullHighPerfLocksAcquired;
1631                break;
1632
1633            case WifiManager.WIFI_MODE_SCAN_ONLY:
1634                ++mScanLocksAcquired;
1635                break;
1636            }
1637            mWifiController.sendMessage(CMD_LOCKS_CHANGED);
1638            return true;
1639        } catch (RemoteException e) {
1640            return false;
1641        } finally {
1642            Binder.restoreCallingIdentity(ident);
1643        }
1644    }
1645
1646    public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
1647        int uid = Binder.getCallingUid();
1648        int pid = Binder.getCallingPid();
1649        if (ws != null && ws.size() == 0) {
1650            ws = null;
1651        }
1652        if (ws != null) {
1653            enforceWakeSourcePermission(uid, pid);
1654        }
1655        long ident = Binder.clearCallingIdentity();
1656        try {
1657            synchronized (mLocks) {
1658                int index = mLocks.findLockByBinder(lock);
1659                if (index < 0) {
1660                    throw new IllegalArgumentException("Wifi lock not active");
1661                }
1662                WifiLock wl = mLocks.mList.get(index);
1663                noteReleaseWifiLock(wl);
1664                wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
1665                noteAcquireWifiLock(wl);
1666            }
1667        } catch (RemoteException e) {
1668        } finally {
1669            Binder.restoreCallingIdentity(ident);
1670        }
1671    }
1672
1673    public boolean releaseWifiLock(IBinder lock) {
1674        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1675        synchronized (mLocks) {
1676            return releaseWifiLockLocked(lock);
1677        }
1678    }
1679
1680    private boolean releaseWifiLockLocked(IBinder lock) {
1681        boolean hadLock;
1682
1683        WifiLock wifiLock = mLocks.removeLock(lock);
1684
1685        if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
1686
1687        hadLock = (wifiLock != null);
1688
1689        long ident = Binder.clearCallingIdentity();
1690        try {
1691            if (hadLock) {
1692                noteReleaseWifiLock(wifiLock);
1693                switch(wifiLock.mMode) {
1694                    case WifiManager.WIFI_MODE_FULL:
1695                        ++mFullLocksReleased;
1696                        break;
1697                    case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1698                        ++mFullHighPerfLocksReleased;
1699                        break;
1700                    case WifiManager.WIFI_MODE_SCAN_ONLY:
1701                        ++mScanLocksReleased;
1702                        break;
1703                }
1704                mWifiController.sendMessage(CMD_LOCKS_CHANGED);
1705            }
1706        } catch (RemoteException e) {
1707        } finally {
1708            Binder.restoreCallingIdentity(ident);
1709        }
1710
1711        return hadLock;
1712    }
1713
1714    private abstract class DeathRecipient
1715            implements IBinder.DeathRecipient {
1716        String mTag;
1717        int mMode;
1718        IBinder mBinder;
1719        WorkSource mWorkSource;
1720
1721        DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) {
1722            super();
1723            mTag = tag;
1724            mMode = mode;
1725            mBinder = binder;
1726            mWorkSource = ws;
1727            try {
1728                mBinder.linkToDeath(this, 0);
1729            } catch (RemoteException e) {
1730                binderDied();
1731            }
1732        }
1733
1734        void unlinkDeathRecipient() {
1735            mBinder.unlinkToDeath(this, 0);
1736        }
1737    }
1738
1739    private class Multicaster extends DeathRecipient {
1740        Multicaster(String tag, IBinder binder) {
1741            super(Binder.getCallingUid(), tag, binder, null);
1742        }
1743
1744        public void binderDied() {
1745            Slog.e(TAG, "Multicaster binderDied");
1746            synchronized (mMulticasters) {
1747                int i = mMulticasters.indexOf(this);
1748                if (i != -1) {
1749                    removeMulticasterLocked(i, mMode);
1750                }
1751            }
1752        }
1753
1754        public String toString() {
1755            return "Multicaster{" + mTag + " binder=" + mBinder + "}";
1756        }
1757
1758        public int getUid() {
1759            return mMode;
1760        }
1761    }
1762
1763    public void initializeMulticastFiltering() {
1764        enforceMulticastChangePermission();
1765
1766        synchronized (mMulticasters) {
1767            // if anybody had requested filters be off, leave off
1768            if (mMulticasters.size() != 0) {
1769                return;
1770            } else {
1771                mWifiStateMachine.startFilteringMulticastV4Packets();
1772            }
1773        }
1774    }
1775
1776    public void acquireMulticastLock(IBinder binder, String tag) {
1777        enforceMulticastChangePermission();
1778
1779        synchronized (mMulticasters) {
1780            mMulticastEnabled++;
1781            mMulticasters.add(new Multicaster(tag, binder));
1782            // Note that we could call stopFilteringMulticastV4Packets only when
1783            // our new size == 1 (first call), but this function won't
1784            // be called often and by making the stopPacket call each
1785            // time we're less fragile and self-healing.
1786            mWifiStateMachine.stopFilteringMulticastV4Packets();
1787        }
1788
1789        int uid = Binder.getCallingUid();
1790        final long ident = Binder.clearCallingIdentity();
1791        try {
1792            mBatteryStats.noteWifiMulticastEnabled(uid);
1793        } catch (RemoteException e) {
1794        } finally {
1795            Binder.restoreCallingIdentity(ident);
1796        }
1797    }
1798
1799    public void releaseMulticastLock() {
1800        enforceMulticastChangePermission();
1801
1802        int uid = Binder.getCallingUid();
1803        synchronized (mMulticasters) {
1804            mMulticastDisabled++;
1805            int size = mMulticasters.size();
1806            for (int i = size - 1; i >= 0; i--) {
1807                Multicaster m = mMulticasters.get(i);
1808                if ((m != null) && (m.getUid() == uid)) {
1809                    removeMulticasterLocked(i, uid);
1810                }
1811            }
1812        }
1813    }
1814
1815    private void removeMulticasterLocked(int i, int uid)
1816    {
1817        Multicaster removed = mMulticasters.remove(i);
1818
1819        if (removed != null) {
1820            removed.unlinkDeathRecipient();
1821        }
1822        if (mMulticasters.size() == 0) {
1823            mWifiStateMachine.startFilteringMulticastV4Packets();
1824        }
1825
1826        final long ident = Binder.clearCallingIdentity();
1827        try {
1828            mBatteryStats.noteWifiMulticastDisabled(uid);
1829        } catch (RemoteException e) {
1830        } finally {
1831            Binder.restoreCallingIdentity(ident);
1832        }
1833    }
1834
1835    public boolean isMulticastEnabled() {
1836        enforceAccessPermission();
1837
1838        synchronized (mMulticasters) {
1839            return (mMulticasters.size() > 0);
1840        }
1841    }
1842
1843    public WifiMonitor getWifiMonitor() {
1844        return mWifiStateMachine.getWifiMonitor();
1845    }
1846
1847    public void enableVerboseLogging(int verbose) {
1848        enforceAccessPermission();
1849        mWifiStateMachine.enableVerboseLogging(verbose);
1850    }
1851
1852    public int getVerboseLoggingLevel() {
1853        enforceAccessPermission();
1854        return mWifiStateMachine.getVerboseLoggingLevel();
1855    }
1856
1857    public void enableAggressiveHandover(int enabled) {
1858        enforceAccessPermission();
1859        mWifiStateMachine.enableAggressiveHandover(enabled);
1860    }
1861
1862    public int getAggressiveHandover() {
1863        enforceAccessPermission();
1864        return mWifiStateMachine.getAggressiveHandover();
1865    }
1866
1867    public void setAllowScansWithTraffic(int enabled) {
1868        enforceAccessPermission();
1869        mWifiStateMachine.setAllowScansWithTraffic(enabled);
1870    }
1871
1872    public int getAllowScansWithTraffic() {
1873        enforceAccessPermission();
1874        return mWifiStateMachine.getAllowScansWithTraffic();
1875    }
1876
1877    public boolean enableAutoJoinWhenAssociated(boolean enabled) {
1878        enforceChangePermission();
1879        return mWifiStateMachine.enableAutoJoinWhenAssociated(enabled);
1880    }
1881
1882    public boolean getEnableAutoJoinWhenAssociated() {
1883        enforceAccessPermission();
1884        return mWifiStateMachine.getEnableAutoJoinWhenAssociated();
1885    }
1886    public void setHalBasedAutojoinOffload(int enabled) {
1887        enforceChangePermission();
1888        mWifiStateMachine.setHalBasedAutojoinOffload(enabled);
1889    }
1890
1891    public int getHalBasedAutojoinOffload() {
1892        enforceAccessPermission();
1893        return mWifiStateMachine.getHalBasedAutojoinOffload();
1894    }
1895
1896    /* Return the Wifi Connection statistics object */
1897    public WifiConnectionStatistics getConnectionStatistics() {
1898        enforceAccessPermission();
1899        enforceReadCredentialPermission();
1900        if (mWifiStateMachineChannel != null) {
1901            return mWifiStateMachine.syncGetConnectionStatistics(mWifiStateMachineChannel);
1902        } else {
1903            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1904            return null;
1905        }
1906    }
1907
1908    public void factoryReset() {
1909        enforceConnectivityInternalPermission();
1910
1911        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
1912            return;
1913        }
1914
1915        if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
1916            // Turn mobile hotspot off
1917            setWifiApEnabled(null, false);
1918        }
1919
1920        if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI)) {
1921            // Enable wifi
1922            setWifiEnabled(true);
1923            // Delete all Wifi SSIDs
1924            List<WifiConfiguration> networks = getConfiguredNetworks();
1925            if (networks != null) {
1926                for (WifiConfiguration config : networks) {
1927                    removeNetwork(config.networkId);
1928                }
1929                saveConfiguration();
1930            }
1931        }
1932    }
1933
1934    /* private methods */
1935    static boolean logAndReturnFalse(String s) {
1936        Log.d(TAG, s);
1937        return false;
1938    }
1939
1940    public static boolean isValid(WifiConfiguration config) {
1941        String validity = checkValidity(config);
1942        return validity == null || logAndReturnFalse(validity);
1943    }
1944
1945    public static String checkValidity(WifiConfiguration config) {
1946        if (config.allowedKeyManagement == null)
1947            return "allowed kmgmt";
1948
1949        if (config.allowedKeyManagement.cardinality() > 1) {
1950            if (config.allowedKeyManagement.cardinality() != 2) {
1951                return "cardinality != 2";
1952            }
1953            if (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP)) {
1954                return "not WPA_EAP";
1955            }
1956            if ((!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X))
1957                    && (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK))) {
1958                return "not PSK or 8021X";
1959            }
1960        }
1961
1962        if (!TextUtils.isEmpty(config.FQDN)) {
1963            /* this is passpoint configuration; it must not have an SSID */
1964            if (!TextUtils.isEmpty(config.SSID)) {
1965                return "SSID not expected for Passpoint: '" + config.SSID +
1966                        "' FQDN " + toHexString(config.FQDN);
1967            }
1968            /* this is passpoint configuration; it must have a providerFriendlyName */
1969            if (TextUtils.isEmpty(config.providerFriendlyName)) {
1970                return "no provider friendly name";
1971            }
1972            WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
1973            /* this is passpoint configuration; it must have enterprise config */
1974            if (enterpriseConfig == null
1975                    || enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.NONE ) {
1976                return "no enterprise config";
1977            }
1978            if ((enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS ||
1979                    enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TTLS ||
1980                    enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.PEAP) &&
1981                    enterpriseConfig.getCaCertificate() == null) {
1982                return "no CA certificate";
1983            }
1984        }
1985
1986        // TODO: Add more checks
1987        return null;
1988    }
1989
1990    public Network getCurrentNetwork() {
1991        enforceAccessPermission();
1992        return mWifiStateMachine.getCurrentNetwork();
1993    }
1994
1995    public static String toHexString(String s) {
1996        if (s == null) {
1997            return "null";
1998        }
1999        StringBuilder sb = new StringBuilder();
2000        sb.append('\'').append(s).append('\'');
2001        for (int n = 0; n < s.length(); n++) {
2002            sb.append(String.format(" %02x", s.charAt(n) & 0xffff));
2003        }
2004        return sb.toString();
2005    }
2006
2007    /**
2008     * Checks that calling process has android.Manifest.permission.ACCESS_COARSE_LOCATION or
2009     * android.Manifest.permission.ACCESS_FINE_LOCATION and a corresponding app op is allowed
2010     */
2011    private boolean checkCallerHasLocationPermission(String callingPackage, int uid) {
2012        if (mContext.checkCallingOrSelfPermission(
2013                Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
2014                && isAppOppAllowed(AppOpsManager.OP_FINE_LOCATION, callingPackage, uid)) {
2015            return true;
2016        }
2017
2018        return mContext.checkCallingOrSelfPermission(
2019                Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
2020                && isAppOppAllowed(AppOpsManager.OP_COARSE_LOCATION, callingPackage, uid);
2021    }
2022
2023    private boolean isAppOppAllowed(int op, String callingPackage, int uid) {
2024        return mAppOps.noteOp(op, uid, callingPackage) == AppOpsManager.MODE_ALLOWED;
2025    }
2026
2027}
2028