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