blob: 15080b2f25b3f86228921b14423cc4b519aab65c [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
17package com.android.server;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.AlarmManager;
20import android.app.PendingIntent;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -070021import android.bluetooth.BluetoothA2dp;
Jaikumar Ganesh084c6652009-12-07 10:58:18 -080022import android.bluetooth.BluetoothDevice;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.content.BroadcastReceiver;
24import android.content.ContentResolver;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.pm.PackageManager;
29import android.net.wifi.IWifiManager;
30import android.net.wifi.WifiInfo;
31import android.net.wifi.WifiManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.net.wifi.WifiStateTracker;
33import android.net.wifi.ScanResult;
34import android.net.wifi.WifiConfiguration;
San Mehat0310f9a2009-07-07 10:49:47 -070035import android.net.wifi.SupplicantState;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080036import android.net.wifi.WifiConfiguration.KeyMgmt;
Irfan Sheriff5321aef2010-02-12 12:35:59 -080037import android.net.ConnectivityManager;
38import android.net.InterfaceConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.net.NetworkStateTracker;
40import android.net.DhcpInfo;
41import android.os.Binder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.os.HandlerThread;
43import android.os.IBinder;
Irfan Sheriff5321aef2010-02-12 12:35:59 -080044import android.os.INetworkManagementService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.RemoteException;
Amith Yamasani47873e52009-07-02 12:05:32 -070046import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.provider.Settings;
Joe Onorato8a9b2202010-02-26 18:56:32 -080048import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049
50import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import java.util.List;
Jaikumar Ganesh084c6652009-12-07 10:58:18 -080052import java.util.Set;
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070053import java.util.concurrent.atomic.AtomicBoolean;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import java.io.FileDescriptor;
55import java.io.PrintWriter;
56
The Android Open Source Project10592532009-03-18 17:39:46 -070057import com.android.internal.app.IBatteryStats;
The Android Open Source Project10592532009-03-18 17:39:46 -070058import com.android.server.am.BatteryStatsService;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080059import com.android.internal.R;
The Android Open Source Project10592532009-03-18 17:39:46 -070060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061/**
62 * WifiService handles remote WiFi operation requests by implementing
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070063 * the IWifiManager interface.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064 *
65 * @hide
66 */
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070067//TODO: Clean up multiple locks and implement WifiService
68// as a SM to track soft AP/client/adhoc bring up based
69// on device idle state, airplane mode and boot.
70
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071public class WifiService extends IWifiManager.Stub {
72 private static final String TAG = "WifiService";
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070073 private static final boolean DBG = true;
74
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 private final WifiStateTracker mWifiStateTracker;
76
77 private Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078
79 private AlarmManager mAlarmManager;
80 private PendingIntent mIdleIntent;
81 private static final int IDLE_REQUEST = 0;
82 private boolean mScreenOff;
83 private boolean mDeviceIdle;
84 private int mPluggedType;
85
Mike Lockwoodbd5ddf02009-07-29 21:37:14 -070086 // true if the user enabled Wifi while in airplane mode
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070087 private AtomicBoolean mAirplaneModeOverwridden = new AtomicBoolean(false);
Mike Lockwoodbd5ddf02009-07-29 21:37:14 -070088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 private final LockList mLocks = new LockList();
Eric Shienbrood5711fad2009-03-27 20:25:31 -070090 // some wifi lock statistics
91 private int mFullLocksAcquired;
92 private int mFullLocksReleased;
93 private int mScanLocksAcquired;
94 private int mScanLocksReleased;
The Android Open Source Project10592532009-03-18 17:39:46 -070095
Robert Greenwalt58ff0212009-05-19 15:53:54 -070096 private final List<Multicaster> mMulticasters =
97 new ArrayList<Multicaster>();
Robert Greenwalt5347bd42009-05-13 15:10:16 -070098 private int mMulticastEnabled;
99 private int mMulticastDisabled;
100
The Android Open Source Project10592532009-03-18 17:39:46 -0700101 private final IBatteryStats mBatteryStats;
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800102
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800103 ConnectivityManager mCm;
104 private String[] mWifiRegexs;
105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 /**
Doug Zongker43866e02010-01-07 12:09:54 -0800107 * See {@link Settings.Secure#WIFI_IDLE_MS}. This is the default value if a
108 * Settings.Secure value is not present. This timeout value is chosen as
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 * the approximate point at which the battery drain caused by Wi-Fi
110 * being enabled but not active exceeds the battery drain caused by
111 * re-establishing a connection to the mobile data network.
112 */
113 private static final long DEFAULT_IDLE_MILLIS = 15 * 60 * 1000; /* 15 minutes */
114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 /**
116 * Number of allowed radio frequency channels in various regulatory domains.
117 * This list is sufficient for 802.11b/g networks (2.4GHz range).
118 */
119 private static int[] sValidRegulatoryChannelCounts = new int[] {11, 13, 14};
120
121 private static final String ACTION_DEVICE_IDLE =
122 "com.android.server.WifiManager.action.DEVICE_IDLE";
123
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700124 private boolean mIsReceiverRegistered = false;
125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 WifiService(Context context, WifiStateTracker tracker) {
127 mContext = context;
128 mWifiStateTracker = tracker;
Mike Lockwoodf32be162009-07-14 17:44:37 -0400129 mWifiStateTracker.enableRssiPolling(true);
The Android Open Source Project10592532009-03-18 17:39:46 -0700130 mBatteryStats = BatteryStatsService.getService();
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800131
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
133 Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
134 mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
135
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700136 HandlerThread wifiThread = new HandlerThread("WifiService");
137 wifiThread.start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 mContext.registerReceiver(
140 new BroadcastReceiver() {
141 @Override
142 public void onReceive(Context context, Intent intent) {
Mike Lockwoodbd5ddf02009-07-29 21:37:14 -0700143 // clear our flag indicating the user has overwridden airplane mode
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700144 mAirplaneModeOverwridden.set(false);
Irfan Sheriffb2e6c012010-04-05 11:57:56 -0700145 // on airplane disable, restore Wifi if the saved state indicates so
146 if (!isAirplaneModeOn() && testAndClearWifiSavedState()) {
147 persistWifiEnabled(true);
148 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 updateWifiState();
150 }
151 },
152 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
153
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800154 mContext.registerReceiver(
155 new BroadcastReceiver() {
156 @Override
157 public void onReceive(Context context, Intent intent) {
158
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700159 ArrayList<String> available = intent.getStringArrayListExtra(
160 ConnectivityManager.EXTRA_AVAILABLE_TETHER);
161 ArrayList<String> active = intent.getStringArrayListExtra(
162 ConnectivityManager.EXTRA_ACTIVE_TETHER);
163 updateTetherState(available, active);
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800164
165 }
166 },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
Irfan Sheriff7b009782010-03-11 16:37:45 -0800167 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800168
Irfan Sheriff7b009782010-03-11 16:37:45 -0800169 /**
170 * Check if Wi-Fi needs to be enabled and start
171 * if needed
Irfan Sheriff60e3ba02010-04-02 12:18:45 -0700172 *
173 * This function is used only at boot time
Irfan Sheriff7b009782010-03-11 16:37:45 -0800174 */
175 public void startWifi() {
Irfan Sheriffa3bd4092010-03-24 17:58:59 -0700176 /* Start if Wi-Fi is enabled or the saved state indicates Wi-Fi was on */
Irfan Sheriff60e3ba02010-04-02 12:18:45 -0700177 boolean wifiEnabled = !isAirplaneModeOn()
178 && (getPersistedWifiEnabled() || testAndClearWifiSavedState());
Irfan Sheriff7b009782010-03-11 16:37:45 -0800179 Slog.i(TAG, "WifiService starting up with Wi-Fi " +
180 (wifiEnabled ? "enabled" : "disabled"));
Irfan Sheriffb99fe5e2010-03-26 14:56:07 -0700181 setWifiEnabled(wifiEnabled);
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800182 }
183
184 private void updateTetherState(ArrayList<String> available, ArrayList<String> tethered) {
185
186 boolean wifiTethered = false;
187 boolean wifiAvailable = false;
188
189 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
190 INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
191
Robert Greenwalt14f2ef42010-06-15 12:19:37 -0700192 if (mCm == null) {
193 mCm = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
194 }
195
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800196 mWifiRegexs = mCm.getTetherableWifiRegexs();
197
198 for (String intf : available) {
199 for (String regex : mWifiRegexs) {
200 if (intf.matches(regex)) {
201
202 InterfaceConfiguration ifcg = null;
203 try {
204 ifcg = service.getInterfaceConfig(intf);
205 if (ifcg != null) {
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700206 /* IP/netmask: 192.168.43.1/255.255.255.0 */
207 ifcg.ipAddr = (192 << 24) + (168 << 16) + (43 << 8) + 1;
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800208 ifcg.netmask = (255 << 24) + (255 << 16) + (255 << 8) + 0;
209 ifcg.interfaceFlags = "up";
210
211 service.setInterfaceConfig(intf, ifcg);
212 }
213 } catch (Exception e) {
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800214 Slog.e(TAG, "Error configuring interface " + intf + ", :" + e);
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700215 setWifiApEnabled(null, false);
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800216 return;
217 }
218
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800219 if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700220 Slog.e(TAG, "Error tethering on " + intf);
221 setWifiApEnabled(null, false);
222 return;
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800223 }
224 break;
225 }
226 }
227 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 }
229
Irfan Sheriffa3bd4092010-03-24 17:58:59 -0700230 private boolean testAndClearWifiSavedState() {
231 final ContentResolver cr = mContext.getContentResolver();
232 int wifiSavedState = 0;
233 try {
234 wifiSavedState = Settings.Secure.getInt(cr, Settings.Secure.WIFI_SAVED_STATE);
235 if(wifiSavedState == 1)
236 Settings.Secure.putInt(cr, Settings.Secure.WIFI_SAVED_STATE, 0);
237 } catch (Settings.SettingNotFoundException e) {
238 ;
239 }
240 return (wifiSavedState == 1);
241 }
242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 private boolean getPersistedWifiEnabled() {
244 final ContentResolver cr = mContext.getContentResolver();
245 try {
246 return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON) == 1;
247 } catch (Settings.SettingNotFoundException e) {
248 Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, 0);
249 return false;
250 }
251 }
252
253 private void persistWifiEnabled(boolean enabled) {
254 final ContentResolver cr = mContext.getContentResolver();
255 Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, enabled ? 1 : 0);
256 }
257
258 NetworkStateTracker getNetworkStateTracker() {
259 return mWifiStateTracker;
260 }
261
262 /**
263 * see {@link android.net.wifi.WifiManager#pingSupplicant()}
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700264 * @return {@code true} if the operation succeeds, {@code false} otherwise
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 */
266 public boolean pingSupplicant() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700267 enforceAccessPermission();
268 return mWifiStateTracker.pingSupplicant();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 }
270
271 /**
272 * see {@link android.net.wifi.WifiManager#startScan()}
273 * @return {@code true} if the operation succeeds
274 */
Mike Lockwooda5ec95c2009-07-08 17:11:17 -0400275 public boolean startScan(boolean forceActive) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 enforceChangePermission();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700277 return mWifiStateTracker.startScan(forceActive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 }
279
280 private void enforceAccessPermission() {
281 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
282 "WifiService");
283 }
284
285 private void enforceChangePermission() {
286 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
287 "WifiService");
288
289 }
290
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -0700291 private void enforceMulticastChangePermission() {
292 mContext.enforceCallingOrSelfPermission(
293 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
294 "WifiService");
295 }
296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700298 * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
299 * @param enable {@code true} to enable, {@code false} to disable.
300 * @return {@code true} if the enable/disable operation was
301 * started or is already in the queue.
302 */
303 public synchronized boolean setWifiEnabled(boolean enable) {
304 enforceChangePermission();
305
306 if (DBG) {
307 Slog.e(TAG, "Invoking mWifiStateTracker.setWifiEnabled\n");
308 }
309
310 // set a flag if the user is enabling Wifi while in airplane mode
311 if (enable && isAirplaneModeOn() && isAirplaneToggleable()) {
312 mAirplaneModeOverwridden.set(true);
313 }
314
315 mWifiStateTracker.setWifiEnabled(enable);
316 persistWifiEnabled(enable);
317
318 if (enable) {
319 if (!mIsReceiverRegistered) {
320 registerForBroadcasts();
321 mIsReceiverRegistered = true;
322 }
323 } else if (mIsReceiverRegistered){
324 mContext.unregisterReceiver(mReceiver);
325 mIsReceiverRegistered = false;
326 }
327
328 return true;
329 }
330
331 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 * see {@link WifiManager#getWifiState()}
333 * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
334 * {@link WifiManager#WIFI_STATE_DISABLING},
335 * {@link WifiManager#WIFI_STATE_ENABLED},
336 * {@link WifiManager#WIFI_STATE_ENABLING},
337 * {@link WifiManager#WIFI_STATE_UNKNOWN}
338 */
339 public int getWifiEnabledState() {
340 enforceAccessPermission();
Irfan Sheriff0f344060092010-03-10 10:05:51 -0800341 return mWifiStateTracker.getWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 }
343
344 /**
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700345 * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800346 * @param wifiConfig SSID, security and channel details as
347 * part of WifiConfiguration
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700348 * @param enabled true to enable and false to disable
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800349 * @return {@code true} if the start operation was
350 * started or is already in the queue.
351 */
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700352 public synchronized boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800353 enforceChangePermission();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800354
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700355 if (enabled) {
356 /* Use default config if there is no existing config */
357 if (wifiConfig == null && ((wifiConfig = getWifiApConfiguration()) == null)) {
358 wifiConfig = new WifiConfiguration();
359 wifiConfig.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default);
360 wifiConfig.allowedKeyManagement.set(KeyMgmt.NONE);
361 }
362 setWifiApConfiguration(wifiConfig);
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800363 }
364
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700365 mWifiStateTracker.setWifiApEnabled(wifiConfig, enabled);
366
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800367 return true;
368 }
369
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700370 /**
371 * see {@link WifiManager#getWifiApState()}
372 * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
373 * {@link WifiManager#WIFI_AP_STATE_DISABLING},
374 * {@link WifiManager#WIFI_AP_STATE_ENABLED},
375 * {@link WifiManager#WIFI_AP_STATE_ENABLING},
376 * {@link WifiManager#WIFI_AP_STATE_FAILED}
377 */
378 public int getWifiApEnabledState() {
Irfan Sheriff17b232b2010-06-24 11:32:26 -0700379 enforceAccessPermission();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700380 return mWifiStateTracker.getWifiApState();
381 }
382
383 /**
384 * see {@link WifiManager#getWifiApConfiguration()}
385 * @return soft access point configuration
386 */
387 public synchronized WifiConfiguration getWifiApConfiguration() {
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800388 final ContentResolver cr = mContext.getContentResolver();
389 WifiConfiguration wifiConfig = new WifiConfiguration();
390 int authType;
391 try {
392 wifiConfig.SSID = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_SSID);
393 if (wifiConfig.SSID == null)
394 return null;
395 authType = Settings.Secure.getInt(cr, Settings.Secure.WIFI_AP_SECURITY);
396 wifiConfig.allowedKeyManagement.set(authType);
397 wifiConfig.preSharedKey = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_PASSWD);
398 return wifiConfig;
399 } catch (Settings.SettingNotFoundException e) {
400 Slog.e(TAG,"AP settings not found, returning");
401 return null;
402 }
403 }
404
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700405 /**
406 * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
407 * @param wifiConfig WifiConfiguration details for soft access point
408 */
409 public synchronized void setWifiApConfiguration(WifiConfiguration wifiConfig) {
Irfan Sheriff17b232b2010-06-24 11:32:26 -0700410 enforceChangePermission();
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800411 final ContentResolver cr = mContext.getContentResolver();
412 boolean isWpa;
413 if (wifiConfig == null)
414 return;
415 Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_SSID, wifiConfig.SSID);
416 isWpa = wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK);
417 Settings.Secure.putInt(cr,
418 Settings.Secure.WIFI_AP_SECURITY,
419 isWpa ? KeyMgmt.WPA_PSK : KeyMgmt.NONE);
420 if (isWpa)
421 Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_PASSWD, wifiConfig.preSharedKey);
422 }
423
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800424 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700425 * see {@link android.net.wifi.WifiManager#disconnect()}
426 * @return {@code true} if the operation succeeds
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800427 */
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700428 public boolean disconnect() {
429 enforceChangePermission();
430 return mWifiStateTracker.disconnectCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800431 }
432
433 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700434 * see {@link android.net.wifi.WifiManager#reconnect()}
435 * @return {@code true} if the operation succeeds
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800436 */
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700437 public boolean reconnect() {
438 enforceChangePermission();
439 return mWifiStateTracker.reconnectCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800440 }
441
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700442 /**
443 * see {@link android.net.wifi.WifiManager#reassociate()}
444 * @return {@code true} if the operation succeeds
445 */
446 public boolean reassociate() {
447 enforceChangePermission();
448 return mWifiStateTracker.reassociateCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800449 }
450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 /**
452 * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
453 * @return the list of configured networks
454 */
455 public List<WifiConfiguration> getConfiguredNetworks() {
456 enforceAccessPermission();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700457 return mWifiStateTracker.getConfiguredNetworks();
Chung-yih Wanga8d15942009-10-09 11:01:49 +0800458 }
459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 /**
461 * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
462 * @return the supplicant-assigned identifier for the new or updated
463 * network if the operation succeeds, or {@code -1} if it fails
464 */
Irfan Sheriff7aac5542009-12-22 21:42:17 -0800465 public int addOrUpdateNetwork(WifiConfiguration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 enforceChangePermission();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700467 return mWifiStateTracker.addOrUpdateNetwork(config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 }
469
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700470 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
472 * @param netId the integer that identifies the network configuration
473 * to the supplicant
474 * @return {@code true} if the operation succeeded
475 */
476 public boolean removeNetwork(int netId) {
477 enforceChangePermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 return mWifiStateTracker.removeNetwork(netId);
479 }
480
481 /**
482 * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
483 * @param netId the integer that identifies the network configuration
484 * to the supplicant
485 * @param disableOthers if true, disable all other networks.
486 * @return {@code true} if the operation succeeded
487 */
488 public boolean enableNetwork(int netId, boolean disableOthers) {
489 enforceChangePermission();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700490 return mWifiStateTracker.enableNetwork(netId, disableOthers);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 }
492
493 /**
494 * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
495 * @param netId the integer that identifies the network configuration
496 * to the supplicant
497 * @return {@code true} if the operation succeeded
498 */
499 public boolean disableNetwork(int netId) {
500 enforceChangePermission();
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -0800501 return mWifiStateTracker.disableNetwork(netId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 }
503
504 /**
505 * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
506 * @return the Wi-Fi information, contained in {@link WifiInfo}.
507 */
508 public WifiInfo getConnectionInfo() {
509 enforceAccessPermission();
510 /*
511 * Make sure we have the latest information, by sending
512 * a status request to the supplicant.
513 */
514 return mWifiStateTracker.requestConnectionInfo();
515 }
516
517 /**
518 * Return the results of the most recent access point scan, in the form of
519 * a list of {@link ScanResult} objects.
520 * @return the list of results
521 */
522 public List<ScanResult> getScanResults() {
523 enforceAccessPermission();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700524 return mWifiStateTracker.getScanResultsList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 }
526
527 /**
528 * Tell the supplicant to persist the current list of configured networks.
529 * @return {@code true} if the operation succeeded
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700530 *
531 * TODO: deprecate this
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 */
533 public boolean saveConfiguration() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700534 boolean result = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 enforceChangePermission();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700536 return mWifiStateTracker.saveConfig();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 }
538
539 /**
540 * Set the number of radio frequency channels that are allowed to be used
541 * in the current regulatory domain. This method should be used only
542 * if the correct number of channels cannot be determined automatically
Robert Greenwaltb5010cc2009-05-21 15:11:40 -0700543 * for some reason. If the operation is successful, the new value may be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 * persisted as a Secure setting.
545 * @param numChannels the number of allowed channels. Must be greater than 0
546 * and less than or equal to 16.
Robert Greenwaltb5010cc2009-05-21 15:11:40 -0700547 * @param persist {@code true} if the setting should be remembered.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 * @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
549 * {@code numChannels} is outside the valid range.
550 */
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700551 public synchronized boolean setNumAllowedChannels(int numChannels, boolean persist) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800552 Slog.i(TAG, "WifiService trying to setNumAllowed to "+numChannels+
Robert Greenwaltb5010cc2009-05-21 15:11:40 -0700553 " with persist set to "+persist);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 enforceChangePermission();
Irfan Sheriff59610c02010-03-30 11:00:41 -0700555
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 /*
557 * Validate the argument. We'd like to let the Wi-Fi driver do this,
558 * but if Wi-Fi isn't currently enabled, that's not possible, and
559 * we want to persist the setting anyway,so that it will take
560 * effect when Wi-Fi does become enabled.
561 */
562 boolean found = false;
563 for (int validChan : sValidRegulatoryChannelCounts) {
564 if (validChan == numChannels) {
565 found = true;
566 break;
567 }
568 }
569 if (!found) {
570 return false;
571 }
572
Robert Greenwaltb5010cc2009-05-21 15:11:40 -0700573 if (persist) {
574 Settings.Secure.putInt(mContext.getContentResolver(),
Irfan Sheriff59610c02010-03-30 11:00:41 -0700575 Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
576 numChannels);
Robert Greenwaltb5010cc2009-05-21 15:11:40 -0700577 }
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700578
579 mWifiStateTracker.setNumAllowedChannels(numChannels);
580
581 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 }
583
584 /**
585 * Return the number of frequency channels that are allowed
586 * to be used in the current regulatory domain.
587 * @return the number of allowed channels, or {@code -1} if an error occurs
588 */
589 public int getNumAllowedChannels() {
590 int numChannels;
591
592 enforceAccessPermission();
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -0800593
594 /*
595 * If we can't get the value from the driver (e.g., because
596 * Wi-Fi is not currently enabled), get the value from
597 * Settings.
598 */
599 numChannels = mWifiStateTracker.getNumAllowedChannels();
600 if (numChannels < 0) {
601 numChannels = Settings.Secure.getInt(mContext.getContentResolver(),
602 Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
603 -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 }
605 return numChannels;
606 }
607
608 /**
609 * Return the list of valid values for the number of allowed radio channels
610 * for various regulatory domains.
611 * @return the list of channel counts
612 */
613 public int[] getValidChannelCounts() {
614 enforceAccessPermission();
615 return sValidRegulatoryChannelCounts;
616 }
617
618 /**
619 * Return the DHCP-assigned addresses from the last successful DHCP request,
620 * if any.
621 * @return the DHCP information
622 */
623 public DhcpInfo getDhcpInfo() {
624 enforceAccessPermission();
625 return mWifiStateTracker.getDhcpInfo();
626 }
627
628 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
629 @Override
630 public void onReceive(Context context, Intent intent) {
631 String action = intent.getAction();
632
Doug Zongker43866e02010-01-07 12:09:54 -0800633 long idleMillis =
634 Settings.Secure.getLong(mContext.getContentResolver(),
635 Settings.Secure.WIFI_IDLE_MS, DEFAULT_IDLE_MILLIS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 int stayAwakeConditions =
Doug Zongker43866e02010-01-07 12:09:54 -0800637 Settings.System.getInt(mContext.getContentResolver(),
638 Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800640 Slog.d(TAG, "ACTION_SCREEN_ON");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 mAlarmManager.cancel(mIdleIntent);
642 mDeviceIdle = false;
643 mScreenOff = false;
Mike Lockwoodf32be162009-07-14 17:44:37 -0400644 mWifiStateTracker.enableRssiPolling(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800646 Slog.d(TAG, "ACTION_SCREEN_OFF");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 mScreenOff = true;
Mike Lockwoodf32be162009-07-14 17:44:37 -0400648 mWifiStateTracker.enableRssiPolling(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800649 /*
650 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
651 * AND the "stay on while plugged in" setting doesn't match the
652 * current power conditions (i.e, not plugged in, plugged in to USB,
653 * or plugged in to AC).
654 */
655 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
San Mehatfa6c7112009-07-07 09:34:44 -0700656 WifiInfo info = mWifiStateTracker.requestConnectionInfo();
657 if (info.getSupplicantState() != SupplicantState.COMPLETED) {
Robert Greenwalt84612ea62009-09-30 09:04:22 -0700658 // we used to go to sleep immediately, but this caused some race conditions
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700659 // we don't have time to track down for this release. Delay instead,
660 // but not as long as we would if connected (below)
Robert Greenwalt84612ea62009-09-30 09:04:22 -0700661 // TODO - fix the race conditions and switch back to the immediate turn-off
662 long triggerTime = System.currentTimeMillis() + (2*60*1000); // 2 min
Joe Onorato8a9b2202010-02-26 18:56:32 -0800663 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for 120,000 ms");
Robert Greenwalt84612ea62009-09-30 09:04:22 -0700664 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
665 // // do not keep Wifi awake when screen is off if Wifi is not associated
666 // mDeviceIdle = true;
667 // updateWifiState();
Mike Lockwoodd9c32bc2009-05-18 14:14:15 -0400668 } else {
669 long triggerTime = System.currentTimeMillis() + idleMillis;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800670 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
Mike Lockwoodd9c32bc2009-05-18 14:14:15 -0400671 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
672 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 }
674 /* we can return now -- there's nothing to do until we get the idle intent back */
675 return;
676 } else if (action.equals(ACTION_DEVICE_IDLE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800677 Slog.d(TAG, "got ACTION_DEVICE_IDLE");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 mDeviceIdle = true;
679 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
680 /*
681 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
682 * AND we are transitioning from a state in which the device was supposed
683 * to stay awake to a state in which it is not supposed to stay awake.
684 * If "stay awake" state is not changing, we do nothing, to avoid resetting
685 * the already-set timer.
686 */
687 int pluggedType = intent.getIntExtra("plugged", 0);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800688 Slog.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689 if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) &&
690 !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) {
691 long triggerTime = System.currentTimeMillis() + idleMillis;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800692 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
694 mPluggedType = pluggedType;
695 return;
696 }
697 mPluggedType = pluggedType;
Nick Pelly005b2282009-09-10 10:21:56 -0700698 } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800699 BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
700 Set<BluetoothDevice> sinks = a2dp.getConnectedSinks();
701 boolean isBluetoothPlaying = false;
702 for (BluetoothDevice sink : sinks) {
703 if (a2dp.getSinkState(sink) == BluetoothA2dp.STATE_PLAYING) {
704 isBluetoothPlaying = true;
705 }
706 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700707 mWifiStateTracker.setBluetoothScanMode(isBluetoothPlaying);
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800708
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709 } else {
710 return;
711 }
712
713 updateWifiState();
714 }
715
716 /**
717 * Determines whether the Wi-Fi chipset should stay awake or be put to
718 * sleep. Looks at the setting for the sleep policy and the current
719 * conditions.
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800720 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 * @see #shouldDeviceStayAwake(int, int)
722 */
723 private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) {
724 int wifiSleepPolicy = Settings.System.getInt(mContext.getContentResolver(),
725 Settings.System.WIFI_SLEEP_POLICY, Settings.System.WIFI_SLEEP_POLICY_DEFAULT);
726
727 if (wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER) {
728 // Never sleep
729 return true;
730 } else if ((wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) &&
731 (pluggedType != 0)) {
732 // Never sleep while plugged, and we're plugged
733 return true;
734 } else {
735 // Default
736 return shouldDeviceStayAwake(stayAwakeConditions, pluggedType);
737 }
738 }
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800739
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 /**
741 * Determine whether the bit value corresponding to {@code pluggedType} is set in
742 * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value
743 * of {@code 0} isn't really a plugged type, but rather an indication that the
744 * device isn't plugged in at all, there is no bit value corresponding to a
745 * {@code pluggedType} value of {@code 0}. That is why we shift by
746 * {@code pluggedType&nbsp;&#8212;&nbsp;1} instead of by {@code pluggedType}.
747 * @param stayAwakeConditions a bit string specifying which "plugged types" should
748 * keep the device (and hence Wi-Fi) awake.
749 * @param pluggedType the type of plug (USB, AC, or none) for which the check is
750 * being made
751 * @return {@code true} if {@code pluggedType} indicates that the device is
752 * supposed to stay awake, {@code false} otherwise.
753 */
754 private boolean shouldDeviceStayAwake(int stayAwakeConditions, int pluggedType) {
755 return (stayAwakeConditions & pluggedType) != 0;
756 }
757 };
758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 private void updateWifiState() {
760 boolean wifiEnabled = getPersistedWifiEnabled();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700761 boolean airplaneMode = isAirplaneModeOn() && !mAirplaneModeOverwridden.get();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 boolean lockHeld = mLocks.hasLocks();
763 int strongestLockMode;
764 boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;
765 boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
766 if (mDeviceIdle && lockHeld) {
767 strongestLockMode = mLocks.getStrongestLockMode();
768 } else {
769 strongestLockMode = WifiManager.WIFI_MODE_FULL;
770 }
771
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700772 /* Disable tethering when airplane mode is enabled */
773 if (airplaneMode) {
774 mWifiStateTracker.setWifiApEnabled(null, false);
775 }
Irfan Sheriffb2e6c012010-04-05 11:57:56 -0700776
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700777 if (wifiShouldBeEnabled) {
778 if (wifiShouldBeStarted) {
779 mWifiStateTracker.setWifiEnabled(true);
780 mWifiStateTracker.setScanOnlyMode(
781 strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
782 mWifiStateTracker.startWifi(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 } else {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700784 mWifiStateTracker.requestCmWakeLock();
785 mWifiStateTracker.disconnectAndStop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 }
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700787 } else {
788 mWifiStateTracker.setWifiEnabled(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 }
790 }
791
792 private void registerForBroadcasts() {
793 IntentFilter intentFilter = new IntentFilter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
795 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
796 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
797 intentFilter.addAction(ACTION_DEVICE_IDLE);
Nick Pelly005b2282009-09-10 10:21:56 -0700798 intentFilter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 mContext.registerReceiver(mReceiver, intentFilter);
800 }
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 private boolean isAirplaneSensitive() {
803 String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
804 Settings.System.AIRPLANE_MODE_RADIOS);
805 return airplaneModeRadios == null
806 || airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
807 }
808
Mike Lockwoodbd5ddf02009-07-29 21:37:14 -0700809 private boolean isAirplaneToggleable() {
810 String toggleableRadios = Settings.System.getString(mContext.getContentResolver(),
811 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
812 return toggleableRadios != null
813 && toggleableRadios.contains(Settings.System.RADIO_WIFI);
814 }
815
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 /**
817 * Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is
818 * currently on.
819 * @return {@code true} if airplane mode is on.
820 */
821 private boolean isAirplaneModeOn() {
822 return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(),
823 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
824 }
825
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 @Override
827 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
828 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
829 != PackageManager.PERMISSION_GRANTED) {
830 pw.println("Permission Denial: can't dump WifiService from from pid="
831 + Binder.getCallingPid()
832 + ", uid=" + Binder.getCallingUid());
833 return;
834 }
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700835 pw.println("Wi-Fi is " + mWifiStateTracker.getWifiStateByName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 pw.println("Stay-awake conditions: " +
837 Settings.System.getInt(mContext.getContentResolver(),
838 Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
839 pw.println();
840
841 pw.println("Internal state:");
842 pw.println(mWifiStateTracker);
843 pw.println();
844 pw.println("Latest scan results:");
845 List<ScanResult> scanResults = mWifiStateTracker.getScanResultsList();
846 if (scanResults != null && scanResults.size() != 0) {
847 pw.println(" BSSID Frequency RSSI Flags SSID");
848 for (ScanResult r : scanResults) {
849 pw.printf(" %17s %9d %5d %-16s %s%n",
850 r.BSSID,
851 r.frequency,
852 r.level,
853 r.capabilities,
854 r.SSID == null ? "" : r.SSID);
855 }
856 }
857 pw.println();
Eric Shienbrood5711fad2009-03-27 20:25:31 -0700858 pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
859 mScanLocksAcquired + " scan");
860 pw.println("Locks released: " + mFullLocksReleased + " full, " +
861 mScanLocksReleased + " scan");
862 pw.println();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863 pw.println("Locks held:");
864 mLocks.dump(pw);
865 }
866
Robert Greenwalt58ff0212009-05-19 15:53:54 -0700867 private class WifiLock extends DeathRecipient {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 WifiLock(int lockMode, String tag, IBinder binder) {
Robert Greenwalt5347bd42009-05-13 15:10:16 -0700869 super(lockMode, tag, binder);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870 }
871
872 public void binderDied() {
873 synchronized (mLocks) {
874 releaseWifiLockLocked(mBinder);
875 }
876 }
877
878 public String toString() {
Robert Greenwalt5347bd42009-05-13 15:10:16 -0700879 return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880 }
881 }
882
883 private class LockList {
884 private List<WifiLock> mList;
885
886 private LockList() {
887 mList = new ArrayList<WifiLock>();
888 }
889
890 private synchronized boolean hasLocks() {
891 return !mList.isEmpty();
892 }
893
894 private synchronized int getStrongestLockMode() {
895 if (mList.isEmpty()) {
896 return WifiManager.WIFI_MODE_FULL;
897 }
898 for (WifiLock l : mList) {
Robert Greenwalt5347bd42009-05-13 15:10:16 -0700899 if (l.mMode == WifiManager.WIFI_MODE_FULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900 return WifiManager.WIFI_MODE_FULL;
901 }
902 }
903 return WifiManager.WIFI_MODE_SCAN_ONLY;
904 }
905
906 private void addLock(WifiLock lock) {
907 if (findLockByBinder(lock.mBinder) < 0) {
908 mList.add(lock);
909 }
910 }
911
912 private WifiLock removeLock(IBinder binder) {
913 int index = findLockByBinder(binder);
914 if (index >= 0) {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -0700915 WifiLock ret = mList.remove(index);
916 ret.unlinkDeathRecipient();
917 return ret;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918 } else {
919 return null;
920 }
921 }
922
923 private int findLockByBinder(IBinder binder) {
924 int size = mList.size();
925 for (int i = size - 1; i >= 0; i--)
926 if (mList.get(i).mBinder == binder)
927 return i;
928 return -1;
929 }
930
931 private void dump(PrintWriter pw) {
932 for (WifiLock l : mList) {
933 pw.print(" ");
934 pw.println(l);
935 }
936 }
937 }
938
939 public boolean acquireWifiLock(IBinder binder, int lockMode, String tag) {
940 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
941 if (lockMode != WifiManager.WIFI_MODE_FULL && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY) {
942 return false;
943 }
944 WifiLock wifiLock = new WifiLock(lockMode, tag, binder);
945 synchronized (mLocks) {
946 return acquireWifiLockLocked(wifiLock);
947 }
948 }
949
950 private boolean acquireWifiLockLocked(WifiLock wifiLock) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800951 Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -0700952
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 mLocks.addLock(wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -0700954
The Android Open Source Project10592532009-03-18 17:39:46 -0700955 int uid = Binder.getCallingUid();
956 long ident = Binder.clearCallingIdentity();
957 try {
Robert Greenwalt5347bd42009-05-13 15:10:16 -0700958 switch(wifiLock.mMode) {
Eric Shienbrood5711fad2009-03-27 20:25:31 -0700959 case WifiManager.WIFI_MODE_FULL:
960 ++mFullLocksAcquired;
961 mBatteryStats.noteFullWifiLockAcquired(uid);
962 break;
963 case WifiManager.WIFI_MODE_SCAN_ONLY:
964 ++mScanLocksAcquired;
965 mBatteryStats.noteScanWifiLockAcquired(uid);
966 break;
The Android Open Source Project10592532009-03-18 17:39:46 -0700967 }
968 } catch (RemoteException e) {
969 } finally {
970 Binder.restoreCallingIdentity(ident);
971 }
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -0700972
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 updateWifiState();
974 return true;
975 }
976
977 public boolean releaseWifiLock(IBinder lock) {
978 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
979 synchronized (mLocks) {
980 return releaseWifiLockLocked(lock);
981 }
982 }
983
984 private boolean releaseWifiLockLocked(IBinder lock) {
Eric Shienbroodd4c5f892009-03-24 18:13:20 -0700985 boolean hadLock;
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -0700986
The Android Open Source Project10592532009-03-18 17:39:46 -0700987 WifiLock wifiLock = mLocks.removeLock(lock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -0700988
Joe Onorato8a9b2202010-02-26 18:56:32 -0800989 Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -0700990
Eric Shienbroodd4c5f892009-03-24 18:13:20 -0700991 hadLock = (wifiLock != null);
992
993 if (hadLock) {
994 int uid = Binder.getCallingUid();
995 long ident = Binder.clearCallingIdentity();
996 try {
Robert Greenwalt5347bd42009-05-13 15:10:16 -0700997 switch(wifiLock.mMode) {
Eric Shienbrood5711fad2009-03-27 20:25:31 -0700998 case WifiManager.WIFI_MODE_FULL:
999 ++mFullLocksReleased;
1000 mBatteryStats.noteFullWifiLockReleased(uid);
1001 break;
1002 case WifiManager.WIFI_MODE_SCAN_ONLY:
1003 ++mScanLocksReleased;
1004 mBatteryStats.noteScanWifiLockReleased(uid);
1005 break;
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001006 }
1007 } catch (RemoteException e) {
1008 } finally {
1009 Binder.restoreCallingIdentity(ident);
The Android Open Source Project10592532009-03-18 17:39:46 -07001010 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001011 }
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001012 // TODO - should this only happen if you hadLock?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 updateWifiState();
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001014 return hadLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001016
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001017 private abstract class DeathRecipient
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001018 implements IBinder.DeathRecipient {
1019 String mTag;
1020 int mMode;
1021 IBinder mBinder;
1022
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001023 DeathRecipient(int mode, String tag, IBinder binder) {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001024 super();
1025 mTag = tag;
1026 mMode = mode;
1027 mBinder = binder;
1028 try {
1029 mBinder.linkToDeath(this, 0);
1030 } catch (RemoteException e) {
1031 binderDied();
1032 }
1033 }
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001034
1035 void unlinkDeathRecipient() {
1036 mBinder.unlinkToDeath(this, 0);
1037 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001038 }
1039
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001040 private class Multicaster extends DeathRecipient {
1041 Multicaster(String tag, IBinder binder) {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001042 super(Binder.getCallingUid(), tag, binder);
1043 }
1044
1045 public void binderDied() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001046 Slog.e(TAG, "Multicaster binderDied");
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001047 synchronized (mMulticasters) {
1048 int i = mMulticasters.indexOf(this);
1049 if (i != -1) {
1050 removeMulticasterLocked(i, mMode);
1051 }
1052 }
1053 }
1054
1055 public String toString() {
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001056 return "Multicaster{" + mTag + " binder=" + mBinder + "}";
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001057 }
1058
1059 public int getUid() {
1060 return mMode;
1061 }
1062 }
1063
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001064 public void initializeMulticastFiltering() {
1065 enforceMulticastChangePermission();
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001066
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001067 synchronized (mMulticasters) {
1068 // if anybody had requested filters be off, leave off
1069 if (mMulticasters.size() != 0) {
1070 return;
1071 } else {
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001072 mWifiStateTracker.startPacketFiltering();
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001073 }
1074 }
1075 }
1076
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -07001077 public void acquireMulticastLock(IBinder binder, String tag) {
1078 enforceMulticastChangePermission();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001079
1080 synchronized (mMulticasters) {
1081 mMulticastEnabled++;
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001082 mMulticasters.add(new Multicaster(tag, binder));
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001083 // Note that we could call stopPacketFiltering only when
1084 // our new size == 1 (first call), but this function won't
1085 // be called often and by making the stopPacket call each
1086 // time we're less fragile and self-healing.
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001087 mWifiStateTracker.stopPacketFiltering();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001088 }
1089
1090 int uid = Binder.getCallingUid();
1091 Long ident = Binder.clearCallingIdentity();
1092 try {
1093 mBatteryStats.noteWifiMulticastEnabled(uid);
1094 } catch (RemoteException e) {
1095 } finally {
1096 Binder.restoreCallingIdentity(ident);
1097 }
1098 }
1099
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -07001100 public void releaseMulticastLock() {
1101 enforceMulticastChangePermission();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001102
1103 int uid = Binder.getCallingUid();
1104 synchronized (mMulticasters) {
1105 mMulticastDisabled++;
1106 int size = mMulticasters.size();
1107 for (int i = size - 1; i >= 0; i--) {
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001108 Multicaster m = mMulticasters.get(i);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001109 if ((m != null) && (m.getUid() == uid)) {
1110 removeMulticasterLocked(i, uid);
1111 }
1112 }
1113 }
1114 }
1115
1116 private void removeMulticasterLocked(int i, int uid)
1117 {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001118 Multicaster removed = mMulticasters.remove(i);
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001119
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001120 if (removed != null) {
1121 removed.unlinkDeathRecipient();
1122 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001123 if (mMulticasters.size() == 0) {
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001124 mWifiStateTracker.startPacketFiltering();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001125 }
1126
1127 Long ident = Binder.clearCallingIdentity();
1128 try {
1129 mBatteryStats.noteWifiMulticastDisabled(uid);
1130 } catch (RemoteException e) {
1131 } finally {
1132 Binder.restoreCallingIdentity(ident);
1133 }
1134 }
1135
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001136 public boolean isMulticastEnabled() {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001137 enforceAccessPermission();
1138
1139 synchronized (mMulticasters) {
1140 return (mMulticasters.size() > 0);
1141 }
1142 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143}