WifiServiceImpl.java revision 200e8ee5097134010a6edee8d031bb02ff7eeb5a
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(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.WifiAdapter#reportActivityInfo}
787     */
788    public WifiActivityEnergyInfo reportActivityInfo(WifiAdapter adapter) {
789        enforceAccessPermission();
790        WifiLinkLayerStats stats;
791        WifiActivityEnergyInfo energyInfo = null;
792        if (mWifiStateMachineChannel != null) {
793            stats = mWifiStateMachine.syncGetLinkLayerStats(mWifiStateMachineChannel, adapter);
794            if (stats != null) {
795                // Convert the LinkLayerStats into EnergyActivity
796                energyInfo = new WifiActivityEnergyInfo(
797                        WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE, stats.tx_time,
798                        stats.rx_time, stats.on_time - stats.tx_time - stats.rx_time,
799                        0 /* TBD */);
800            }
801            return energyInfo;
802        } else {
803            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
804            return null;
805        }
806    }
807
808    /**
809     * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
810     * @return the list of configured networks
811     */
812    public List<WifiConfiguration> getConfiguredNetworks() {
813        enforceAccessPermission();
814        if (mWifiStateMachineChannel != null) {
815            return mWifiStateMachine.syncGetConfiguredNetworks(mWifiStateMachineChannel);
816        } else {
817            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
818            return null;
819        }
820    }
821
822    /**
823     * see {@link android.net.wifi.WifiManager#getPrivilegedConfiguredNetworks()}
824     * @return the list of configured networks with real preSharedKey
825     */
826    public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
827        enforceReadCredentialPermission();
828        enforceAccessPermission();
829        if (mWifiStateMachineChannel != null) {
830            return mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel);
831        } else {
832            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
833            return null;
834        }
835    }
836
837    /**
838     * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
839     * @return the supplicant-assigned identifier for the new or updated
840     * network if the operation succeeds, or {@code -1} if it fails
841     */
842    public int addOrUpdateNetwork(WifiConfiguration config) {
843        enforceChangePermission();
844        if (config.isValid()) {
845            //TODO: pass the Uid the WifiStateMachine as a message parameter
846            Slog.e("addOrUpdateNetwork", " uid = " + Integer.toString(Binder.getCallingUid())
847                    + " SSID " + config.SSID
848                    + " nid=" + Integer.toString(config.networkId));
849            if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
850                config.creatorUid = Binder.getCallingUid();
851            } else {
852                config.lastUpdateUid = Binder.getCallingUid();
853            }
854            if (mWifiStateMachineChannel != null) {
855                return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
856            } else {
857                Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
858                return -1;
859            }
860        } else {
861            Slog.e(TAG, "bad network configuration");
862            return -1;
863        }
864    }
865
866     /**
867     * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
868     * @param netId the integer that identifies the network configuration
869     * to the supplicant
870     * @return {@code true} if the operation succeeded
871     */
872    public boolean removeNetwork(int netId) {
873        enforceChangePermission();
874
875        if (!isOwner(Binder.getCallingUid())) {
876            Slog.e(TAG, "Remove is not authorized for user");
877            return false;
878        }
879
880        if (mWifiStateMachineChannel != null) {
881            return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
882        } else {
883            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
884            return false;
885        }
886    }
887
888    /**
889     * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
890     * @param netId the integer that identifies the network configuration
891     * to the supplicant
892     * @param disableOthers if true, disable all other networks.
893     * @return {@code true} if the operation succeeded
894     */
895    public boolean enableNetwork(int netId, boolean disableOthers) {
896        enforceChangePermission();
897        if (mWifiStateMachineChannel != null) {
898            return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
899                    disableOthers);
900        } else {
901            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
902            return false;
903        }
904    }
905
906    /**
907     * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
908     * @param netId the integer that identifies the network configuration
909     * to the supplicant
910     * @return {@code true} if the operation succeeded
911     */
912    public boolean disableNetwork(int netId) {
913        enforceChangePermission();
914        if (mWifiStateMachineChannel != null) {
915            return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
916        } else {
917            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
918            return false;
919        }
920    }
921
922    /**
923     * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
924     * @return the Wi-Fi information, contained in {@link WifiInfo}.
925     */
926    public WifiInfo getConnectionInfo() {
927        enforceAccessPermission();
928        /*
929         * Make sure we have the latest information, by sending
930         * a status request to the supplicant.
931         */
932        return mWifiStateMachine.syncRequestConnectionInfo();
933    }
934
935    /**
936     * Return the results of the most recent access point scan, in the form of
937     * a list of {@link ScanResult} objects.
938     * @return the list of results
939     */
940    public List<ScanResult> getScanResults(String callingPackage) {
941        enforceAccessPermission();
942        int userId = UserHandle.getCallingUserId();
943        int uid = Binder.getCallingUid();
944        long ident = Binder.clearCallingIdentity();
945        try {
946            if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
947                    != AppOpsManager.MODE_ALLOWED) {
948                return new ArrayList<ScanResult>();
949            }
950            if (!isCurrentProfile(userId)) {
951                return new ArrayList<ScanResult>();
952            }
953            return mWifiStateMachine.syncGetScanResultsList();
954        } finally {
955            Binder.restoreCallingIdentity(ident);
956        }
957    }
958
959    /**
960     * Returns true if the calling user is the current one or a profile of the
961     * current user..
962     */
963    private boolean isCurrentProfile(int userId) {
964        int currentUser = ActivityManager.getCurrentUser();
965        if (userId == currentUser) {
966            return true;
967        }
968        List<UserInfo> profiles = UserManager.get(mContext).getProfiles(currentUser);
969        for (UserInfo user : profiles) {
970            if (userId == user.id) {
971                return true;
972            }
973        }
974        return false;
975    }
976
977    /**
978     * Returns true if uid is an application running under the owner or a profile of the owner.
979     *
980     * Note: Should not be called if identity is cleared.
981     */
982    private boolean isOwner(int uid) {
983        long ident = Binder.clearCallingIdentity();
984        int userId = UserHandle.getUserId(uid);
985        try {
986            int ownerUser = UserHandle.USER_OWNER;
987            if (userId == ownerUser) {
988                return true;
989            }
990            List<UserInfo> profiles = UserManager.get(mContext).getProfiles(ownerUser);
991            for (UserInfo profile : profiles) {
992                if (userId == profile.id) {
993                    return true;
994                }
995            }
996            return false;
997        }
998        finally {
999            Binder.restoreCallingIdentity(ident);
1000        }
1001    }
1002
1003
1004    /**
1005     * Tell the supplicant to persist the current list of configured networks.
1006     * @return {@code true} if the operation succeeded
1007     *
1008     * TODO: deprecate this
1009     */
1010    public boolean saveConfiguration() {
1011        boolean result = true;
1012        enforceChangePermission();
1013        if (mWifiStateMachineChannel != null) {
1014            return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
1015        } else {
1016            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1017            return false;
1018        }
1019    }
1020
1021    /**
1022     * Set the country code
1023     * @param countryCode ISO 3166 country code.
1024     * @param persist {@code true} if the setting should be remembered.
1025     *
1026     * The persist behavior exists so that wifi can fall back to the last
1027     * persisted country code on a restart, when the locale information is
1028     * not available from telephony.
1029     */
1030    public void setCountryCode(String countryCode, boolean persist) {
1031        Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
1032                " with persist set to " + persist);
1033        enforceConnectivityInternalPermission();
1034        final long token = Binder.clearCallingIdentity();
1035        try {
1036            mWifiStateMachine.setCountryCode(countryCode, persist);
1037        } finally {
1038            Binder.restoreCallingIdentity(token);
1039        }
1040    }
1041
1042    /**
1043     * Set the operational frequency band
1044     * @param band One of
1045     *     {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
1046     *     {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
1047     *     {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
1048     * @param persist {@code true} if the setting should be remembered.
1049     *
1050     */
1051    public void setFrequencyBand(int band, boolean persist) {
1052        enforceChangePermission();
1053        if (!isDualBandSupported()) return;
1054        Slog.i(TAG, "WifiService trying to set frequency band to " + band +
1055                " with persist set to " + persist);
1056        final long token = Binder.clearCallingIdentity();
1057        try {
1058            mWifiStateMachine.setFrequencyBand(band, persist);
1059        } finally {
1060            Binder.restoreCallingIdentity(token);
1061        }
1062    }
1063
1064
1065    /**
1066     * Get the operational frequency band
1067     */
1068    public int getFrequencyBand() {
1069        enforceAccessPermission();
1070        return mWifiStateMachine.getFrequencyBand();
1071    }
1072
1073    public boolean isDualBandSupported() {
1074        //TODO: Should move towards adding a driver API that checks at runtime
1075        return mContext.getResources().getBoolean(
1076                com.android.internal.R.bool.config_wifi_dual_band_support);
1077    }
1078
1079    /**
1080     * Return the DHCP-assigned addresses from the last successful DHCP request,
1081     * if any.
1082     * @return the DHCP information
1083     * @deprecated
1084     */
1085    public DhcpInfo getDhcpInfo() {
1086        enforceAccessPermission();
1087        DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults();
1088
1089        DhcpInfo info = new DhcpInfo();
1090
1091        if (dhcpResults.ipAddress != null &&
1092                dhcpResults.ipAddress.getAddress() instanceof Inet4Address) {
1093            info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.ipAddress.getAddress());
1094        }
1095
1096        if (dhcpResults.gateway != null) {
1097            info.gateway = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.gateway);
1098        }
1099
1100        int dnsFound = 0;
1101        for (InetAddress dns : dhcpResults.dnsServers) {
1102            if (dns instanceof Inet4Address) {
1103                if (dnsFound == 0) {
1104                    info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1105                } else {
1106                    info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1107                }
1108                if (++dnsFound > 1) break;
1109            }
1110        }
1111        InetAddress serverAddress = dhcpResults.serverAddress;
1112        if (serverAddress instanceof Inet4Address) {
1113            info.serverAddress = NetworkUtils.inetAddressToInt((Inet4Address)serverAddress);
1114        }
1115        info.leaseDuration = dhcpResults.leaseDuration;
1116
1117        return info;
1118    }
1119
1120    /**
1121     * see {@link android.net.wifi.WifiManager#startWifi}
1122     *
1123     */
1124    public void startWifi() {
1125        enforceConnectivityInternalPermission();
1126        /* TODO: may be add permissions for access only to connectivity service
1127         * TODO: if a start issued, keep wifi alive until a stop issued irrespective
1128         * of WifiLock & device idle status unless wifi enabled status is toggled
1129         */
1130
1131        mWifiStateMachine.setDriverStart(true);
1132        mWifiStateMachine.reconnectCommand();
1133    }
1134
1135    /**
1136     * see {@link android.net.wifi.WifiManager#stopWifi}
1137     *
1138     */
1139    public void stopWifi() {
1140        enforceConnectivityInternalPermission();
1141        /*
1142         * TODO: if a stop is issued, wifi is brought up only by startWifi
1143         * unless wifi enabled status is toggled
1144         */
1145        mWifiStateMachine.setDriverStart(false);
1146    }
1147
1148    /**
1149     * see {@link android.net.wifi.WifiManager#addToBlacklist}
1150     *
1151     */
1152    public void addToBlacklist(String bssid) {
1153        enforceChangePermission();
1154
1155        mWifiStateMachine.addToBlacklist(bssid);
1156    }
1157
1158    /**
1159     * see {@link android.net.wifi.WifiManager#clearBlacklist}
1160     *
1161     */
1162    public void clearBlacklist() {
1163        enforceChangePermission();
1164
1165        mWifiStateMachine.clearBlacklist();
1166    }
1167
1168    /**
1169     * enable TDLS for the local NIC to remote NIC
1170     * The APPs don't know the remote MAC address to identify NIC though,
1171     * so we need to do additional work to find it from remote IP address
1172     */
1173
1174    class TdlsTaskParams {
1175        public String remoteIpAddress;
1176        public boolean enable;
1177    }
1178
1179    class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> {
1180        @Override
1181        protected Integer doInBackground(TdlsTaskParams... params) {
1182
1183            // Retrieve parameters for the call
1184            TdlsTaskParams param = params[0];
1185            String remoteIpAddress = param.remoteIpAddress.trim();
1186            boolean enable = param.enable;
1187
1188            // Get MAC address of Remote IP
1189            String macAddress = null;
1190
1191            BufferedReader reader = null;
1192
1193            try {
1194                reader = new BufferedReader(new FileReader("/proc/net/arp"));
1195
1196                // Skip over the line bearing colum titles
1197                String line = reader.readLine();
1198
1199                while ((line = reader.readLine()) != null) {
1200                    String[] tokens = line.split("[ ]+");
1201                    if (tokens.length < 6) {
1202                        continue;
1203                    }
1204
1205                    // ARP column format is
1206                    // Address HWType HWAddress Flags Mask IFace
1207                    String ip = tokens[0];
1208                    String mac = tokens[3];
1209
1210                    if (remoteIpAddress.equals(ip)) {
1211                        macAddress = mac;
1212                        break;
1213                    }
1214                }
1215
1216                if (macAddress == null) {
1217                    Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " +
1218                            "/proc/net/arp");
1219                } else {
1220                    enableTdlsWithMacAddress(macAddress, enable);
1221                }
1222
1223            } catch (FileNotFoundException e) {
1224                Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address");
1225            } catch (IOException e) {
1226                Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address");
1227            } finally {
1228                try {
1229                    if (reader != null) {
1230                        reader.close();
1231                    }
1232                }
1233                catch (IOException e) {
1234                    // Do nothing
1235                }
1236            }
1237
1238            return 0;
1239        }
1240    }
1241
1242    public void enableTdls(String remoteAddress, boolean enable) {
1243        if (remoteAddress == null) {
1244          throw new IllegalArgumentException("remoteAddress cannot be null");
1245        }
1246
1247        TdlsTaskParams params = new TdlsTaskParams();
1248        params.remoteIpAddress = remoteAddress;
1249        params.enable = enable;
1250        new TdlsTask().execute(params);
1251    }
1252
1253
1254    public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
1255        if (remoteMacAddress == null) {
1256          throw new IllegalArgumentException("remoteMacAddress cannot be null");
1257        }
1258
1259        mWifiStateMachine.enableTdls(remoteMacAddress, enable);
1260    }
1261
1262    /**
1263     * Get a reference to handler. This is used by a client to establish
1264     * an AsyncChannel communication with WifiService
1265     */
1266    public Messenger getWifiServiceMessenger() {
1267        enforceAccessPermission();
1268        enforceChangePermission();
1269        return new Messenger(mClientHandler);
1270    }
1271
1272
1273    /**
1274     * Get the IP and proxy configuration file
1275     */
1276    public String getConfigFile() {
1277        enforceAccessPermission();
1278        return mWifiStateMachine.getConfigFile();
1279    }
1280
1281    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1282        @Override
1283        public void onReceive(Context context, Intent intent) {
1284            String action = intent.getAction();
1285            if (action.equals(Intent.ACTION_SCREEN_ON)) {
1286                mWifiController.sendMessage(CMD_SCREEN_ON);
1287            } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1288                mWifiController.sendMessage(CMD_USER_PRESENT);
1289            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1290                mWifiController.sendMessage(CMD_SCREEN_OFF);
1291            } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
1292                int pluggedType = intent.getIntExtra("plugged", 0);
1293                mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null);
1294            } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
1295                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
1296                        BluetoothAdapter.STATE_DISCONNECTED);
1297                mWifiStateMachine.sendBluetoothAdapterStateChange(state);
1298            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
1299                boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false);
1300                mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0);
1301            }
1302        }
1303    };
1304
1305    /**
1306     * Observes settings changes to scan always mode.
1307     */
1308    private void registerForScanModeChange() {
1309        ContentObserver contentObserver = new ContentObserver(null) {
1310            @Override
1311            public void onChange(boolean selfChange) {
1312                mSettingsStore.handleWifiScanAlwaysAvailableToggled();
1313                mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED);
1314            }
1315        };
1316
1317        mContext.getContentResolver().registerContentObserver(
1318                Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE),
1319                false, contentObserver);
1320    }
1321
1322    private void registerForBroadcasts() {
1323        IntentFilter intentFilter = new IntentFilter();
1324        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
1325        intentFilter.addAction(Intent.ACTION_USER_PRESENT);
1326        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
1327        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
1328        intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
1329        intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
1330        intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
1331        mContext.registerReceiver(mReceiver, intentFilter);
1332    }
1333
1334    @Override
1335    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1336        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1337                != PackageManager.PERMISSION_GRANTED) {
1338            pw.println("Permission Denial: can't dump WifiService from from pid="
1339                    + Binder.getCallingPid()
1340                    + ", uid=" + Binder.getCallingUid());
1341            return;
1342        }
1343        pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
1344        pw.println("Stay-awake conditions: " +
1345                Settings.Global.getInt(mContext.getContentResolver(),
1346                                       Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
1347        pw.println("mMulticastEnabled " + mMulticastEnabled);
1348        pw.println("mMulticastDisabled " + mMulticastDisabled);
1349        mWifiController.dump(fd, pw, args);
1350        mSettingsStore.dump(fd, pw, args);
1351        mNotificationController.dump(fd, pw, args);
1352        mTrafficPoller.dump(fd, pw, args);
1353
1354        pw.println("Latest scan results:");
1355        List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
1356        if (scanResults != null && scanResults.size() != 0) {
1357            pw.println("  BSSID              Frequency   RSSI  Flags             SSID");
1358            for (ScanResult r : scanResults) {
1359                pw.printf("  %17s  %9d  %5d  %-16s  %s%n",
1360                                         r.BSSID,
1361                                         r.frequency,
1362                                         r.level,
1363                                         r.capabilities,
1364                                         r.SSID == null ? "" : r.SSID);
1365            }
1366        }
1367        pw.println();
1368        pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
1369                mFullHighPerfLocksAcquired + " full high perf, " +
1370                mScanLocksAcquired + " scan");
1371        pw.println("Locks released: " + mFullLocksReleased + " full, " +
1372                mFullHighPerfLocksReleased + " full high perf, " +
1373                mScanLocksReleased + " scan");
1374        pw.println();
1375        pw.println("Locks held:");
1376        mLocks.dump(pw);
1377
1378        mWifiWatchdogStateMachine.dump(fd, pw, args);
1379        pw.println();
1380        mWifiStateMachine.dump(fd, pw, args);
1381        pw.println();
1382    }
1383
1384    private class WifiLock extends DeathRecipient {
1385        WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
1386            super(lockMode, tag, binder, ws);
1387        }
1388
1389        public void binderDied() {
1390            synchronized (mLocks) {
1391                releaseWifiLockLocked(mBinder);
1392            }
1393        }
1394
1395        public String toString() {
1396            return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
1397        }
1398    }
1399
1400    class LockList {
1401        private List<WifiLock> mList;
1402
1403        private LockList() {
1404            mList = new ArrayList<WifiLock>();
1405        }
1406
1407        synchronized boolean hasLocks() {
1408            return !mList.isEmpty();
1409        }
1410
1411        synchronized int getStrongestLockMode() {
1412            if (mList.isEmpty()) {
1413                return WifiManager.WIFI_MODE_FULL;
1414            }
1415
1416            if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
1417                return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
1418            }
1419
1420            if (mFullLocksAcquired > mFullLocksReleased) {
1421                return WifiManager.WIFI_MODE_FULL;
1422            }
1423
1424            return WifiManager.WIFI_MODE_SCAN_ONLY;
1425        }
1426
1427        synchronized void updateWorkSource(WorkSource ws) {
1428            for (int i = 0; i < mLocks.mList.size(); i++) {
1429                ws.add(mLocks.mList.get(i).mWorkSource);
1430            }
1431        }
1432
1433        private void addLock(WifiLock lock) {
1434            if (findLockByBinder(lock.mBinder) < 0) {
1435                mList.add(lock);
1436            }
1437        }
1438
1439        private WifiLock removeLock(IBinder binder) {
1440            int index = findLockByBinder(binder);
1441            if (index >= 0) {
1442                WifiLock ret = mList.remove(index);
1443                ret.unlinkDeathRecipient();
1444                return ret;
1445            } else {
1446                return null;
1447            }
1448        }
1449
1450        private int findLockByBinder(IBinder binder) {
1451            int size = mList.size();
1452            for (int i = size - 1; i >= 0; i--) {
1453                if (mList.get(i).mBinder == binder)
1454                    return i;
1455            }
1456            return -1;
1457        }
1458
1459        private void dump(PrintWriter pw) {
1460            for (WifiLock l : mList) {
1461                pw.print("    ");
1462                pw.println(l);
1463            }
1464        }
1465    }
1466
1467    void enforceWakeSourcePermission(int uid, int pid) {
1468        if (uid == android.os.Process.myUid()) {
1469            return;
1470        }
1471        mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
1472                pid, uid, null);
1473    }
1474
1475    public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
1476        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1477        if (lockMode != WifiManager.WIFI_MODE_FULL &&
1478                lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
1479                lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
1480            Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
1481            if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
1482            return false;
1483        }
1484        if (ws != null && ws.size() == 0) {
1485            ws = null;
1486        }
1487        if (ws != null) {
1488            enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
1489        }
1490        if (ws == null) {
1491            ws = new WorkSource(Binder.getCallingUid());
1492        }
1493        WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
1494        synchronized (mLocks) {
1495            return acquireWifiLockLocked(wifiLock);
1496        }
1497    }
1498
1499    private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
1500        switch(wifiLock.mMode) {
1501            case WifiManager.WIFI_MODE_FULL:
1502            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1503            case WifiManager.WIFI_MODE_SCAN_ONLY:
1504                mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
1505                break;
1506        }
1507    }
1508
1509    private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
1510        switch(wifiLock.mMode) {
1511            case WifiManager.WIFI_MODE_FULL:
1512            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1513            case WifiManager.WIFI_MODE_SCAN_ONLY:
1514                mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
1515                break;
1516        }
1517    }
1518
1519    private boolean acquireWifiLockLocked(WifiLock wifiLock) {
1520        if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
1521
1522        mLocks.addLock(wifiLock);
1523
1524        long ident = Binder.clearCallingIdentity();
1525        try {
1526            noteAcquireWifiLock(wifiLock);
1527            switch(wifiLock.mMode) {
1528            case WifiManager.WIFI_MODE_FULL:
1529                ++mFullLocksAcquired;
1530                break;
1531            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1532                ++mFullHighPerfLocksAcquired;
1533                break;
1534
1535            case WifiManager.WIFI_MODE_SCAN_ONLY:
1536                ++mScanLocksAcquired;
1537                break;
1538            }
1539            mWifiController.sendMessage(CMD_LOCKS_CHANGED);
1540            return true;
1541        } catch (RemoteException e) {
1542            return false;
1543        } finally {
1544            Binder.restoreCallingIdentity(ident);
1545        }
1546    }
1547
1548    public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
1549        int uid = Binder.getCallingUid();
1550        int pid = Binder.getCallingPid();
1551        if (ws != null && ws.size() == 0) {
1552            ws = null;
1553        }
1554        if (ws != null) {
1555            enforceWakeSourcePermission(uid, pid);
1556        }
1557        long ident = Binder.clearCallingIdentity();
1558        try {
1559            synchronized (mLocks) {
1560                int index = mLocks.findLockByBinder(lock);
1561                if (index < 0) {
1562                    throw new IllegalArgumentException("Wifi lock not active");
1563                }
1564                WifiLock wl = mLocks.mList.get(index);
1565                noteReleaseWifiLock(wl);
1566                wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
1567                noteAcquireWifiLock(wl);
1568            }
1569        } catch (RemoteException e) {
1570        } finally {
1571            Binder.restoreCallingIdentity(ident);
1572        }
1573    }
1574
1575    public boolean releaseWifiLock(IBinder lock) {
1576        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1577        synchronized (mLocks) {
1578            return releaseWifiLockLocked(lock);
1579        }
1580    }
1581
1582    private boolean releaseWifiLockLocked(IBinder lock) {
1583        boolean hadLock;
1584
1585        WifiLock wifiLock = mLocks.removeLock(lock);
1586
1587        if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
1588
1589        hadLock = (wifiLock != null);
1590
1591        long ident = Binder.clearCallingIdentity();
1592        try {
1593            if (hadLock) {
1594                noteReleaseWifiLock(wifiLock);
1595                switch(wifiLock.mMode) {
1596                    case WifiManager.WIFI_MODE_FULL:
1597                        ++mFullLocksReleased;
1598                        break;
1599                    case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1600                        ++mFullHighPerfLocksReleased;
1601                        break;
1602                    case WifiManager.WIFI_MODE_SCAN_ONLY:
1603                        ++mScanLocksReleased;
1604                        break;
1605                }
1606                mWifiController.sendMessage(CMD_LOCKS_CHANGED);
1607            }
1608        } catch (RemoteException e) {
1609        } finally {
1610            Binder.restoreCallingIdentity(ident);
1611        }
1612
1613        return hadLock;
1614    }
1615
1616    private abstract class DeathRecipient
1617            implements IBinder.DeathRecipient {
1618        String mTag;
1619        int mMode;
1620        IBinder mBinder;
1621        WorkSource mWorkSource;
1622
1623        DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) {
1624            super();
1625            mTag = tag;
1626            mMode = mode;
1627            mBinder = binder;
1628            mWorkSource = ws;
1629            try {
1630                mBinder.linkToDeath(this, 0);
1631            } catch (RemoteException e) {
1632                binderDied();
1633            }
1634        }
1635
1636        void unlinkDeathRecipient() {
1637            mBinder.unlinkToDeath(this, 0);
1638        }
1639    }
1640
1641    private class Multicaster extends DeathRecipient {
1642        Multicaster(String tag, IBinder binder) {
1643            super(Binder.getCallingUid(), tag, binder, null);
1644        }
1645
1646        public void binderDied() {
1647            Slog.e(TAG, "Multicaster binderDied");
1648            synchronized (mMulticasters) {
1649                int i = mMulticasters.indexOf(this);
1650                if (i != -1) {
1651                    removeMulticasterLocked(i, mMode);
1652                }
1653            }
1654        }
1655
1656        public String toString() {
1657            return "Multicaster{" + mTag + " binder=" + mBinder + "}";
1658        }
1659
1660        public int getUid() {
1661            return mMode;
1662        }
1663    }
1664
1665    public void initializeMulticastFiltering() {
1666        enforceMulticastChangePermission();
1667
1668        synchronized (mMulticasters) {
1669            // if anybody had requested filters be off, leave off
1670            if (mMulticasters.size() != 0) {
1671                return;
1672            } else {
1673                mWifiStateMachine.startFilteringMulticastV4Packets();
1674            }
1675        }
1676    }
1677
1678    public void acquireMulticastLock(IBinder binder, String tag) {
1679        enforceMulticastChangePermission();
1680
1681        synchronized (mMulticasters) {
1682            mMulticastEnabled++;
1683            mMulticasters.add(new Multicaster(tag, binder));
1684            // Note that we could call stopFilteringMulticastV4Packets only when
1685            // our new size == 1 (first call), but this function won't
1686            // be called often and by making the stopPacket call each
1687            // time we're less fragile and self-healing.
1688            mWifiStateMachine.stopFilteringMulticastV4Packets();
1689        }
1690
1691        int uid = Binder.getCallingUid();
1692        final long ident = Binder.clearCallingIdentity();
1693        try {
1694            mBatteryStats.noteWifiMulticastEnabled(uid);
1695        } catch (RemoteException e) {
1696        } finally {
1697            Binder.restoreCallingIdentity(ident);
1698        }
1699    }
1700
1701    public void releaseMulticastLock() {
1702        enforceMulticastChangePermission();
1703
1704        int uid = Binder.getCallingUid();
1705        synchronized (mMulticasters) {
1706            mMulticastDisabled++;
1707            int size = mMulticasters.size();
1708            for (int i = size - 1; i >= 0; i--) {
1709                Multicaster m = mMulticasters.get(i);
1710                if ((m != null) && (m.getUid() == uid)) {
1711                    removeMulticasterLocked(i, uid);
1712                }
1713            }
1714        }
1715    }
1716
1717    private void removeMulticasterLocked(int i, int uid)
1718    {
1719        Multicaster removed = mMulticasters.remove(i);
1720
1721        if (removed != null) {
1722            removed.unlinkDeathRecipient();
1723        }
1724        if (mMulticasters.size() == 0) {
1725            mWifiStateMachine.startFilteringMulticastV4Packets();
1726        }
1727
1728        final long ident = Binder.clearCallingIdentity();
1729        try {
1730            mBatteryStats.noteWifiMulticastDisabled(uid);
1731        } catch (RemoteException e) {
1732        } finally {
1733            Binder.restoreCallingIdentity(ident);
1734        }
1735    }
1736
1737    public boolean isMulticastEnabled() {
1738        enforceAccessPermission();
1739
1740        synchronized (mMulticasters) {
1741            return (mMulticasters.size() > 0);
1742        }
1743    }
1744
1745    public WifiMonitor getWifiMonitor() {
1746        return mWifiStateMachine.getWifiMonitor();
1747    }
1748
1749
1750    public void enableVerboseLogging(int verbose) {
1751        enforceAccessPermission();
1752        mWifiStateMachine.enableVerboseLogging(verbose);
1753    }
1754
1755    public int getVerboseLoggingLevel() {
1756        enforceAccessPermission();
1757        return mWifiStateMachine.getVerboseLoggingLevel();
1758    }
1759
1760    public void enableAggressiveHandover(int enabled) {
1761        enforceAccessPermission();
1762        mWifiStateMachine.enableAggressiveHandover(enabled);
1763    }
1764
1765    public int getAggressiveHandover() {
1766        enforceAccessPermission();
1767        return mWifiStateMachine.getAggressiveHandover();
1768    }
1769
1770    public void setAllowScansWithTraffic(int enabled) {
1771        enforceAccessPermission();
1772        mWifiStateMachine.setAllowScansWithTraffic(enabled);
1773    }
1774
1775    public int getAllowScansWithTraffic() {
1776        enforceAccessPermission();
1777        return mWifiStateMachine.getAllowScansWithTraffic();
1778    }
1779
1780    /* Return the Wifi Connection statistics object */
1781    public WifiConnectionStatistics getConnectionStatistics() {
1782        enforceAccessPermission();
1783        enforceReadCredentialPermission();
1784        if (mWifiStateMachineChannel != null) {
1785            return mWifiStateMachine.syncGetConnectionStatistics(mWifiStateMachineChannel);
1786        } else {
1787            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1788            return null;
1789        }
1790    }
1791}
1792