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