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