WifiServiceImpl.java revision 65ada07fcc88600d1a8c77269f62590f630f7aab
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(callingPackage)) {
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(String callingPackage) {
1012        boolean legacyForegroundApp = !isMApp(mContext, callingPackage)
1013                && isForegroundApp(callingPackage);
1014        return legacyForegroundApp || Settings.Secure.getInt(mContext.getContentResolver(),
1015                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF)
1016                != Settings.Secure.LOCATION_MODE_OFF;
1017    }
1018
1019    /**
1020     * Returns true if the caller holds INTERACT_ACROSS_USERS_FULL.
1021     */
1022    private boolean checkInteractAcrossUsersFull() {
1023        return mContext.checkCallingOrSelfPermission(
1024                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1025                == PackageManager.PERMISSION_GRANTED;
1026    }
1027
1028    /**
1029     * Returns true if the caller holds PEERS_MAC_ADDRESS.
1030     */
1031    private boolean checkPeersMacAddress() {
1032        return mContext.checkCallingOrSelfPermission(
1033                android.Manifest.permission.PEERS_MAC_ADDRESS) == PackageManager.PERMISSION_GRANTED;
1034    }
1035
1036    /**
1037     * Returns true if the calling user is the current one or a profile of the
1038     * current user..
1039     */
1040    private boolean isCurrentProfile(int userId) {
1041        int currentUser = ActivityManager.getCurrentUser();
1042        if (userId == currentUser) {
1043            return true;
1044        }
1045        List<UserInfo> profiles = mUserManager.getProfiles(currentUser);
1046        for (UserInfo user : profiles) {
1047            if (userId == user.id) {
1048                return true;
1049            }
1050        }
1051        return false;
1052    }
1053
1054    /**
1055     * Returns true if uid is an application running under the owner or a profile of the owner.
1056     *
1057     * Note: Should not be called if identity is cleared.
1058     */
1059    private boolean isOwner(int uid) {
1060        long ident = Binder.clearCallingIdentity();
1061        int userId = UserHandle.getUserId(uid);
1062        try {
1063            int ownerUser = UserHandle.USER_OWNER;
1064            if (userId == ownerUser) {
1065                return true;
1066            }
1067            List<UserInfo> profiles = mUserManager.getProfiles(ownerUser);
1068            for (UserInfo profile : profiles) {
1069                if (userId == profile.id) {
1070                    return true;
1071                }
1072            }
1073            return false;
1074        }
1075        finally {
1076            Binder.restoreCallingIdentity(ident);
1077        }
1078    }
1079
1080
1081    /**
1082     * Tell the supplicant to persist the current list of configured networks.
1083     * @return {@code true} if the operation succeeded
1084     *
1085     * TODO: deprecate this
1086     */
1087    public boolean saveConfiguration() {
1088        boolean result = true;
1089        enforceChangePermission();
1090        if (mWifiStateMachineChannel != null) {
1091            return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
1092        } else {
1093            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1094            return false;
1095        }
1096    }
1097
1098    /**
1099     * Set the country code
1100     * @param countryCode ISO 3166 country code.
1101     * @param persist {@code true} if the setting should be remembered.
1102     *
1103     * The persist behavior exists so that wifi can fall back to the last
1104     * persisted country code on a restart, when the locale information is
1105     * not available from telephony.
1106     */
1107    public void setCountryCode(String countryCode, boolean persist) {
1108        Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
1109                " with persist set to " + persist);
1110        enforceConnectivityInternalPermission();
1111        final long token = Binder.clearCallingIdentity();
1112        try {
1113            mWifiStateMachine.setCountryCode(countryCode, persist);
1114        } finally {
1115            Binder.restoreCallingIdentity(token);
1116        }
1117    }
1118
1119     /**
1120     * Get the country code
1121     * @return ISO 3166 country code.
1122     */
1123    public String getCountryCode() {
1124        enforceConnectivityInternalPermission();
1125        String country = mWifiStateMachine.getCurrentCountryCode();
1126        return country;
1127    }
1128    /**
1129     * Set the operational frequency band
1130     * @param band One of
1131     *     {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
1132     *     {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
1133     *     {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
1134     * @param persist {@code true} if the setting should be remembered.
1135     *
1136     */
1137    public void setFrequencyBand(int band, boolean persist) {
1138        enforceChangePermission();
1139        if (!isDualBandSupported()) return;
1140        Slog.i(TAG, "WifiService trying to set frequency band to " + band +
1141                " with persist set to " + persist);
1142        final long token = Binder.clearCallingIdentity();
1143        try {
1144            mWifiStateMachine.setFrequencyBand(band, persist);
1145        } finally {
1146            Binder.restoreCallingIdentity(token);
1147        }
1148    }
1149
1150
1151    /**
1152     * Get the operational frequency band
1153     */
1154    public int getFrequencyBand() {
1155        enforceAccessPermission();
1156        return mWifiStateMachine.getFrequencyBand();
1157    }
1158
1159    public boolean isDualBandSupported() {
1160        //TODO: Should move towards adding a driver API that checks at runtime
1161        return mContext.getResources().getBoolean(
1162                com.android.internal.R.bool.config_wifi_dual_band_support);
1163    }
1164
1165    /**
1166     * Return the DHCP-assigned addresses from the last successful DHCP request,
1167     * if any.
1168     * @return the DHCP information
1169     * @deprecated
1170     */
1171    public DhcpInfo getDhcpInfo() {
1172        enforceAccessPermission();
1173        DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults();
1174
1175        DhcpInfo info = new DhcpInfo();
1176
1177        if (dhcpResults.ipAddress != null &&
1178                dhcpResults.ipAddress.getAddress() instanceof Inet4Address) {
1179            info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.ipAddress.getAddress());
1180        }
1181
1182        if (dhcpResults.gateway != null) {
1183            info.gateway = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.gateway);
1184        }
1185
1186        int dnsFound = 0;
1187        for (InetAddress dns : dhcpResults.dnsServers) {
1188            if (dns instanceof Inet4Address) {
1189                if (dnsFound == 0) {
1190                    info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1191                } else {
1192                    info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1193                }
1194                if (++dnsFound > 1) break;
1195            }
1196        }
1197        InetAddress serverAddress = dhcpResults.serverAddress;
1198        if (serverAddress instanceof Inet4Address) {
1199            info.serverAddress = NetworkUtils.inetAddressToInt((Inet4Address)serverAddress);
1200        }
1201        info.leaseDuration = dhcpResults.leaseDuration;
1202
1203        return info;
1204    }
1205
1206    /**
1207     * see {@link android.net.wifi.WifiManager#startWifi}
1208     *
1209     */
1210    public void startWifi() {
1211        enforceConnectivityInternalPermission();
1212        /* TODO: may be add permissions for access only to connectivity service
1213         * TODO: if a start issued, keep wifi alive until a stop issued irrespective
1214         * of WifiLock & device idle status unless wifi enabled status is toggled
1215         */
1216
1217        mWifiStateMachine.setDriverStart(true);
1218        mWifiStateMachine.reconnectCommand();
1219    }
1220
1221    /**
1222     * see {@link android.net.wifi.WifiManager#stopWifi}
1223     *
1224     */
1225    public void stopWifi() {
1226        enforceConnectivityInternalPermission();
1227        /*
1228         * TODO: if a stop is issued, wifi is brought up only by startWifi
1229         * unless wifi enabled status is toggled
1230         */
1231        mWifiStateMachine.setDriverStart(false);
1232    }
1233
1234    /**
1235     * see {@link android.net.wifi.WifiManager#addToBlacklist}
1236     *
1237     */
1238    public void addToBlacklist(String bssid) {
1239        enforceChangePermission();
1240
1241        mWifiStateMachine.addToBlacklist(bssid);
1242    }
1243
1244    /**
1245     * see {@link android.net.wifi.WifiManager#clearBlacklist}
1246     *
1247     */
1248    public void clearBlacklist() {
1249        enforceChangePermission();
1250
1251        mWifiStateMachine.clearBlacklist();
1252    }
1253
1254    /**
1255     * enable TDLS for the local NIC to remote NIC
1256     * The APPs don't know the remote MAC address to identify NIC though,
1257     * so we need to do additional work to find it from remote IP address
1258     */
1259
1260    class TdlsTaskParams {
1261        public String remoteIpAddress;
1262        public boolean enable;
1263    }
1264
1265    class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> {
1266        @Override
1267        protected Integer doInBackground(TdlsTaskParams... params) {
1268
1269            // Retrieve parameters for the call
1270            TdlsTaskParams param = params[0];
1271            String remoteIpAddress = param.remoteIpAddress.trim();
1272            boolean enable = param.enable;
1273
1274            // Get MAC address of Remote IP
1275            String macAddress = null;
1276
1277            BufferedReader reader = null;
1278
1279            try {
1280                reader = new BufferedReader(new FileReader("/proc/net/arp"));
1281
1282                // Skip over the line bearing colum titles
1283                String line = reader.readLine();
1284
1285                while ((line = reader.readLine()) != null) {
1286                    String[] tokens = line.split("[ ]+");
1287                    if (tokens.length < 6) {
1288                        continue;
1289                    }
1290
1291                    // ARP column format is
1292                    // Address HWType HWAddress Flags Mask IFace
1293                    String ip = tokens[0];
1294                    String mac = tokens[3];
1295
1296                    if (remoteIpAddress.equals(ip)) {
1297                        macAddress = mac;
1298                        break;
1299                    }
1300                }
1301
1302                if (macAddress == null) {
1303                    Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " +
1304                            "/proc/net/arp");
1305                } else {
1306                    enableTdlsWithMacAddress(macAddress, enable);
1307                }
1308
1309            } catch (FileNotFoundException e) {
1310                Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address");
1311            } catch (IOException e) {
1312                Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address");
1313            } finally {
1314                try {
1315                    if (reader != null) {
1316                        reader.close();
1317                    }
1318                }
1319                catch (IOException e) {
1320                    // Do nothing
1321                }
1322            }
1323
1324            return 0;
1325        }
1326    }
1327
1328    public void enableTdls(String remoteAddress, boolean enable) {
1329        if (remoteAddress == null) {
1330          throw new IllegalArgumentException("remoteAddress cannot be null");
1331        }
1332
1333        TdlsTaskParams params = new TdlsTaskParams();
1334        params.remoteIpAddress = remoteAddress;
1335        params.enable = enable;
1336        new TdlsTask().execute(params);
1337    }
1338
1339
1340    public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
1341        if (remoteMacAddress == null) {
1342          throw new IllegalArgumentException("remoteMacAddress cannot be null");
1343        }
1344
1345        mWifiStateMachine.enableTdls(remoteMacAddress, enable);
1346    }
1347
1348    /**
1349     * Get a reference to handler. This is used by a client to establish
1350     * an AsyncChannel communication with WifiService
1351     */
1352    public Messenger getWifiServiceMessenger() {
1353        enforceAccessPermission();
1354        enforceChangePermission();
1355        return new Messenger(mClientHandler);
1356    }
1357
1358    /**
1359     * Disable an ephemeral network, i.e. network that is created thru a WiFi Scorer
1360     */
1361    public void disableEphemeralNetwork(String SSID) {
1362        enforceAccessPermission();
1363        enforceChangePermission();
1364        mWifiStateMachine.disableEphemeralNetwork(SSID);
1365    }
1366
1367    /**
1368     * Get the IP and proxy configuration file
1369     */
1370    public String getConfigFile() {
1371        enforceAccessPermission();
1372        return mWifiStateMachine.getConfigFile();
1373    }
1374
1375    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1376        @Override
1377        public void onReceive(Context context, Intent intent) {
1378            String action = intent.getAction();
1379            if (action.equals(Intent.ACTION_SCREEN_ON)) {
1380                mWifiController.sendMessage(CMD_SCREEN_ON);
1381            } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1382                mWifiController.sendMessage(CMD_USER_PRESENT);
1383            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1384                mWifiController.sendMessage(CMD_SCREEN_OFF);
1385            } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
1386                int pluggedType = intent.getIntExtra("plugged", 0);
1387                mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null);
1388            } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
1389                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
1390                        BluetoothAdapter.STATE_DISCONNECTED);
1391                mWifiStateMachine.sendBluetoothAdapterStateChange(state);
1392            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
1393                boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false);
1394                mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0);
1395            } else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
1396                handleIdleModeChanged();
1397            }
1398        }
1399    };
1400
1401    /**
1402     * Observes settings changes to scan always mode.
1403     */
1404    private void registerForScanModeChange() {
1405        ContentObserver contentObserver = new ContentObserver(null) {
1406            @Override
1407            public void onChange(boolean selfChange) {
1408                mSettingsStore.handleWifiScanAlwaysAvailableToggled();
1409                mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED);
1410            }
1411        };
1412
1413        mContext.getContentResolver().registerContentObserver(
1414                Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE),
1415                false, contentObserver);
1416    }
1417
1418    private void registerForBroadcasts() {
1419        IntentFilter intentFilter = new IntentFilter();
1420        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
1421        intentFilter.addAction(Intent.ACTION_USER_PRESENT);
1422        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
1423        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
1424        intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
1425        intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
1426        intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
1427        intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
1428        mContext.registerReceiver(mReceiver, intentFilter);
1429    }
1430
1431    private void registerForPackageOrUserRemoval() {
1432        IntentFilter intentFilter = new IntentFilter();
1433        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1434        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
1435        mContext.registerReceiverAsUser(new BroadcastReceiver() {
1436            @Override
1437            public void onReceive(Context context, Intent intent) {
1438                switch (intent.getAction()) {
1439                    case Intent.ACTION_PACKAGE_REMOVED: {
1440                        if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1441                            return;
1442                        }
1443                        int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
1444                        Uri uri = intent.getData();
1445                        if (uid == -1 || uri == null) {
1446                            return;
1447                        }
1448                        String pkgName = uri.getSchemeSpecificPart();
1449                        mWifiStateMachine.removeAppConfigs(pkgName, uid);
1450                        break;
1451                    }
1452                    case Intent.ACTION_USER_REMOVED: {
1453                        int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
1454                        mWifiStateMachine.removeUserConfigs(userHandle);
1455                        break;
1456                    }
1457                }
1458            }
1459        }, UserHandle.ALL, intentFilter, null, null);
1460    }
1461
1462    @Override
1463    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1464        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1465                != PackageManager.PERMISSION_GRANTED) {
1466            pw.println("Permission Denial: can't dump WifiService from from pid="
1467                    + Binder.getCallingPid()
1468                    + ", uid=" + Binder.getCallingUid());
1469            return;
1470        }
1471        pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
1472        pw.println("Stay-awake conditions: " +
1473                Settings.Global.getInt(mContext.getContentResolver(),
1474                                       Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
1475        pw.println("mMulticastEnabled " + mMulticastEnabled);
1476        pw.println("mMulticastDisabled " + mMulticastDisabled);
1477        pw.println("mInIdleMode " + mInIdleMode);
1478        pw.println("mScanPending " + mScanPending);
1479        mWifiController.dump(fd, pw, args);
1480        mSettingsStore.dump(fd, pw, args);
1481        mNotificationController.dump(fd, pw, args);
1482        mTrafficPoller.dump(fd, pw, args);
1483
1484        pw.println("Latest scan results:");
1485        List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
1486        long nowMs = System.currentTimeMillis();
1487        if (scanResults != null && scanResults.size() != 0) {
1488            pw.println("    BSSID              Frequency  RSSI    Age      SSID " +
1489                    "                                Flags");
1490            for (ScanResult r : scanResults) {
1491                long ageSec = 0;
1492                long ageMilli = 0;
1493                if (nowMs > r.seen && r.seen > 0) {
1494                    ageSec = (nowMs - r.seen) / 1000;
1495                    ageMilli = (nowMs - r.seen) % 1000;
1496                }
1497                String candidate = " ";
1498                if (r.isAutoJoinCandidate > 0) candidate = "+";
1499                pw.printf("  %17s  %9d  %5d  %3d.%03d%s   %-32s  %s\n",
1500                                         r.BSSID,
1501                                         r.frequency,
1502                                         r.level,
1503                                         ageSec, ageMilli,
1504                                         candidate,
1505                                         r.SSID == null ? "" : r.SSID,
1506                                         r.capabilities);
1507            }
1508        }
1509        pw.println();
1510        pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
1511                mFullHighPerfLocksAcquired + " full high perf, " +
1512                mScanLocksAcquired + " scan");
1513        pw.println("Locks released: " + mFullLocksReleased + " full, " +
1514                mFullHighPerfLocksReleased + " full high perf, " +
1515                mScanLocksReleased + " scan");
1516        pw.println();
1517        pw.println("Locks held:");
1518        mLocks.dump(pw);
1519
1520        pw.println("Multicast Locks held:");
1521        for (Multicaster l : mMulticasters) {
1522            pw.print("    ");
1523            pw.println(l);
1524        }
1525
1526        mWifiWatchdogStateMachine.dump(fd, pw, args);
1527        pw.println();
1528        mWifiStateMachine.dump(fd, pw, args);
1529        pw.println();
1530    }
1531
1532    private class WifiLock extends DeathRecipient {
1533        WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
1534            super(lockMode, tag, binder, ws);
1535        }
1536
1537        public void binderDied() {
1538            synchronized (mLocks) {
1539                releaseWifiLockLocked(mBinder);
1540            }
1541        }
1542
1543        public String toString() {
1544            return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
1545        }
1546    }
1547
1548    class LockList {
1549        private List<WifiLock> mList;
1550
1551        private LockList() {
1552            mList = new ArrayList<WifiLock>();
1553        }
1554
1555        synchronized boolean hasLocks() {
1556            return !mList.isEmpty();
1557        }
1558
1559        synchronized int getStrongestLockMode() {
1560            if (mList.isEmpty()) {
1561                return WifiManager.WIFI_MODE_FULL;
1562            }
1563
1564            if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
1565                return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
1566            }
1567
1568            if (mFullLocksAcquired > mFullLocksReleased) {
1569                return WifiManager.WIFI_MODE_FULL;
1570            }
1571
1572            return WifiManager.WIFI_MODE_SCAN_ONLY;
1573        }
1574
1575        synchronized void updateWorkSource(WorkSource ws) {
1576            for (int i = 0; i < mLocks.mList.size(); i++) {
1577                ws.add(mLocks.mList.get(i).mWorkSource);
1578            }
1579        }
1580
1581        private void addLock(WifiLock lock) {
1582            if (findLockByBinder(lock.mBinder) < 0) {
1583                mList.add(lock);
1584            }
1585        }
1586
1587        private WifiLock removeLock(IBinder binder) {
1588            int index = findLockByBinder(binder);
1589            if (index >= 0) {
1590                WifiLock ret = mList.remove(index);
1591                ret.unlinkDeathRecipient();
1592                return ret;
1593            } else {
1594                return null;
1595            }
1596        }
1597
1598        private int findLockByBinder(IBinder binder) {
1599            int size = mList.size();
1600            for (int i = size - 1; i >= 0; i--) {
1601                if (mList.get(i).mBinder == binder)
1602                    return i;
1603            }
1604            return -1;
1605        }
1606
1607        private void dump(PrintWriter pw) {
1608            for (WifiLock l : mList) {
1609                pw.print("    ");
1610                pw.println(l);
1611            }
1612        }
1613    }
1614
1615    void enforceWakeSourcePermission(int uid, int pid) {
1616        if (uid == android.os.Process.myUid()) {
1617            return;
1618        }
1619        mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
1620                pid, uid, null);
1621    }
1622
1623    public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
1624        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1625        if (lockMode != WifiManager.WIFI_MODE_FULL &&
1626                lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
1627                lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
1628            Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
1629            if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
1630            return false;
1631        }
1632        if (ws != null && ws.size() == 0) {
1633            ws = null;
1634        }
1635        if (ws != null) {
1636            enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
1637        }
1638        if (ws == null) {
1639            ws = new WorkSource(Binder.getCallingUid());
1640        }
1641        WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
1642        synchronized (mLocks) {
1643            return acquireWifiLockLocked(wifiLock);
1644        }
1645    }
1646
1647    private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
1648        switch(wifiLock.mMode) {
1649            case WifiManager.WIFI_MODE_FULL:
1650            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1651            case WifiManager.WIFI_MODE_SCAN_ONLY:
1652                mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
1653                break;
1654        }
1655    }
1656
1657    private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
1658        switch(wifiLock.mMode) {
1659            case WifiManager.WIFI_MODE_FULL:
1660            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1661            case WifiManager.WIFI_MODE_SCAN_ONLY:
1662                mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
1663                break;
1664        }
1665    }
1666
1667    private boolean acquireWifiLockLocked(WifiLock wifiLock) {
1668        if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
1669
1670        mLocks.addLock(wifiLock);
1671
1672        long ident = Binder.clearCallingIdentity();
1673        try {
1674            noteAcquireWifiLock(wifiLock);
1675            switch(wifiLock.mMode) {
1676            case WifiManager.WIFI_MODE_FULL:
1677                ++mFullLocksAcquired;
1678                break;
1679            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1680                ++mFullHighPerfLocksAcquired;
1681                break;
1682
1683            case WifiManager.WIFI_MODE_SCAN_ONLY:
1684                ++mScanLocksAcquired;
1685                break;
1686            }
1687            mWifiController.sendMessage(CMD_LOCKS_CHANGED);
1688            return true;
1689        } catch (RemoteException e) {
1690            return false;
1691        } finally {
1692            Binder.restoreCallingIdentity(ident);
1693        }
1694    }
1695
1696    public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
1697        int uid = Binder.getCallingUid();
1698        int pid = Binder.getCallingPid();
1699        if (ws != null && ws.size() == 0) {
1700            ws = null;
1701        }
1702        if (ws != null) {
1703            enforceWakeSourcePermission(uid, pid);
1704        }
1705        long ident = Binder.clearCallingIdentity();
1706        try {
1707            synchronized (mLocks) {
1708                int index = mLocks.findLockByBinder(lock);
1709                if (index < 0) {
1710                    throw new IllegalArgumentException("Wifi lock not active");
1711                }
1712                WifiLock wl = mLocks.mList.get(index);
1713                noteReleaseWifiLock(wl);
1714                wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
1715                noteAcquireWifiLock(wl);
1716            }
1717        } catch (RemoteException e) {
1718        } finally {
1719            Binder.restoreCallingIdentity(ident);
1720        }
1721    }
1722
1723    public boolean releaseWifiLock(IBinder lock) {
1724        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1725        synchronized (mLocks) {
1726            return releaseWifiLockLocked(lock);
1727        }
1728    }
1729
1730    private boolean releaseWifiLockLocked(IBinder lock) {
1731        boolean hadLock;
1732
1733        WifiLock wifiLock = mLocks.removeLock(lock);
1734
1735        if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
1736
1737        hadLock = (wifiLock != null);
1738
1739        long ident = Binder.clearCallingIdentity();
1740        try {
1741            if (hadLock) {
1742                noteReleaseWifiLock(wifiLock);
1743                switch(wifiLock.mMode) {
1744                    case WifiManager.WIFI_MODE_FULL:
1745                        ++mFullLocksReleased;
1746                        break;
1747                    case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1748                        ++mFullHighPerfLocksReleased;
1749                        break;
1750                    case WifiManager.WIFI_MODE_SCAN_ONLY:
1751                        ++mScanLocksReleased;
1752                        break;
1753                }
1754                mWifiController.sendMessage(CMD_LOCKS_CHANGED);
1755            }
1756        } catch (RemoteException e) {
1757        } finally {
1758            Binder.restoreCallingIdentity(ident);
1759        }
1760
1761        return hadLock;
1762    }
1763
1764    private abstract class DeathRecipient
1765            implements IBinder.DeathRecipient {
1766        String mTag;
1767        int mMode;
1768        IBinder mBinder;
1769        WorkSource mWorkSource;
1770
1771        DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) {
1772            super();
1773            mTag = tag;
1774            mMode = mode;
1775            mBinder = binder;
1776            mWorkSource = ws;
1777            try {
1778                mBinder.linkToDeath(this, 0);
1779            } catch (RemoteException e) {
1780                binderDied();
1781            }
1782        }
1783
1784        void unlinkDeathRecipient() {
1785            mBinder.unlinkToDeath(this, 0);
1786        }
1787    }
1788
1789    private class Multicaster extends DeathRecipient {
1790        Multicaster(String tag, IBinder binder) {
1791            super(Binder.getCallingUid(), tag, binder, null);
1792        }
1793
1794        public void binderDied() {
1795            Slog.e(TAG, "Multicaster binderDied");
1796            synchronized (mMulticasters) {
1797                int i = mMulticasters.indexOf(this);
1798                if (i != -1) {
1799                    removeMulticasterLocked(i, mMode);
1800                }
1801            }
1802        }
1803
1804        public String toString() {
1805            return "Multicaster{" + mTag + " binder=" + mBinder + "}";
1806        }
1807
1808        public int getUid() {
1809            return mMode;
1810        }
1811    }
1812
1813    public void initializeMulticastFiltering() {
1814        enforceMulticastChangePermission();
1815
1816        synchronized (mMulticasters) {
1817            // if anybody had requested filters be off, leave off
1818            if (mMulticasters.size() != 0) {
1819                return;
1820            } else {
1821                mWifiStateMachine.startFilteringMulticastV4Packets();
1822            }
1823        }
1824    }
1825
1826    public void acquireMulticastLock(IBinder binder, String tag) {
1827        enforceMulticastChangePermission();
1828
1829        synchronized (mMulticasters) {
1830            mMulticastEnabled++;
1831            mMulticasters.add(new Multicaster(tag, binder));
1832            // Note that we could call stopFilteringMulticastV4Packets only when
1833            // our new size == 1 (first call), but this function won't
1834            // be called often and by making the stopPacket call each
1835            // time we're less fragile and self-healing.
1836            mWifiStateMachine.stopFilteringMulticastV4Packets();
1837        }
1838
1839        int uid = Binder.getCallingUid();
1840        final long ident = Binder.clearCallingIdentity();
1841        try {
1842            mBatteryStats.noteWifiMulticastEnabled(uid);
1843        } catch (RemoteException e) {
1844        } finally {
1845            Binder.restoreCallingIdentity(ident);
1846        }
1847    }
1848
1849    public void releaseMulticastLock() {
1850        enforceMulticastChangePermission();
1851
1852        int uid = Binder.getCallingUid();
1853        synchronized (mMulticasters) {
1854            mMulticastDisabled++;
1855            int size = mMulticasters.size();
1856            for (int i = size - 1; i >= 0; i--) {
1857                Multicaster m = mMulticasters.get(i);
1858                if ((m != null) && (m.getUid() == uid)) {
1859                    removeMulticasterLocked(i, uid);
1860                }
1861            }
1862        }
1863    }
1864
1865    private void removeMulticasterLocked(int i, int uid)
1866    {
1867        Multicaster removed = mMulticasters.remove(i);
1868
1869        if (removed != null) {
1870            removed.unlinkDeathRecipient();
1871        }
1872        if (mMulticasters.size() == 0) {
1873            mWifiStateMachine.startFilteringMulticastV4Packets();
1874        }
1875
1876        final long ident = Binder.clearCallingIdentity();
1877        try {
1878            mBatteryStats.noteWifiMulticastDisabled(uid);
1879        } catch (RemoteException e) {
1880        } finally {
1881            Binder.restoreCallingIdentity(ident);
1882        }
1883    }
1884
1885    public boolean isMulticastEnabled() {
1886        enforceAccessPermission();
1887
1888        synchronized (mMulticasters) {
1889            return (mMulticasters.size() > 0);
1890        }
1891    }
1892
1893    public WifiMonitor getWifiMonitor() {
1894        return mWifiStateMachine.getWifiMonitor();
1895    }
1896
1897    public void enableVerboseLogging(int verbose) {
1898        enforceAccessPermission();
1899        mWifiStateMachine.enableVerboseLogging(verbose);
1900    }
1901
1902    public int getVerboseLoggingLevel() {
1903        enforceAccessPermission();
1904        return mWifiStateMachine.getVerboseLoggingLevel();
1905    }
1906
1907    public void enableAggressiveHandover(int enabled) {
1908        enforceAccessPermission();
1909        mWifiStateMachine.enableAggressiveHandover(enabled);
1910    }
1911
1912    public int getAggressiveHandover() {
1913        enforceAccessPermission();
1914        return mWifiStateMachine.getAggressiveHandover();
1915    }
1916
1917    public void setAllowScansWithTraffic(int enabled) {
1918        enforceAccessPermission();
1919        mWifiStateMachine.setAllowScansWithTraffic(enabled);
1920    }
1921
1922    public int getAllowScansWithTraffic() {
1923        enforceAccessPermission();
1924        return mWifiStateMachine.getAllowScansWithTraffic();
1925    }
1926
1927    public boolean enableAutoJoinWhenAssociated(boolean enabled) {
1928        enforceChangePermission();
1929        return mWifiStateMachine.enableAutoJoinWhenAssociated(enabled);
1930    }
1931
1932    public boolean getEnableAutoJoinWhenAssociated() {
1933        enforceAccessPermission();
1934        return mWifiStateMachine.getEnableAutoJoinWhenAssociated();
1935    }
1936    public void setHalBasedAutojoinOffload(int enabled) {
1937        enforceChangePermission();
1938        mWifiStateMachine.setHalBasedAutojoinOffload(enabled);
1939    }
1940
1941    public int getHalBasedAutojoinOffload() {
1942        enforceAccessPermission();
1943        return mWifiStateMachine.getHalBasedAutojoinOffload();
1944    }
1945
1946    /* Return the Wifi Connection statistics object */
1947    public WifiConnectionStatistics getConnectionStatistics() {
1948        enforceAccessPermission();
1949        enforceReadCredentialPermission();
1950        if (mWifiStateMachineChannel != null) {
1951            return mWifiStateMachine.syncGetConnectionStatistics(mWifiStateMachineChannel);
1952        } else {
1953            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1954            return null;
1955        }
1956    }
1957
1958    public void factoryReset() {
1959        enforceConnectivityInternalPermission();
1960
1961        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
1962            return;
1963        }
1964
1965        if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
1966            // Turn mobile hotspot off
1967            setWifiApEnabled(null, false);
1968        }
1969
1970        if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI)) {
1971            // Enable wifi
1972            setWifiEnabled(true);
1973            // Delete all Wifi SSIDs
1974            List<WifiConfiguration> networks = getConfiguredNetworks();
1975            if (networks != null) {
1976                for (WifiConfiguration config : networks) {
1977                    removeNetwork(config.networkId);
1978                }
1979                saveConfiguration();
1980            }
1981        }
1982    }
1983
1984    /* private methods */
1985    static boolean logAndReturnFalse(String s) {
1986        Log.d(TAG, s);
1987        return false;
1988    }
1989
1990    public static boolean isValid(WifiConfiguration config) {
1991        String validity = checkValidity(config);
1992        return validity == null || logAndReturnFalse(validity);
1993    }
1994
1995    public static boolean isValidPasspoint(WifiConfiguration config) {
1996        String validity = checkPasspointValidity(config);
1997        return validity == null || logAndReturnFalse(validity);
1998    }
1999
2000    public static String checkValidity(WifiConfiguration config) {
2001        if (config.allowedKeyManagement == null)
2002            return "allowed kmgmt";
2003
2004        if (config.allowedKeyManagement.cardinality() > 1) {
2005            if (config.allowedKeyManagement.cardinality() != 2) {
2006                return "cardinality != 2";
2007            }
2008            if (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP)) {
2009                return "not WPA_EAP";
2010            }
2011            if ((!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X))
2012                    && (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK))) {
2013                return "not PSK or 8021X";
2014            }
2015        }
2016        return null;
2017    }
2018
2019    public static String checkPasspointValidity(WifiConfiguration config) {
2020        if (!TextUtils.isEmpty(config.FQDN)) {
2021            /* this is passpoint configuration; it must not have an SSID */
2022            if (!TextUtils.isEmpty(config.SSID)) {
2023                return "SSID not expected for Passpoint: '" + config.SSID +
2024                        "' FQDN " + toHexString(config.FQDN);
2025            }
2026            /* this is passpoint configuration; it must have a providerFriendlyName */
2027            if (TextUtils.isEmpty(config.providerFriendlyName)) {
2028                return "no provider friendly name";
2029            }
2030            WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
2031            /* this is passpoint configuration; it must have enterprise config */
2032            if (enterpriseConfig == null
2033                    || enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.NONE ) {
2034                return "no enterprise config";
2035            }
2036            if ((enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS ||
2037                    enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TTLS ||
2038                    enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.PEAP) &&
2039                    enterpriseConfig.getCaCertificate() == null) {
2040                return "no CA certificate";
2041            }
2042        }
2043        return null;
2044    }
2045
2046    public Network getCurrentNetwork() {
2047        enforceAccessPermission();
2048        return mWifiStateMachine.getCurrentNetwork();
2049    }
2050
2051    public static String toHexString(String s) {
2052        if (s == null) {
2053            return "null";
2054        }
2055        StringBuilder sb = new StringBuilder();
2056        sb.append('\'').append(s).append('\'');
2057        for (int n = 0; n < s.length(); n++) {
2058            sb.append(String.format(" %02x", s.charAt(n) & 0xffff));
2059        }
2060        return sb.toString();
2061    }
2062
2063    /**
2064     * Checks that calling process has android.Manifest.permission.ACCESS_COARSE_LOCATION or
2065     * android.Manifest.permission.ACCESS_FINE_LOCATION and a corresponding app op is allowed
2066     */
2067    private boolean checkCallerCanAccessScanResults(String callingPackage, int uid) {
2068        if (ActivityManager.checkUidPermission(Manifest.permission.ACCESS_FINE_LOCATION, uid)
2069                == PackageManager.PERMISSION_GRANTED
2070                && checkAppOppAllowed(AppOpsManager.OP_FINE_LOCATION, callingPackage, uid)) {
2071            return true;
2072        }
2073
2074        if (ActivityManager.checkUidPermission(Manifest.permission.ACCESS_COARSE_LOCATION, uid)
2075                == PackageManager.PERMISSION_GRANTED
2076                && checkAppOppAllowed(AppOpsManager.OP_COARSE_LOCATION, callingPackage, uid)) {
2077            return true;
2078        }
2079        boolean apiLevel23App = isMApp(mContext, callingPackage);
2080        // Pre-M apps running in the foreground should continue getting scan results
2081        if (!apiLevel23App && isForegroundApp(callingPackage)) {
2082            return true;
2083        }
2084        Log.e(TAG, "Permission denial: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION "
2085                + "permission to get scan results");
2086        return false;
2087    }
2088
2089    private boolean checkAppOppAllowed(int op, String callingPackage, int uid) {
2090        return mAppOps.noteOp(op, uid, callingPackage) == AppOpsManager.MODE_ALLOWED;
2091    }
2092
2093    private static boolean isMApp(Context context, String pkgName) {
2094        try {
2095            return context.getPackageManager().getApplicationInfo(pkgName, 0)
2096                    .targetSdkVersion >= Build.VERSION_CODES.M;
2097        } catch (PackageManager.NameNotFoundException e) {
2098            // In case of exception, assume M app (more strict checking)
2099        }
2100        return true;
2101    }
2102
2103    /**
2104     * Return true if the specified package name is a foreground app.
2105     *
2106     * @param pkgName application package name.
2107     */
2108    private boolean isForegroundApp(String pkgName) {
2109        ActivityManager am = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
2110        List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
2111        return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName());
2112    }
2113
2114}
2115