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