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