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