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