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