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