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