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