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