blob: bd5a3fd732aa6473e9fd01a8fa13f66aea477ffc [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07002 * Copyright (C) 2010 The Android Open Source Project
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003 *
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
Irfan Sheriffd017f352013-02-20 13:30:44 -080017package com.android.server.wifi;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Irfan Sheriff330b1872012-09-16 12:27:57 -070019import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.app.AlarmManager;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -080021import android.app.AppOpsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.app.PendingIntent;
Jaikumar Ganesh7440fc22010-09-27 17:04:14 -070023import android.bluetooth.BluetoothAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.pm.PackageManager;
29import android.net.wifi.IWifiManager;
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -080030import android.net.wifi.ScanResult;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.net.wifi.WifiInfo;
32import android.net.wifi.WifiManager;
Irfan Sheriff0d255342010-07-28 09:35:20 -070033import android.net.wifi.WifiStateMachine;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.net.wifi.WifiConfiguration;
Isaac Levy654f5092011-07-13 17:41:45 -070035import android.net.wifi.WifiWatchdogStateMachine;
Irfan Sheriff5321aef2010-02-12 12:35:59 -080036import android.net.ConnectivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.net.DhcpInfo;
Robert Greenwalt4717c262012-10-31 14:32:53 -070038import android.net.DhcpResults;
39import android.net.LinkAddress;
Irfan Sheriff0d255342010-07-28 09:35:20 -070040import android.net.NetworkInfo;
Irfan Sheriff227bec42011-02-15 19:30:27 -080041import android.net.NetworkInfo.DetailedState;
Robert Greenwalt4717c262012-10-31 14:32:53 -070042import android.net.NetworkUtils;
43import android.net.RouteInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.os.Binder;
Irfan Sheriff0d255342010-07-28 09:35:20 -070045import android.os.Handler;
Irfan Sheriff227bec42011-02-15 19:30:27 -080046import android.os.Messenger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.os.HandlerThread;
48import android.os.IBinder;
Irfan Sheriff5321aef2010-02-12 12:35:59 -080049import android.os.INetworkManagementService;
Irfan Sheriff0d255342010-07-28 09:35:20 -070050import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.RemoteException;
Irfan Sheriff227bec42011-02-15 19:30:27 -080052import android.os.SystemProperties;
Irfan Sheriff330b1872012-09-16 12:27:57 -070053import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070054import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.provider.Settings;
Nick Pelly6ccaa542012-06-15 15:22:47 -070056import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080057import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058
Irfan Sherifff0afe412012-11-30 14:07:44 -080059import java.io.FileDescriptor;
60import java.io.PrintWriter;
Robert Greenwalt4717c262012-10-31 14:32:53 -070061import java.net.InetAddress;
62import java.net.Inet4Address;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import java.util.List;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065
The Android Open Source Project10592532009-03-18 17:39:46 -070066import com.android.internal.app.IBatteryStats;
Irfan Sheriff616f3172011-09-11 19:59:01 -070067import com.android.internal.telephony.TelephonyIntents;
Wink Saville4b7ba092010-10-20 15:37:41 -070068import com.android.internal.util.AsyncChannel;
The Android Open Source Project10592532009-03-18 17:39:46 -070069import com.android.server.am.BatteryStatsService;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080070import com.android.internal.R;
The Android Open Source Project10592532009-03-18 17:39:46 -070071
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072/**
73 * WifiService handles remote WiFi operation requests by implementing
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070074 * the IWifiManager interface.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 *
76 * @hide
77 */
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070078//TODO: Clean up multiple locks and implement WifiService
79// as a SM to track soft AP/client/adhoc bring up based
80// on device idle state, airplane mode and boot.
81
Irfan Sheriffb8c0e002013-02-20 14:19:54 -080082public final class WifiService extends IWifiManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 private static final String TAG = "WifiService";
Dianne Hackborn5fd21692011-06-07 14:09:47 -070084 private static final boolean DBG = false;
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070085
Irfan Sheriff0d255342010-07-28 09:35:20 -070086 private final WifiStateMachine mWifiStateMachine;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087
Irfan Sheriffb8c0e002013-02-20 14:19:54 -080088 private final Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089
90 private AlarmManager mAlarmManager;
91 private PendingIntent mIdleIntent;
92 private static final int IDLE_REQUEST = 0;
93 private boolean mScreenOff;
94 private boolean mDeviceIdle;
Irfan Sheriff616f3172011-09-11 19:59:01 -070095 private boolean mEmergencyCallbackMode = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 private int mPluggedType;
97
98 private final LockList mLocks = new LockList();
Eric Shienbrood5711fad2009-03-27 20:25:31 -070099 // some wifi lock statistics
Irfan Sheriff5876a422010-08-12 20:26:23 -0700100 private int mFullHighPerfLocksAcquired;
101 private int mFullHighPerfLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -0700102 private int mFullLocksAcquired;
103 private int mFullLocksReleased;
104 private int mScanLocksAcquired;
105 private int mScanLocksReleased;
The Android Open Source Project10592532009-03-18 17:39:46 -0700106
Robert Greenwalt58ff0212009-05-19 15:53:54 -0700107 private final List<Multicaster> mMulticasters =
108 new ArrayList<Multicaster>();
Robert Greenwalt5347bd42009-05-13 15:10:16 -0700109 private int mMulticastEnabled;
110 private int mMulticastDisabled;
111
The Android Open Source Project10592532009-03-18 17:39:46 -0700112 private final IBatteryStats mBatteryStats;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800113 private final AppOpsManager mAppOps;
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800114
Irfan Sheriff227bec42011-02-15 19:30:27 -0800115 private String mInterfaceName;
116
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800117 /* Tracks the open wi-fi network notification */
118 private WifiNotificationController mNotificationController;
119 /* Polls traffic stats and notifies clients */
120 private WifiTrafficPoller mTrafficPoller;
121 /* Tracks the persisted states for wi-fi & airplane mode */
122 private WifiSettingsStore mSettingsStore;
Irfan Sheriff227bec42011-02-15 19:30:27 -0800123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 /**
Christopher Tate6f5a9a92012-09-14 17:24:28 -0700125 * See {@link Settings.Global#WIFI_IDLE_MS}. This is the default value if a
126 * Settings.Global value is not present. This timeout value is chosen as
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 * the approximate point at which the battery drain caused by Wi-Fi
128 * being enabled but not active exceeds the battery drain caused by
129 * re-establishing a connection to the mobile data network.
130 */
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700131 private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */
132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 private static final String ACTION_DEVICE_IDLE =
134 "com.android.server.WifiManager.action.DEVICE_IDLE";
135
Nick Pelly6ccaa542012-06-15 15:22:47 -0700136 /* The work source (UID) that triggered the current WIFI scan, synchronized
137 * on this */
138 private WorkSource mScanWorkSource;
139
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700140 private boolean mIsReceiverRegistered = false;
141
Irfan Sheriff0d255342010-07-28 09:35:20 -0700142 NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
143
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700144 /**
Wink Saville4b7ba092010-10-20 15:37:41 -0700145 * Asynchronous channel to WifiStateMachine
146 */
Irfan Sheriff227bec42011-02-15 19:30:27 -0800147 private AsyncChannel mWifiStateMachineChannel;
Wink Saville4b7ba092010-10-20 15:37:41 -0700148
149 /**
Irfan Sheriff227bec42011-02-15 19:30:27 -0800150 * Clients receiving asynchronous messages
Wink Saville4b7ba092010-10-20 15:37:41 -0700151 */
Irfan Sheriff302b06d2013-02-22 12:35:31 -0800152 private List<Messenger> mClients = new ArrayList<Messenger>();
Wink Saville4b7ba092010-10-20 15:37:41 -0700153
Irfan Sheriff227bec42011-02-15 19:30:27 -0800154 /**
155 * Handles client connections
156 */
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800157 private class ClientHandler extends Handler {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800158
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800159 ClientHandler(android.os.Looper looper) {
Wink Saville4b7ba092010-10-20 15:37:41 -0700160 super(looper);
Wink Saville4b7ba092010-10-20 15:37:41 -0700161 }
162
163 @Override
164 public void handleMessage(Message msg) {
165 switch (msg.what) {
166 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
167 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
Irfan Sheriff6bfc8882012-08-29 15:35:57 -0700168 if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
Irfan Sheriff302b06d2013-02-22 12:35:31 -0800169 // We track the clients by the Messenger
170 // since it is expected to be always available
171 mClients.add(msg.replyTo);
Wink Saville4b7ba092010-10-20 15:37:41 -0700172 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800173 Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
174 }
175 break;
176 }
Irfan Sheriffc23971b2011-03-04 17:06:31 -0800177 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
178 if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
Irfan Sheriff6bfc8882012-08-29 15:35:57 -0700179 if (DBG) Slog.d(TAG, "Send failed, client connection lost");
Irfan Sheriffc23971b2011-03-04 17:06:31 -0800180 } else {
Irfan Sheriff6bfc8882012-08-29 15:35:57 -0700181 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
Irfan Sheriffc23971b2011-03-04 17:06:31 -0800182 }
Irfan Sheriff302b06d2013-02-22 12:35:31 -0800183 mClients.remove(msg.replyTo);
Irfan Sheriffc23971b2011-03-04 17:06:31 -0800184 break;
185 }
Irfan Sheriff227bec42011-02-15 19:30:27 -0800186 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
187 AsyncChannel ac = new AsyncChannel();
188 ac.connect(mContext, this, msg.replyTo);
189 break;
190 }
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800191 /* Client commands are forwarded to state machine */
192 case WifiManager.CONNECT_NETWORK:
193 case WifiManager.SAVE_NETWORK:
194 case WifiManager.FORGET_NETWORK:
195 case WifiManager.START_WPS:
196 case WifiManager.CANCEL_WPS:
197 case WifiManager.DISABLE_NETWORK:
Yuhao Zhengf6307822012-08-14 14:21:25 -0700198 case WifiManager.RSSI_PKTCNT_FETCH: {
199 mWifiStateMachine.sendMessage(Message.obtain(msg));
200 break;
201 }
Wink Saville4b7ba092010-10-20 15:37:41 -0700202 default: {
203 Slog.d(TAG, "WifiServicehandler.handleMessage ignoring msg=" + msg);
204 break;
205 }
206 }
207 }
208 }
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800209 private ClientHandler mClientHandler;
Irfan Sheriff227bec42011-02-15 19:30:27 -0800210
211 /**
212 * Handles interaction with WifiStateMachine
213 */
214 private class WifiStateMachineHandler extends Handler {
215 private AsyncChannel mWsmChannel;
216
217 WifiStateMachineHandler(android.os.Looper looper) {
218 super(looper);
219 mWsmChannel = new AsyncChannel();
220 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
221 }
222
223 @Override
224 public void handleMessage(Message msg) {
225 switch (msg.what) {
226 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
227 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
228 mWifiStateMachineChannel = mWsmChannel;
229 } else {
230 Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1);
231 mWifiStateMachineChannel = null;
232 }
233 break;
234 }
Irfan Sheriff6da83d52011-06-06 12:54:06 -0700235 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
236 Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1);
237 mWifiStateMachineChannel = null;
238 //Re-establish connection to state machine
239 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
240 break;
241 }
Irfan Sheriff227bec42011-02-15 19:30:27 -0800242 default: {
243 Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg);
244 break;
245 }
246 }
247 }
248 }
249 WifiStateMachineHandler mWifiStateMachineHandler;
Wink Saville4b7ba092010-10-20 15:37:41 -0700250
251 /**
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700252 * Temporary for computing UIDS that are responsible for starting WIFI.
253 * Protected by mWifiStateTracker lock.
254 */
255 private final WorkSource mTmpWorkSource = new WorkSource();
Isaac Levy654f5092011-07-13 17:41:45 -0700256 private WifiWatchdogStateMachine mWifiWatchdogStateMachine;
Irfan Sheriff0d255342010-07-28 09:35:20 -0700257
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800258 public WifiService(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 mContext = context;
Irfan Sheriff227bec42011-02-15 19:30:27 -0800260
261 mInterfaceName = SystemProperties.get("wifi.interface", "wlan0");
262
263 mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName);
Irfan Sheriff0d255342010-07-28 09:35:20 -0700264 mWifiStateMachine.enableRssiPolling(true);
The Android Open Source Project10592532009-03-18 17:39:46 -0700265 mBatteryStats = BatteryStatsService.getService();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800266 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
269 Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
270 mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
271
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800272 mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine);
273 mTrafficPoller = new WifiTrafficPoller(mContext, mClients, mInterfaceName);
274 mSettingsStore = new WifiSettingsStore(mContext);
275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 mContext.registerReceiver(
277 new BroadcastReceiver() {
278 @Override
279 public void onReceive(Context context, Intent intent) {
Irfan Sheriff8a64b1a2013-02-20 15:12:41 -0800280 if (mSettingsStore.handleAirplaneModeToggled()) {
281 updateWifiState();
282 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 }
284 },
285 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
286
Irfan Sheriff0d255342010-07-28 09:35:20 -0700287 mContext.registerReceiver(
288 new BroadcastReceiver() {
289 @Override
290 public void onReceive(Context context, Intent intent) {
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800291 if (intent.getAction().equals(
Irfan Sheriff0d255342010-07-28 09:35:20 -0700292 WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
Nick Pelly6ccaa542012-06-15 15:22:47 -0700293 noteScanEnd();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700294 }
295 }
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800296 }, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
Irfan Sheriff0d255342010-07-28 09:35:20 -0700297
Irfan Sheriff227bec42011-02-15 19:30:27 -0800298 HandlerThread wifiThread = new HandlerThread("WifiService");
299 wifiThread.start();
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800300 mClientHandler = new ClientHandler(wifiThread.getLooper());
Irfan Sheriff227bec42011-02-15 19:30:27 -0800301 mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
Irfan Sheriff7b009782010-03-11 16:37:45 -0800302 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800303
Nick Pelly6ccaa542012-06-15 15:22:47 -0700304 /** Tell battery stats about a new WIFI scan */
305 private void noteScanStart() {
306 WorkSource scanWorkSource = null;
307 synchronized (WifiService.this) {
308 if (mScanWorkSource != null) {
309 // Scan already in progress, don't add this one to battery stats
310 return;
311 }
312 scanWorkSource = new WorkSource(Binder.getCallingUid());
313 mScanWorkSource = scanWorkSource;
314 }
315
316 long id = Binder.clearCallingIdentity();
317 try {
318 mBatteryStats.noteWifiScanStartedFromSource(scanWorkSource);
319 } catch (RemoteException e) {
320 Log.w(TAG, e);
321 } finally {
322 Binder.restoreCallingIdentity(id);
323 }
324 }
325
326 /** Tell battery stats that the current WIFI scan has completed */
327 private void noteScanEnd() {
328 WorkSource scanWorkSource = null;
329 synchronized (WifiService.this) {
330 scanWorkSource = mScanWorkSource;
331 mScanWorkSource = null;
332 }
333 if (scanWorkSource != null) {
334 try {
335 mBatteryStats.noteWifiScanStoppedFromSource(scanWorkSource);
336 } catch (RemoteException e) {
337 Log.w(TAG, e);
338 }
339 }
340 }
341
Irfan Sheriff7b009782010-03-11 16:37:45 -0800342 /**
343 * Check if Wi-Fi needs to be enabled and start
344 * if needed
Irfan Sheriff60e3ba02010-04-02 12:18:45 -0700345 *
346 * This function is used only at boot time
Irfan Sheriff7b009782010-03-11 16:37:45 -0800347 */
Irfan Sheriff0d255342010-07-28 09:35:20 -0700348 public void checkAndStartWifi() {
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800349 /* Check if wi-fi needs to be enabled */
350 boolean wifiEnabled = mSettingsStore.shouldWifiBeEnabled();
Irfan Sheriff7b009782010-03-11 16:37:45 -0800351 Slog.i(TAG, "WifiService starting up with Wi-Fi " +
352 (wifiEnabled ? "enabled" : "disabled"));
Irfan Sherifff03d6202012-05-17 12:33:46 -0700353
354 // If we are already disabled (could be due to airplane mode), avoid changing persist
355 // state here
356 if (wifiEnabled) setWifiEnabled(wifiEnabled);
Isaac Levybc7dfb52011-06-06 15:34:01 -0700357
Isaac Levy654f5092011-07-13 17:41:45 -0700358 mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
359 makeWifiWatchdogStateMachine(mContext);
360
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800361 }
362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 /**
364 * see {@link android.net.wifi.WifiManager#pingSupplicant()}
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700365 * @return {@code true} if the operation succeeds, {@code false} otherwise
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 */
367 public boolean pingSupplicant() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700368 enforceAccessPermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800369 if (mWifiStateMachineChannel != null) {
370 return mWifiStateMachine.syncPingSupplicant(mWifiStateMachineChannel);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700371 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800372 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700373 return false;
374 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 }
376
377 /**
378 * see {@link android.net.wifi.WifiManager#startScan()}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 */
Irfan Sheriffbcc97ca2013-02-21 14:15:18 -0800380 public void startScan() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 enforceChangePermission();
Irfan Sheriffbcc97ca2013-02-21 14:15:18 -0800382 mWifiStateMachine.startScan();
Nick Pelly6ccaa542012-06-15 15:22:47 -0700383 noteScanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 }
385
386 private void enforceAccessPermission() {
387 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
388 "WifiService");
389 }
390
391 private void enforceChangePermission() {
392 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
393 "WifiService");
394
395 }
396
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -0700397 private void enforceMulticastChangePermission() {
398 mContext.enforceCallingOrSelfPermission(
399 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
400 "WifiService");
401 }
402
Irfan Sheriffda6da092012-08-16 12:49:23 -0700403 private void enforceConnectivityInternalPermission() {
404 mContext.enforceCallingOrSelfPermission(
405 android.Manifest.permission.CONNECTIVITY_INTERNAL,
406 "ConnectivityService");
407 }
408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700410 * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
411 * @param enable {@code true} to enable, {@code false} to disable.
412 * @return {@code true} if the enable/disable operation was
413 * started or is already in the queue.
414 */
415 public synchronized boolean setWifiEnabled(boolean enable) {
416 enforceChangePermission();
Irfan Sheriffbd21b782012-05-16 13:13:54 -0700417 Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
418 + ", uid=" + Binder.getCallingUid());
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700419 if (DBG) {
Irfan Sheriff0d255342010-07-28 09:35:20 -0700420 Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700421 }
422
Irfan Sheriff61180692010-08-18 16:07:39 -0700423 /*
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800424 * Caller might not have WRITE_SECURE_SETTINGS,
425 * only CHANGE_WIFI_STATE is enforced
426 */
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800427
Irfan Sherifff03d6202012-05-17 12:33:46 -0700428 long ident = Binder.clearCallingIdentity();
Irfan Sheriff3d33a632012-09-16 17:59:13 -0700429 try {
Irfan Sheriff8a64b1a2013-02-20 15:12:41 -0800430 if (! mSettingsStore.handleWifiToggled(enable)) {
431 // Nothing to do if wifi cannot be toggled
432 return true;
433 }
Irfan Sheriff3d33a632012-09-16 17:59:13 -0700434 } finally {
435 Binder.restoreCallingIdentity(ident);
436 }
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700437
438 if (enable) {
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800439 reportStartWorkSource();
440 }
441
442 mWifiStateMachine.setWifiEnabled(enable);
443
444 if (enable) {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700445 if (!mIsReceiverRegistered) {
446 registerForBroadcasts();
447 mIsReceiverRegistered = true;
448 }
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800449 } else if (mIsReceiverRegistered) {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700450 mContext.unregisterReceiver(mReceiver);
451 mIsReceiverRegistered = false;
452 }
453
454 return true;
455 }
456
457 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 * see {@link WifiManager#getWifiState()}
459 * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
460 * {@link WifiManager#WIFI_STATE_DISABLING},
461 * {@link WifiManager#WIFI_STATE_ENABLED},
462 * {@link WifiManager#WIFI_STATE_ENABLING},
463 * {@link WifiManager#WIFI_STATE_UNKNOWN}
464 */
465 public int getWifiEnabledState() {
466 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700467 return mWifiStateMachine.syncGetWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 }
469
470 /**
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700471 * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800472 * @param wifiConfig SSID, security and channel details as
473 * part of WifiConfiguration
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700474 * @param enabled true to enable and false to disable
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800475 */
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700476 public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800477 enforceChangePermission();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700478 mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800479 }
480
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700481 /**
482 * see {@link WifiManager#getWifiApState()}
483 * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
484 * {@link WifiManager#WIFI_AP_STATE_DISABLING},
485 * {@link WifiManager#WIFI_AP_STATE_ENABLED},
486 * {@link WifiManager#WIFI_AP_STATE_ENABLING},
487 * {@link WifiManager#WIFI_AP_STATE_FAILED}
488 */
489 public int getWifiApEnabledState() {
Irfan Sheriff17b232b2010-06-24 11:32:26 -0700490 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700491 return mWifiStateMachine.syncGetWifiApState();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700492 }
493
494 /**
495 * see {@link WifiManager#getWifiApConfiguration()}
496 * @return soft access point configuration
497 */
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700498 public WifiConfiguration getWifiApConfiguration() {
499 enforceAccessPermission();
Irfan Sheriff9575a1b2011-11-07 10:34:54 -0800500 return mWifiStateMachine.syncGetWifiApConfiguration();
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800501 }
502
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700503 /**
504 * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
505 * @param wifiConfig WifiConfiguration details for soft access point
506 */
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700507 public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
Irfan Sheriff17b232b2010-06-24 11:32:26 -0700508 enforceChangePermission();
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800509 if (wifiConfig == null)
510 return;
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700511 mWifiStateMachine.setWifiApConfiguration(wifiConfig);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800512 }
513
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800514 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700515 * see {@link android.net.wifi.WifiManager#disconnect()}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800516 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700517 public void disconnect() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700518 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700519 mWifiStateMachine.disconnectCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800520 }
521
522 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700523 * see {@link android.net.wifi.WifiManager#reconnect()}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800524 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700525 public void reconnect() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700526 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700527 mWifiStateMachine.reconnectCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800528 }
529
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700530 /**
531 * see {@link android.net.wifi.WifiManager#reassociate()}
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700532 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700533 public void reassociate() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700534 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700535 mWifiStateMachine.reassociateCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800536 }
537
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538 /**
539 * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
540 * @return the list of configured networks
541 */
542 public List<WifiConfiguration> getConfiguredNetworks() {
543 enforceAccessPermission();
Irfan Sheriffe744cff2011-12-11 09:17:50 -0800544 if (mWifiStateMachineChannel != null) {
545 return mWifiStateMachine.syncGetConfiguredNetworks(mWifiStateMachineChannel);
546 } else {
547 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
548 return null;
549 }
Chung-yih Wanga8d15942009-10-09 11:01:49 +0800550 }
551
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 /**
553 * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
554 * @return the supplicant-assigned identifier for the new or updated
555 * network if the operation succeeds, or {@code -1} if it fails
556 */
Irfan Sheriff7aac5542009-12-22 21:42:17 -0800557 public int addOrUpdateNetwork(WifiConfiguration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800559 if (mWifiStateMachineChannel != null) {
560 return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700561 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800562 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700563 return -1;
564 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 }
566
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700567 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
569 * @param netId the integer that identifies the network configuration
570 * to the supplicant
571 * @return {@code true} if the operation succeeded
572 */
573 public boolean removeNetwork(int netId) {
574 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800575 if (mWifiStateMachineChannel != null) {
576 return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
Wink Saville4b7ba092010-10-20 15:37:41 -0700577 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800578 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Wink Saville4b7ba092010-10-20 15:37:41 -0700579 return false;
580 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 }
582
583 /**
584 * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
585 * @param netId the integer that identifies the network configuration
586 * to the supplicant
587 * @param disableOthers if true, disable all other networks.
588 * @return {@code true} if the operation succeeded
589 */
590 public boolean enableNetwork(int netId, boolean disableOthers) {
591 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800592 if (mWifiStateMachineChannel != null) {
593 return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
594 disableOthers);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700595 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800596 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700597 return false;
598 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 }
600
601 /**
602 * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
603 * @param netId the integer that identifies the network configuration
604 * to the supplicant
605 * @return {@code true} if the operation succeeded
606 */
607 public boolean disableNetwork(int netId) {
608 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800609 if (mWifiStateMachineChannel != null) {
610 return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700611 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800612 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700613 return false;
614 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 }
616
617 /**
618 * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
619 * @return the Wi-Fi information, contained in {@link WifiInfo}.
620 */
621 public WifiInfo getConnectionInfo() {
622 enforceAccessPermission();
623 /*
624 * Make sure we have the latest information, by sending
625 * a status request to the supplicant.
626 */
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700627 return mWifiStateMachine.syncRequestConnectionInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 }
629
630 /**
631 * Return the results of the most recent access point scan, in the form of
632 * a list of {@link ScanResult} objects.
633 * @return the list of results
634 */
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800635 public List<ScanResult> getScanResults(String callingPackage) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 enforceAccessPermission();
Irfan Sheriffdb831da2012-09-16 17:39:26 -0700637 int userId = UserHandle.getCallingUserId();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800638 int uid = Binder.getCallingUid();
Irfan Sheriffdb831da2012-09-16 17:39:26 -0700639 long ident = Binder.clearCallingIdentity();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800640 if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
641 != AppOpsManager.MODE_ALLOWED) {
642 return new ArrayList<ScanResult>();
643 }
Irfan Sheriff3d33a632012-09-16 17:59:13 -0700644 try {
645 int currentUser = ActivityManager.getCurrentUser();
646 if (userId != currentUser) {
647 return new ArrayList<ScanResult>();
648 } else {
649 return mWifiStateMachine.syncGetScanResultsList();
650 }
651 } finally {
652 Binder.restoreCallingIdentity(ident);
Irfan Sheriff330b1872012-09-16 12:27:57 -0700653 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 }
655
656 /**
657 * Tell the supplicant to persist the current list of configured networks.
658 * @return {@code true} if the operation succeeded
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700659 *
660 * TODO: deprecate this
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 */
662 public boolean saveConfiguration() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700663 boolean result = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800665 if (mWifiStateMachineChannel != null) {
666 return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700667 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800668 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700669 return false;
670 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 }
672
673 /**
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700674 * Set the country code
675 * @param countryCode ISO 3166 country code.
Robert Greenwaltb5010cc2009-05-21 15:11:40 -0700676 * @param persist {@code true} if the setting should be remembered.
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700677 *
678 * The persist behavior exists so that wifi can fall back to the last
679 * persisted country code on a restart, when the locale information is
680 * not available from telephony.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 */
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700682 public void setCountryCode(String countryCode, boolean persist) {
683 Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
684 " with persist set to " + persist);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 enforceChangePermission();
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700686 mWifiStateMachine.setCountryCode(countryCode, persist);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 }
688
689 /**
Irfan Sheriff36f74132010-11-04 16:57:37 -0700690 * Set the operational frequency band
691 * @param band One of
692 * {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
693 * {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
694 * {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
695 * @param persist {@code true} if the setting should be remembered.
696 *
697 */
698 public void setFrequencyBand(int band, boolean persist) {
699 enforceChangePermission();
700 if (!isDualBandSupported()) return;
701 Slog.i(TAG, "WifiService trying to set frequency band to " + band +
702 " with persist set to " + persist);
703 mWifiStateMachine.setFrequencyBand(band, persist);
704 }
705
706
707 /**
708 * Get the operational frequency band
709 */
710 public int getFrequencyBand() {
711 enforceAccessPermission();
712 return mWifiStateMachine.getFrequencyBand();
713 }
714
715 public boolean isDualBandSupported() {
716 //TODO: Should move towards adding a driver API that checks at runtime
717 return mContext.getResources().getBoolean(
718 com.android.internal.R.bool.config_wifi_dual_band_support);
719 }
720
721 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722 * Return the DHCP-assigned addresses from the last successful DHCP request,
723 * if any.
724 * @return the DHCP information
Robert Greenwalt4717c262012-10-31 14:32:53 -0700725 * @deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 */
727 public DhcpInfo getDhcpInfo() {
728 enforceAccessPermission();
Robert Greenwalt4717c262012-10-31 14:32:53 -0700729 DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults();
730 if (dhcpResults.linkProperties == null) return null;
731
732 DhcpInfo info = new DhcpInfo();
733 for (LinkAddress la : dhcpResults.linkProperties.getLinkAddresses()) {
734 InetAddress addr = la.getAddress();
735 if (addr instanceof Inet4Address) {
736 info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address)addr);
737 break;
738 }
739 }
740 for (RouteInfo r : dhcpResults.linkProperties.getRoutes()) {
741 if (r.isDefaultRoute()) {
742 InetAddress gateway = r.getGateway();
743 if (gateway instanceof Inet4Address) {
744 info.gateway = NetworkUtils.inetAddressToInt((Inet4Address)gateway);
745 }
746 } else if (r.isHostRoute()) {
747 LinkAddress dest = r.getDestination();
748 if (dest.getAddress() instanceof Inet4Address) {
749 info.netmask = NetworkUtils.prefixLengthToNetmaskInt(
750 dest.getNetworkPrefixLength());
751 }
752 }
753 }
754 int dnsFound = 0;
755 for (InetAddress dns : dhcpResults.linkProperties.getDnses()) {
756 if (dns instanceof Inet4Address) {
757 if (dnsFound == 0) {
758 info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
759 } else {
760 info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
761 }
762 if (++dnsFound > 1) break;
763 }
764 }
765 InetAddress serverAddress = dhcpResults.serverAddress;
766 if (serverAddress instanceof Inet4Address) {
767 info.serverAddress = NetworkUtils.inetAddressToInt((Inet4Address)serverAddress);
768 }
769 info.leaseDuration = dhcpResults.leaseDuration;
770
771 return info;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 }
773
Irfan Sheriff0d255342010-07-28 09:35:20 -0700774 /**
775 * see {@link android.net.wifi.WifiManager#startWifi}
776 *
777 */
778 public void startWifi() {
Irfan Sheriffda6da092012-08-16 12:49:23 -0700779 enforceConnectivityInternalPermission();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700780 /* TODO: may be add permissions for access only to connectivity service
781 * TODO: if a start issued, keep wifi alive until a stop issued irrespective
782 * of WifiLock & device idle status unless wifi enabled status is toggled
783 */
784
Irfan Sheriff4494c902011-12-08 10:47:54 -0800785 mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode);
Irfan Sheriff0d255342010-07-28 09:35:20 -0700786 mWifiStateMachine.reconnectCommand();
787 }
788
Irfan Sheriffda6da092012-08-16 12:49:23 -0700789 public void captivePortalCheckComplete() {
790 enforceConnectivityInternalPermission();
791 mWifiStateMachine.captivePortalCheckComplete();
792 }
793
Irfan Sheriff0d255342010-07-28 09:35:20 -0700794 /**
795 * see {@link android.net.wifi.WifiManager#stopWifi}
796 *
797 */
798 public void stopWifi() {
Irfan Sheriffda6da092012-08-16 12:49:23 -0700799 enforceConnectivityInternalPermission();
800 /*
Irfan Sheriff0d255342010-07-28 09:35:20 -0700801 * TODO: if a stop is issued, wifi is brought up only by startWifi
802 * unless wifi enabled status is toggled
803 */
Irfan Sheriff4494c902011-12-08 10:47:54 -0800804 mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode);
Irfan Sheriff0d255342010-07-28 09:35:20 -0700805 }
806
Irfan Sheriff0d255342010-07-28 09:35:20 -0700807 /**
808 * see {@link android.net.wifi.WifiManager#addToBlacklist}
809 *
810 */
811 public void addToBlacklist(String bssid) {
812 enforceChangePermission();
813
814 mWifiStateMachine.addToBlacklist(bssid);
815 }
816
817 /**
818 * see {@link android.net.wifi.WifiManager#clearBlacklist}
819 *
820 */
821 public void clearBlacklist() {
822 enforceChangePermission();
823
824 mWifiStateMachine.clearBlacklist();
825 }
826
Irfan Sheriff227bec42011-02-15 19:30:27 -0800827 /**
828 * Get a reference to handler. This is used by a client to establish
829 * an AsyncChannel communication with WifiService
830 */
Irfan Sheriff07573b32012-01-27 21:00:19 -0800831 public Messenger getWifiServiceMessenger() {
Irfan Sheriff35bbe272012-08-23 16:57:43 -0700832 enforceAccessPermission();
833 enforceChangePermission();
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800834 return new Messenger(mClientHandler);
Irfan Sheriff227bec42011-02-15 19:30:27 -0800835 }
836
Irfan Sheriff07573b32012-01-27 21:00:19 -0800837 /** Get a reference to WifiStateMachine handler for AsyncChannel communication */
838 public Messenger getWifiStateMachineMessenger() {
839 enforceAccessPermission();
840 enforceChangePermission();
841 return mWifiStateMachine.getMessenger();
842 }
843
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800844 /**
845 * Get the IP and proxy configuration file
846 */
847 public String getConfigFile() {
848 enforceAccessPermission();
849 return mWifiStateMachine.getConfigFile();
850 }
851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
853 @Override
854 public void onReceive(Context context, Intent intent) {
855 String action = intent.getAction();
856
Doug Zongker43866e02010-01-07 12:09:54 -0800857 long idleMillis =
Christopher Tate6f5a9a92012-09-14 17:24:28 -0700858 Settings.Global.getLong(mContext.getContentResolver(),
859 Settings.Global.WIFI_IDLE_MS, DEFAULT_IDLE_MS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860 int stayAwakeConditions =
Christopher Tate6f5a9a92012-09-14 17:24:28 -0700861 Settings.Global.getInt(mContext.getContentResolver(),
862 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Joe Onorato431bb222010-10-18 19:13:23 -0400864 if (DBG) {
865 Slog.d(TAG, "ACTION_SCREEN_ON");
866 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 mAlarmManager.cancel(mIdleIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 mScreenOff = false;
Irfan Sheriffe6daca52011-11-03 15:46:50 -0700869 setDeviceIdleAndUpdateWifi(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Joe Onorato431bb222010-10-18 19:13:23 -0400871 if (DBG) {
872 Slog.d(TAG, "ACTION_SCREEN_OFF");
873 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 mScreenOff = true;
875 /*
876 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
877 * AND the "stay on while plugged in" setting doesn't match the
878 * current power conditions (i.e, not plugged in, plugged in to USB,
879 * or plugged in to AC).
880 */
881 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
Irfan Sheriffe6daca52011-11-03 15:46:50 -0700882 //Delayed shutdown if wifi is connected
883 if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
884 if (DBG) Slog.d(TAG, "setting ACTION_DEVICE_IDLE: " + idleMillis + " ms");
885 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
886 + idleMillis, mIdleIntent);
Mike Lockwoodd9c32bc2009-05-18 14:14:15 -0400887 } else {
Irfan Sheriffe6daca52011-11-03 15:46:50 -0700888 setDeviceIdleAndUpdateWifi(true);
Mike Lockwoodd9c32bc2009-05-18 14:14:15 -0400889 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891 } else if (action.equals(ACTION_DEVICE_IDLE)) {
Irfan Sheriffe6daca52011-11-03 15:46:50 -0700892 setDeviceIdleAndUpdateWifi(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
894 /*
895 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
896 * AND we are transitioning from a state in which the device was supposed
897 * to stay awake to a state in which it is not supposed to stay awake.
898 * If "stay awake" state is not changing, we do nothing, to avoid resetting
899 * the already-set timer.
900 */
901 int pluggedType = intent.getIntExtra("plugged", 0);
Joe Onorato431bb222010-10-18 19:13:23 -0400902 if (DBG) {
903 Slog.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType);
904 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) &&
906 !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) {
907 long triggerTime = System.currentTimeMillis() + idleMillis;
Joe Onorato431bb222010-10-18 19:13:23 -0400908 if (DBG) {
909 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
910 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 }
Irfan Sheriff8cef0672011-12-13 17:03:59 -0800913
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 mPluggedType = pluggedType;
Irfan Sheriff65eaec82011-01-05 22:00:16 -0800915 } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
916 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
917 BluetoothAdapter.STATE_DISCONNECTED);
918 mWifiStateMachine.sendBluetoothAdapterStateChange(state);
Irfan Sheriff616f3172011-09-11 19:59:01 -0700919 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
920 mEmergencyCallbackMode = intent.getBooleanExtra("phoneinECMState", false);
921 updateWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 }
924
925 /**
926 * Determines whether the Wi-Fi chipset should stay awake or be put to
927 * sleep. Looks at the setting for the sleep policy and the current
928 * conditions.
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800929 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930 * @see #shouldDeviceStayAwake(int, int)
931 */
932 private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) {
Irfan Sheriff739f6bc2011-01-28 16:43:12 -0800933 //Never sleep as long as the user has not changed the settings
Brian Muramatsu35d323a2012-09-20 19:52:34 -0700934 int wifiSleepPolicy = Settings.Global.getInt(mContext.getContentResolver(),
935 Settings.Global.WIFI_SLEEP_POLICY,
936 Settings.Global.WIFI_SLEEP_POLICY_NEVER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937
Brian Muramatsu35d323a2012-09-20 19:52:34 -0700938 if (wifiSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 // Never sleep
940 return true;
Brian Muramatsu35d323a2012-09-20 19:52:34 -0700941 } else if ((wifiSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) &&
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 (pluggedType != 0)) {
943 // Never sleep while plugged, and we're plugged
944 return true;
945 } else {
946 // Default
947 return shouldDeviceStayAwake(stayAwakeConditions, pluggedType);
948 }
949 }
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800950
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800951 /**
952 * Determine whether the bit value corresponding to {@code pluggedType} is set in
953 * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value
954 * of {@code 0} isn't really a plugged type, but rather an indication that the
955 * device isn't plugged in at all, there is no bit value corresponding to a
956 * {@code pluggedType} value of {@code 0}. That is why we shift by
Ben Dodson4e8620f2010-08-25 10:55:47 -0700957 * {@code pluggedType - 1} instead of by {@code pluggedType}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 * @param stayAwakeConditions a bit string specifying which "plugged types" should
959 * keep the device (and hence Wi-Fi) awake.
960 * @param pluggedType the type of plug (USB, AC, or none) for which the check is
961 * being made
962 * @return {@code true} if {@code pluggedType} indicates that the device is
963 * supposed to stay awake, {@code false} otherwise.
964 */
965 private boolean shouldDeviceStayAwake(int stayAwakeConditions, int pluggedType) {
966 return (stayAwakeConditions & pluggedType) != 0;
967 }
968 };
969
Irfan Sheriffe6daca52011-11-03 15:46:50 -0700970 private void setDeviceIdleAndUpdateWifi(boolean deviceIdle) {
971 mDeviceIdle = deviceIdle;
972 reportStartWorkSource();
973 updateWifiState();
974 }
975
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700976 private synchronized void reportStartWorkSource() {
977 mTmpWorkSource.clear();
978 if (mDeviceIdle) {
979 for (int i=0; i<mLocks.mList.size(); i++) {
980 mTmpWorkSource.add(mLocks.mList.get(i).mWorkSource);
Dianne Hackborn58e0eef2010-09-16 01:22:10 -0700981 }
Dianne Hackborn58e0eef2010-09-16 01:22:10 -0700982 }
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700983 mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource);
Dianne Hackborn58e0eef2010-09-16 01:22:10 -0700984 }
Jaikumar Ganesh7440fc22010-09-27 17:04:14 -0700985
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 private void updateWifiState() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 boolean lockHeld = mLocks.hasLocks();
Irfan Sheriff5876a422010-08-12 20:26:23 -0700988 int strongestLockMode = WifiManager.WIFI_MODE_FULL;
Irfan Sheriff616f3172011-09-11 19:59:01 -0700989 boolean wifiShouldBeStarted;
990
991 if (mEmergencyCallbackMode) {
992 wifiShouldBeStarted = false;
993 } else {
994 wifiShouldBeStarted = !mDeviceIdle || lockHeld;
995 }
Irfan Sheriff5876a422010-08-12 20:26:23 -0700996
997 if (lockHeld) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 strongestLockMode = mLocks.getStrongestLockMode();
Irfan Sheriff5876a422010-08-12 20:26:23 -0700999 }
1000 /* If device is not idle, lockmode cannot be scan only */
1001 if (!mDeviceIdle && strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002 strongestLockMode = WifiManager.WIFI_MODE_FULL;
1003 }
1004
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001005 /* Disable tethering when airplane mode is enabled */
Irfan Sheriffb8c0e002013-02-20 14:19:54 -08001006 if (mSettingsStore.isAirplaneModeOn()) {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001007 mWifiStateMachine.setWifiApEnabled(null, false);
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001008 }
Irfan Sheriffb2e6c012010-04-05 11:57:56 -07001009
Irfan Sheriffb8c0e002013-02-20 14:19:54 -08001010 if (mSettingsStore.shouldWifiBeEnabled()) {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001011 if (wifiShouldBeStarted) {
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001012 reportStartWorkSource();
Irfan Sheriff0d255342010-07-28 09:35:20 -07001013 mWifiStateMachine.setWifiEnabled(true);
1014 mWifiStateMachine.setScanOnlyMode(
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001015 strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
Irfan Sheriff4494c902011-12-08 10:47:54 -08001016 mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode);
Irfan Sheriff5876a422010-08-12 20:26:23 -07001017 mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode
1018 == WifiManager.WIFI_MODE_FULL_HIGH_PERF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 } else {
Irfan Sheriff4494c902011-12-08 10:47:54 -08001020 mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 }
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001022 } else {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001023 mWifiStateMachine.setWifiEnabled(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 }
1025 }
1026
1027 private void registerForBroadcasts() {
1028 IntentFilter intentFilter = new IntentFilter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
1030 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
1031 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
1032 intentFilter.addAction(ACTION_DEVICE_IDLE);
Irfan Sheriff65eaec82011-01-05 22:00:16 -08001033 intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
Irfan Sheriff616f3172011-09-11 19:59:01 -07001034 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 mContext.registerReceiver(mReceiver, intentFilter);
1036 }
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001037
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001038 @Override
1039 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1040 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1041 != PackageManager.PERMISSION_GRANTED) {
1042 pw.println("Permission Denial: can't dump WifiService from from pid="
1043 + Binder.getCallingPid()
1044 + ", uid=" + Binder.getCallingUid());
1045 return;
1046 }
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001047 pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 pw.println("Stay-awake conditions: " +
Christopher Tatec09cdce2012-09-10 16:50:14 -07001049 Settings.Global.getInt(mContext.getContentResolver(),
1050 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
Irfan Sherifff0afe412012-11-30 14:07:44 -08001051 pw.println("mScreenOff " + mScreenOff);
1052 pw.println("mDeviceIdle " + mDeviceIdle);
1053 pw.println("mPluggedType " + mPluggedType);
1054 pw.println("mEmergencyCallbackMode " + mEmergencyCallbackMode);
1055 pw.println("mMulticastEnabled " + mMulticastEnabled);
1056 pw.println("mMulticastDisabled " + mMulticastDisabled);
Irfan Sheriffb8c0e002013-02-20 14:19:54 -08001057 mSettingsStore.dump(fd, pw, args);
1058 mNotificationController.dump(fd, pw, args);
1059 mTrafficPoller.dump(fd, pw, args);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 pw.println("Latest scan results:");
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001062 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001063 if (scanResults != null && scanResults.size() != 0) {
1064 pw.println(" BSSID Frequency RSSI Flags SSID");
1065 for (ScanResult r : scanResults) {
1066 pw.printf(" %17s %9d %5d %-16s %s%n",
1067 r.BSSID,
1068 r.frequency,
1069 r.level,
1070 r.capabilities,
1071 r.SSID == null ? "" : r.SSID);
1072 }
1073 }
1074 pw.println();
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001075 pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
Irfan Sheriff5876a422010-08-12 20:26:23 -07001076 mFullHighPerfLocksAcquired + " full high perf, " +
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001077 mScanLocksAcquired + " scan");
1078 pw.println("Locks released: " + mFullLocksReleased + " full, " +
Irfan Sheriff5876a422010-08-12 20:26:23 -07001079 mFullHighPerfLocksReleased + " full high perf, " +
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001080 mScanLocksReleased + " scan");
1081 pw.println();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 pw.println("Locks held:");
1083 mLocks.dump(pw);
Isaac Levybc7dfb52011-06-06 15:34:01 -07001084
Irfan Sherifff0afe412012-11-30 14:07:44 -08001085 mWifiWatchdogStateMachine.dump(fd, pw, args);
Isaac Levybc7dfb52011-06-06 15:34:01 -07001086 pw.println();
Irfan Sheriff60792372012-04-16 16:47:10 -07001087 mWifiStateMachine.dump(fd, pw, args);
Irfan Sherifff0afe412012-11-30 14:07:44 -08001088 pw.println();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 }
1090
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001091 private class WifiLock extends DeathRecipient {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001092 WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
1093 super(lockMode, tag, binder, ws);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 }
1095
1096 public void binderDied() {
1097 synchronized (mLocks) {
1098 releaseWifiLockLocked(mBinder);
1099 }
1100 }
1101
1102 public String toString() {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001103 return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 }
1105 }
1106
1107 private class LockList {
1108 private List<WifiLock> mList;
1109
1110 private LockList() {
1111 mList = new ArrayList<WifiLock>();
1112 }
1113
1114 private synchronized boolean hasLocks() {
1115 return !mList.isEmpty();
1116 }
1117
1118 private synchronized int getStrongestLockMode() {
1119 if (mList.isEmpty()) {
1120 return WifiManager.WIFI_MODE_FULL;
1121 }
Irfan Sheriff5876a422010-08-12 20:26:23 -07001122
1123 if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
1124 return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 }
Irfan Sheriff5876a422010-08-12 20:26:23 -07001126
1127 if (mFullLocksAcquired > mFullLocksReleased) {
1128 return WifiManager.WIFI_MODE_FULL;
1129 }
1130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 return WifiManager.WIFI_MODE_SCAN_ONLY;
1132 }
1133
1134 private void addLock(WifiLock lock) {
1135 if (findLockByBinder(lock.mBinder) < 0) {
1136 mList.add(lock);
1137 }
1138 }
1139
1140 private WifiLock removeLock(IBinder binder) {
1141 int index = findLockByBinder(binder);
1142 if (index >= 0) {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001143 WifiLock ret = mList.remove(index);
1144 ret.unlinkDeathRecipient();
1145 return ret;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 } else {
1147 return null;
1148 }
1149 }
1150
1151 private int findLockByBinder(IBinder binder) {
1152 int size = mList.size();
1153 for (int i = size - 1; i >= 0; i--)
1154 if (mList.get(i).mBinder == binder)
1155 return i;
1156 return -1;
1157 }
1158
1159 private void dump(PrintWriter pw) {
1160 for (WifiLock l : mList) {
1161 pw.print(" ");
1162 pw.println(l);
1163 }
1164 }
1165 }
1166
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001167 void enforceWakeSourcePermission(int uid, int pid) {
Dianne Hackborne746f032010-09-13 16:02:57 -07001168 if (uid == android.os.Process.myUid()) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001169 return;
1170 }
1171 mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
1172 pid, uid, null);
1173 }
1174
1175 public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
Irfan Sheriff5876a422010-08-12 20:26:23 -07001177 if (lockMode != WifiManager.WIFI_MODE_FULL &&
1178 lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
1179 lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
1180 Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
1181 if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 return false;
1183 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001184 if (ws != null && ws.size() == 0) {
1185 ws = null;
1186 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001187 if (ws != null) {
1188 enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
1189 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001190 if (ws == null) {
1191 ws = new WorkSource(Binder.getCallingUid());
1192 }
1193 WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194 synchronized (mLocks) {
1195 return acquireWifiLockLocked(wifiLock);
1196 }
1197 }
1198
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001199 private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
1200 switch(wifiLock.mMode) {
1201 case WifiManager.WIFI_MODE_FULL:
Irfan Sheriff5876a422010-08-12 20:26:23 -07001202 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001203 case WifiManager.WIFI_MODE_SCAN_ONLY:
Nick Pelly6ccaa542012-06-15 15:22:47 -07001204 mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001205 break;
1206 }
1207 }
1208
1209 private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
1210 switch(wifiLock.mMode) {
1211 case WifiManager.WIFI_MODE_FULL:
Irfan Sheriff5876a422010-08-12 20:26:23 -07001212 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001213 case WifiManager.WIFI_MODE_SCAN_ONLY:
Nick Pelly6ccaa542012-06-15 15:22:47 -07001214 mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001215 break;
1216 }
1217 }
1218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 private boolean acquireWifiLockLocked(WifiLock wifiLock) {
Irfan Sheriffc89dd542010-09-28 08:40:54 -07001220 if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 mLocks.addLock(wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001223
The Android Open Source Project10592532009-03-18 17:39:46 -07001224 long ident = Binder.clearCallingIdentity();
1225 try {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001226 noteAcquireWifiLock(wifiLock);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001227 switch(wifiLock.mMode) {
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001228 case WifiManager.WIFI_MODE_FULL:
1229 ++mFullLocksAcquired;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001230 break;
Irfan Sheriff5876a422010-08-12 20:26:23 -07001231 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1232 ++mFullHighPerfLocksAcquired;
1233 break;
1234
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001235 case WifiManager.WIFI_MODE_SCAN_ONLY:
1236 ++mScanLocksAcquired;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001237 break;
The Android Open Source Project10592532009-03-18 17:39:46 -07001238 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001239
1240 // Be aggressive about adding new locks into the accounted state...
1241 // we want to over-report rather than under-report.
1242 reportStartWorkSource();
1243
1244 updateWifiState();
1245 return true;
The Android Open Source Project10592532009-03-18 17:39:46 -07001246 } catch (RemoteException e) {
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001247 return false;
The Android Open Source Project10592532009-03-18 17:39:46 -07001248 } finally {
1249 Binder.restoreCallingIdentity(ident);
1250 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251 }
1252
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001253 public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
1254 int uid = Binder.getCallingUid();
1255 int pid = Binder.getCallingPid();
1256 if (ws != null && ws.size() == 0) {
1257 ws = null;
1258 }
1259 if (ws != null) {
1260 enforceWakeSourcePermission(uid, pid);
1261 }
1262 long ident = Binder.clearCallingIdentity();
1263 try {
1264 synchronized (mLocks) {
1265 int index = mLocks.findLockByBinder(lock);
1266 if (index < 0) {
1267 throw new IllegalArgumentException("Wifi lock not active");
1268 }
1269 WifiLock wl = mLocks.mList.get(index);
1270 noteReleaseWifiLock(wl);
1271 wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
1272 noteAcquireWifiLock(wl);
1273 }
1274 } catch (RemoteException e) {
1275 } finally {
1276 Binder.restoreCallingIdentity(ident);
1277 }
1278 }
1279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 public boolean releaseWifiLock(IBinder lock) {
1281 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1282 synchronized (mLocks) {
1283 return releaseWifiLockLocked(lock);
1284 }
1285 }
1286
1287 private boolean releaseWifiLockLocked(IBinder lock) {
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001288 boolean hadLock;
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001289
The Android Open Source Project10592532009-03-18 17:39:46 -07001290 WifiLock wifiLock = mLocks.removeLock(lock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001291
Irfan Sheriffc89dd542010-09-28 08:40:54 -07001292 if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001293
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001294 hadLock = (wifiLock != null);
1295
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001296 long ident = Binder.clearCallingIdentity();
1297 try {
1298 if (hadLock) {
Wink Savillece0ea1f2011-10-13 16:55:20 -07001299 noteReleaseWifiLock(wifiLock);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001300 switch(wifiLock.mMode) {
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001301 case WifiManager.WIFI_MODE_FULL:
1302 ++mFullLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001303 break;
Irfan Sheriff5876a422010-08-12 20:26:23 -07001304 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1305 ++mFullHighPerfLocksReleased;
1306 break;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001307 case WifiManager.WIFI_MODE_SCAN_ONLY:
1308 ++mScanLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001309 break;
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001310 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001311 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001312
1313 // TODO - should this only happen if you hadLock?
1314 updateWifiState();
1315
1316 } catch (RemoteException e) {
1317 } finally {
1318 Binder.restoreCallingIdentity(ident);
The Android Open Source Project10592532009-03-18 17:39:46 -07001319 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001320
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001321 return hadLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001323
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001324 private abstract class DeathRecipient
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001325 implements IBinder.DeathRecipient {
1326 String mTag;
1327 int mMode;
1328 IBinder mBinder;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001329 WorkSource mWorkSource;
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001330
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001331 DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001332 super();
1333 mTag = tag;
1334 mMode = mode;
1335 mBinder = binder;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001336 mWorkSource = ws;
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001337 try {
1338 mBinder.linkToDeath(this, 0);
1339 } catch (RemoteException e) {
1340 binderDied();
1341 }
1342 }
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001343
1344 void unlinkDeathRecipient() {
1345 mBinder.unlinkToDeath(this, 0);
1346 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001347 }
1348
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001349 private class Multicaster extends DeathRecipient {
1350 Multicaster(String tag, IBinder binder) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001351 super(Binder.getCallingUid(), tag, binder, null);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001352 }
1353
1354 public void binderDied() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001355 Slog.e(TAG, "Multicaster binderDied");
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001356 synchronized (mMulticasters) {
1357 int i = mMulticasters.indexOf(this);
1358 if (i != -1) {
1359 removeMulticasterLocked(i, mMode);
1360 }
1361 }
1362 }
1363
1364 public String toString() {
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001365 return "Multicaster{" + mTag + " binder=" + mBinder + "}";
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001366 }
1367
1368 public int getUid() {
1369 return mMode;
1370 }
1371 }
1372
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001373 public void initializeMulticastFiltering() {
1374 enforceMulticastChangePermission();
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001375
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001376 synchronized (mMulticasters) {
1377 // if anybody had requested filters be off, leave off
1378 if (mMulticasters.size() != 0) {
1379 return;
1380 } else {
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001381 mWifiStateMachine.startFilteringMulticastV4Packets();
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001382 }
1383 }
1384 }
1385
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -07001386 public void acquireMulticastLock(IBinder binder, String tag) {
1387 enforceMulticastChangePermission();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001388
1389 synchronized (mMulticasters) {
1390 mMulticastEnabled++;
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001391 mMulticasters.add(new Multicaster(tag, binder));
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001392 // Note that we could call stopFilteringMulticastV4Packets only when
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001393 // our new size == 1 (first call), but this function won't
1394 // be called often and by making the stopPacket call each
1395 // time we're less fragile and self-healing.
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001396 mWifiStateMachine.stopFilteringMulticastV4Packets();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001397 }
1398
1399 int uid = Binder.getCallingUid();
You Kim2bea5852012-10-23 22:56:51 +09001400 final long ident = Binder.clearCallingIdentity();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001401 try {
1402 mBatteryStats.noteWifiMulticastEnabled(uid);
1403 } catch (RemoteException e) {
1404 } finally {
1405 Binder.restoreCallingIdentity(ident);
1406 }
1407 }
1408
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -07001409 public void releaseMulticastLock() {
1410 enforceMulticastChangePermission();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001411
1412 int uid = Binder.getCallingUid();
1413 synchronized (mMulticasters) {
1414 mMulticastDisabled++;
1415 int size = mMulticasters.size();
1416 for (int i = size - 1; i >= 0; i--) {
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001417 Multicaster m = mMulticasters.get(i);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001418 if ((m != null) && (m.getUid() == uid)) {
1419 removeMulticasterLocked(i, uid);
1420 }
1421 }
1422 }
1423 }
1424
1425 private void removeMulticasterLocked(int i, int uid)
1426 {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001427 Multicaster removed = mMulticasters.remove(i);
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001428
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001429 if (removed != null) {
1430 removed.unlinkDeathRecipient();
1431 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001432 if (mMulticasters.size() == 0) {
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001433 mWifiStateMachine.startFilteringMulticastV4Packets();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001434 }
1435
You Kim2bea5852012-10-23 22:56:51 +09001436 final long ident = Binder.clearCallingIdentity();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001437 try {
1438 mBatteryStats.noteWifiMulticastDisabled(uid);
1439 } catch (RemoteException e) {
1440 } finally {
1441 Binder.restoreCallingIdentity(ident);
1442 }
1443 }
1444
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001445 public boolean isMulticastEnabled() {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001446 enforceAccessPermission();
1447
1448 synchronized (mMulticasters) {
1449 return (mMulticasters.size() > 0);
1450 }
1451 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001452}