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