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