blob: adb63f9b8dcf1617ba96a149ac4ba10fef05c590 [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
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;
Irfan Sheriff0d255342010-07-28 09:35:20 -070021import android.app.Notification;
22import android.app.NotificationManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.app.PendingIntent;
Jaikumar Ganesh7440fc22010-09-27 17:04:14 -070024import android.bluetooth.BluetoothAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.BroadcastReceiver;
26import android.content.ContentResolver;
27import android.content.Context;
28import android.content.Intent;
29import android.content.IntentFilter;
30import android.content.pm.PackageManager;
Irfan Sheriff0d255342010-07-28 09:35:20 -070031import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.net.wifi.IWifiManager;
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -080033import android.net.wifi.ScanResult;
34import android.net.wifi.SupplicantState;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.net.wifi.WifiInfo;
36import android.net.wifi.WifiManager;
Irfan Sheriff0d255342010-07-28 09:35:20 -070037import android.net.wifi.WifiStateMachine;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.net.wifi.WifiConfiguration;
Isaac Levy654f5092011-07-13 17:41:45 -070039import android.net.wifi.WifiWatchdogStateMachine;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080040import android.net.wifi.WifiConfiguration.KeyMgmt;
Irfan Sheriff651cdfc2011-09-07 00:31:20 -070041import android.net.wifi.WpsInfo;
Irfan Sheriffe4c56c92011-01-12 16:33:58 -080042import android.net.wifi.WpsResult;
Irfan Sheriff5321aef2010-02-12 12:35:59 -080043import android.net.ConnectivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.net.DhcpInfo;
Irfan Sheriff0d255342010-07-28 09:35:20 -070045import android.net.NetworkInfo;
46import android.net.NetworkInfo.State;
Irfan Sheriff227bec42011-02-15 19:30:27 -080047import android.net.NetworkInfo.DetailedState;
48import android.net.TrafficStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.os.Binder;
Irfan Sheriff0d255342010-07-28 09:35:20 -070050import android.os.Handler;
Irfan Sheriff227bec42011-02-15 19:30:27 -080051import android.os.Messenger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.os.HandlerThread;
53import android.os.IBinder;
Irfan Sheriff5321aef2010-02-12 12:35:59 -080054import android.os.INetworkManagementService;
Irfan Sheriff0d255342010-07-28 09:35:20 -070055import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.os.RemoteException;
Amith Yamasani47873e52009-07-02 12:05:32 -070057import android.os.ServiceManager;
Irfan Sheriff227bec42011-02-15 19:30:27 -080058import android.os.SystemProperties;
Irfan Sheriff330b1872012-09-16 12:27:57 -070059import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070060import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.provider.Settings;
Irfan Sheriff0d255342010-07-28 09:35:20 -070062import android.text.TextUtils;
Nick Pelly6ccaa542012-06-15 15:22:47 -070063import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080064import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065
66import java.util.ArrayList;
Irfan Sheriff8cef0672011-12-13 17:03:59 -080067import java.util.HashMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068import java.util.List;
Jaikumar Ganesh084c6652009-12-07 10:58:18 -080069import java.util.Set;
Irfan Sheriff658772f2011-03-08 14:52:31 -080070import java.util.concurrent.atomic.AtomicInteger;
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070071import java.util.concurrent.atomic.AtomicBoolean;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import java.io.FileDescriptor;
73import java.io.PrintWriter;
74
The Android Open Source Project10592532009-03-18 17:39:46 -070075import com.android.internal.app.IBatteryStats;
Irfan Sheriff616f3172011-09-11 19:59:01 -070076import com.android.internal.telephony.TelephonyIntents;
Wink Saville4b7ba092010-10-20 15:37:41 -070077import com.android.internal.util.AsyncChannel;
The Android Open Source Project10592532009-03-18 17:39:46 -070078import com.android.server.am.BatteryStatsService;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080079import com.android.internal.R;
The Android Open Source Project10592532009-03-18 17:39:46 -070080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081/**
82 * WifiService handles remote WiFi operation requests by implementing
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070083 * the IWifiManager interface.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 *
85 * @hide
86 */
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070087//TODO: Clean up multiple locks and implement WifiService
88// as a SM to track soft AP/client/adhoc bring up based
89// on device idle state, airplane mode and boot.
90
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091public class WifiService extends IWifiManager.Stub {
92 private static final String TAG = "WifiService";
Dianne Hackborn5fd21692011-06-07 14:09:47 -070093 private static final boolean DBG = false;
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070094
Irfan Sheriff0d255342010-07-28 09:35:20 -070095 private final WifiStateMachine mWifiStateMachine;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096
97 private Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098
99 private AlarmManager mAlarmManager;
100 private PendingIntent mIdleIntent;
101 private static final int IDLE_REQUEST = 0;
102 private boolean mScreenOff;
103 private boolean mDeviceIdle;
Irfan Sheriff616f3172011-09-11 19:59:01 -0700104 private boolean mEmergencyCallbackMode = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 private int mPluggedType;
106
107 private final LockList mLocks = new LockList();
Eric Shienbrood5711fad2009-03-27 20:25:31 -0700108 // some wifi lock statistics
Irfan Sheriff5876a422010-08-12 20:26:23 -0700109 private int mFullHighPerfLocksAcquired;
110 private int mFullHighPerfLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -0700111 private int mFullLocksAcquired;
112 private int mFullLocksReleased;
113 private int mScanLocksAcquired;
114 private int mScanLocksReleased;
The Android Open Source Project10592532009-03-18 17:39:46 -0700115
Robert Greenwalt58ff0212009-05-19 15:53:54 -0700116 private final List<Multicaster> mMulticasters =
117 new ArrayList<Multicaster>();
Robert Greenwalt5347bd42009-05-13 15:10:16 -0700118 private int mMulticastEnabled;
119 private int mMulticastDisabled;
120
The Android Open Source Project10592532009-03-18 17:39:46 -0700121 private final IBatteryStats mBatteryStats;
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800122
Irfan Sheriff227bec42011-02-15 19:30:27 -0800123 private boolean mEnableTrafficStatsPoll = false;
124 private int mTrafficStatsPollToken = 0;
125 private long mTxPkts;
126 private long mRxPkts;
127 /* Tracks last reported data activity */
128 private int mDataActivity;
129 private String mInterfaceName;
130
131 /**
132 * Interval in milliseconds between polling for traffic
133 * statistics
134 */
135 private static final int POLL_TRAFFIC_STATS_INTERVAL_MSECS = 1000;
136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 /**
Christopher Tate6f5a9a92012-09-14 17:24:28 -0700138 * See {@link Settings.Global#WIFI_IDLE_MS}. This is the default value if a
139 * Settings.Global value is not present. This timeout value is chosen as
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 * the approximate point at which the battery drain caused by Wi-Fi
141 * being enabled but not active exceeds the battery drain caused by
142 * re-establishing a connection to the mobile data network.
143 */
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700144 private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */
145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 private static final String ACTION_DEVICE_IDLE =
147 "com.android.server.WifiManager.action.DEVICE_IDLE";
148
Irfan Sheriff658772f2011-03-08 14:52:31 -0800149 private static final int WIFI_DISABLED = 0;
150 private static final int WIFI_ENABLED = 1;
151 /* Wifi enabled while in airplane mode */
152 private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2;
Irfan Sheriff31b92e22011-10-03 12:13:20 -0700153 /* Wifi disabled due to airplane mode on */
154 private static final int WIFI_DISABLED_AIRPLANE_ON = 3;
Irfan Sheriff658772f2011-03-08 14:52:31 -0800155
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800156 /* Persisted state that tracks the wifi & airplane interaction from settings */
157 private AtomicInteger mPersistWifiState = new AtomicInteger(WIFI_DISABLED);
158 /* Tracks current airplane mode state */
Irfan Sheriff658772f2011-03-08 14:52:31 -0800159 private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false);
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800160 /* Tracks whether wifi is enabled from WifiStateMachine's perspective */
161 private boolean mWifiEnabled;
Irfan Sheriff658772f2011-03-08 14:52:31 -0800162
Nick Pelly6ccaa542012-06-15 15:22:47 -0700163 /* The work source (UID) that triggered the current WIFI scan, synchronized
164 * on this */
165 private WorkSource mScanWorkSource;
166
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700167 private boolean mIsReceiverRegistered = false;
168
Irfan Sheriff0d255342010-07-28 09:35:20 -0700169
170 NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
171
172 // Variables relating to the 'available networks' notification
173 /**
174 * The icon to show in the 'available networks' notification. This will also
175 * be the ID of the Notification given to the NotificationManager.
176 */
177 private static final int ICON_NETWORKS_AVAILABLE =
178 com.android.internal.R.drawable.stat_notify_wifi_in_range;
179 /**
180 * When a notification is shown, we wait this amount before possibly showing it again.
181 */
182 private final long NOTIFICATION_REPEAT_DELAY_MS;
183 /**
184 * Whether the user has set the setting to show the 'available networks' notification.
185 */
186 private boolean mNotificationEnabled;
187 /**
188 * Observes the user setting to keep {@link #mNotificationEnabled} in sync.
189 */
190 private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
191 /**
192 * The {@link System#currentTimeMillis()} must be at least this value for us
193 * to show the notification again.
194 */
195 private long mNotificationRepeatTime;
196 /**
197 * The Notification object given to the NotificationManager.
198 */
199 private Notification mNotification;
200 /**
201 * Whether the notification is being shown, as set by us. That is, if the
202 * user cancels the notification, we will not receive the callback so this
203 * will still be true. We only guarantee if this is false, then the
204 * notification is not showing.
205 */
206 private boolean mNotificationShown;
207 /**
208 * The number of continuous scans that must occur before consider the
209 * supplicant in a scanning state. This allows supplicant to associate with
210 * remembered networks that are in the scan results.
211 */
212 private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3;
213 /**
214 * The number of scans since the last network state change. When this
215 * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the
216 * supplicant to actually be scanning. When the network state changes to
217 * something other than scanning, we reset this to 0.
218 */
219 private int mNumScansSinceNetworkStateChange;
Jaikumar Ganesh7440fc22010-09-27 17:04:14 -0700220
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700221 /**
Wink Saville4b7ba092010-10-20 15:37:41 -0700222 * Asynchronous channel to WifiStateMachine
223 */
Irfan Sheriff227bec42011-02-15 19:30:27 -0800224 private AsyncChannel mWifiStateMachineChannel;
Wink Saville4b7ba092010-10-20 15:37:41 -0700225
226 /**
Irfan Sheriff227bec42011-02-15 19:30:27 -0800227 * Clients receiving asynchronous messages
Wink Saville4b7ba092010-10-20 15:37:41 -0700228 */
Irfan Sheriff227bec42011-02-15 19:30:27 -0800229 private List<AsyncChannel> mClients = new ArrayList<AsyncChannel>();
Wink Saville4b7ba092010-10-20 15:37:41 -0700230
Irfan Sheriff227bec42011-02-15 19:30:27 -0800231 /**
232 * Handles client connections
233 */
234 private class AsyncServiceHandler extends Handler {
235
236 AsyncServiceHandler(android.os.Looper looper) {
Wink Saville4b7ba092010-10-20 15:37:41 -0700237 super(looper);
Wink Saville4b7ba092010-10-20 15:37:41 -0700238 }
239
240 @Override
241 public void handleMessage(Message msg) {
242 switch (msg.what) {
243 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
244 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
Irfan Sheriff6bfc8882012-08-29 15:35:57 -0700245 if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
Irfan Sheriff227bec42011-02-15 19:30:27 -0800246 mClients.add((AsyncChannel) msg.obj);
Wink Saville4b7ba092010-10-20 15:37:41 -0700247 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800248 Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
249 }
250 break;
251 }
Irfan Sheriffc23971b2011-03-04 17:06:31 -0800252 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
253 if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
Irfan Sheriff6bfc8882012-08-29 15:35:57 -0700254 if (DBG) Slog.d(TAG, "Send failed, client connection lost");
Irfan Sheriffc23971b2011-03-04 17:06:31 -0800255 } else {
Irfan Sheriff6bfc8882012-08-29 15:35:57 -0700256 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
Irfan Sheriffc23971b2011-03-04 17:06:31 -0800257 }
258 mClients.remove((AsyncChannel) msg.obj);
259 break;
260 }
Irfan Sheriff227bec42011-02-15 19:30:27 -0800261 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
262 AsyncChannel ac = new AsyncChannel();
263 ac.connect(mContext, this, msg.replyTo);
264 break;
265 }
Irfan Sheriffd3975a92012-02-24 10:54:13 -0800266 case WifiManager.ENABLE_TRAFFIC_STATS_POLL: {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800267 mEnableTrafficStatsPoll = (msg.arg1 == 1);
268 mTrafficStatsPollToken++;
269 if (mEnableTrafficStatsPoll) {
270 notifyOnDataActivity();
Irfan Sheriffd3975a92012-02-24 10:54:13 -0800271 sendMessageDelayed(Message.obtain(this, WifiManager.TRAFFIC_STATS_POLL,
Irfan Sheriff227bec42011-02-15 19:30:27 -0800272 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
273 }
274 break;
275 }
Irfan Sheriffd3975a92012-02-24 10:54:13 -0800276 case WifiManager.TRAFFIC_STATS_POLL: {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800277 if (msg.arg1 == mTrafficStatsPollToken) {
278 notifyOnDataActivity();
Irfan Sheriffd3975a92012-02-24 10:54:13 -0800279 sendMessageDelayed(Message.obtain(this, WifiManager.TRAFFIC_STATS_POLL,
Irfan Sheriff227bec42011-02-15 19:30:27 -0800280 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
Wink Saville4b7ba092010-10-20 15:37:41 -0700281 }
282 break;
283 }
Irfan Sheriffd3975a92012-02-24 10:54:13 -0800284 case WifiManager.CONNECT_NETWORK: {
285 mWifiStateMachine.sendMessage(Message.obtain(msg));
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800286 break;
287 }
Irfan Sheriffd3975a92012-02-24 10:54:13 -0800288 case WifiManager.SAVE_NETWORK: {
289 mWifiStateMachine.sendMessage(Message.obtain(msg));
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800290 break;
291 }
Irfan Sheriffd3975a92012-02-24 10:54:13 -0800292 case WifiManager.FORGET_NETWORK: {
293 mWifiStateMachine.sendMessage(Message.obtain(msg));
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800294 break;
295 }
Irfan Sheriffd3975a92012-02-24 10:54:13 -0800296 case WifiManager.START_WPS: {
297 mWifiStateMachine.sendMessage(Message.obtain(msg));
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800298 break;
299 }
Irfan Sheriff86a5f5b2012-02-28 17:03:56 -0800300 case WifiManager.CANCEL_WPS: {
301 mWifiStateMachine.sendMessage(Message.obtain(msg));
302 break;
303 }
Irfan Sheriffd3975a92012-02-24 10:54:13 -0800304 case WifiManager.DISABLE_NETWORK: {
305 mWifiStateMachine.sendMessage(Message.obtain(msg));
Isaac Levy8dc6a1b2011-07-27 08:00:03 -0700306 break;
307 }
Yuhao Zhengf6307822012-08-14 14:21:25 -0700308 case WifiManager.RSSI_PKTCNT_FETCH: {
309 mWifiStateMachine.sendMessage(Message.obtain(msg));
310 break;
311 }
Wink Saville4b7ba092010-10-20 15:37:41 -0700312 default: {
313 Slog.d(TAG, "WifiServicehandler.handleMessage ignoring msg=" + msg);
314 break;
315 }
316 }
317 }
318 }
Irfan Sheriff227bec42011-02-15 19:30:27 -0800319 private AsyncServiceHandler mAsyncServiceHandler;
320
321 /**
322 * Handles interaction with WifiStateMachine
323 */
324 private class WifiStateMachineHandler extends Handler {
325 private AsyncChannel mWsmChannel;
326
327 WifiStateMachineHandler(android.os.Looper looper) {
328 super(looper);
329 mWsmChannel = new AsyncChannel();
330 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
331 }
332
333 @Override
334 public void handleMessage(Message msg) {
335 switch (msg.what) {
336 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
337 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
338 mWifiStateMachineChannel = mWsmChannel;
339 } else {
340 Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1);
341 mWifiStateMachineChannel = null;
342 }
343 break;
344 }
Irfan Sheriff6da83d52011-06-06 12:54:06 -0700345 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
346 Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1);
347 mWifiStateMachineChannel = null;
348 //Re-establish connection to state machine
349 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
350 break;
351 }
Irfan Sheriff227bec42011-02-15 19:30:27 -0800352 default: {
353 Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg);
354 break;
355 }
356 }
357 }
358 }
359 WifiStateMachineHandler mWifiStateMachineHandler;
Wink Saville4b7ba092010-10-20 15:37:41 -0700360
361 /**
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700362 * Temporary for computing UIDS that are responsible for starting WIFI.
363 * Protected by mWifiStateTracker lock.
364 */
365 private final WorkSource mTmpWorkSource = new WorkSource();
Isaac Levy654f5092011-07-13 17:41:45 -0700366 private WifiWatchdogStateMachine mWifiWatchdogStateMachine;
Irfan Sheriff0d255342010-07-28 09:35:20 -0700367
368 WifiService(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 mContext = context;
Irfan Sheriff227bec42011-02-15 19:30:27 -0800370
371 mInterfaceName = SystemProperties.get("wifi.interface", "wlan0");
372
373 mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName);
Irfan Sheriff0d255342010-07-28 09:35:20 -0700374 mWifiStateMachine.enableRssiPolling(true);
The Android Open Source Project10592532009-03-18 17:39:46 -0700375 mBatteryStats = BatteryStatsService.getService();
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800376
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
378 Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
379 mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 mContext.registerReceiver(
382 new BroadcastReceiver() {
383 @Override
384 public void onReceive(Context context, Intent intent) {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800385 mAirplaneModeOn.set(isAirplaneModeOn());
Irfan Sheriff42d73bb2012-05-17 14:14:44 -0700386 handleAirplaneModeToggled(mAirplaneModeOn.get());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 updateWifiState();
388 }
389 },
390 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
391
Irfan Sheriff0d255342010-07-28 09:35:20 -0700392 IntentFilter filter = new IntentFilter();
393 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
394 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
395 filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
396
397 mContext.registerReceiver(
398 new BroadcastReceiver() {
399 @Override
400 public void onReceive(Context context, Intent intent) {
401 if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800402 int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
403 WifiManager.WIFI_STATE_DISABLED);
404
405 mWifiEnabled = (wifiState == WifiManager.WIFI_STATE_ENABLED);
406
407 // reset & clear notification on any wifi state change
Irfan Sheriff0d255342010-07-28 09:35:20 -0700408 resetNotification();
409 } else if (intent.getAction().equals(
410 WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
411 mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
412 WifiManager.EXTRA_NETWORK_INFO);
413 // reset & clear notification on a network connect & disconnect
414 switch(mNetworkInfo.getDetailedState()) {
415 case CONNECTED:
416 case DISCONNECTED:
Irfan Sheriffda6da092012-08-16 12:49:23 -0700417 case CAPTIVE_PORTAL_CHECK:
Irfan Sheriff227bec42011-02-15 19:30:27 -0800418 evaluateTrafficStatsPolling();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700419 resetNotification();
420 break;
421 }
422 } else if (intent.getAction().equals(
423 WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
Nick Pelly6ccaa542012-06-15 15:22:47 -0700424 noteScanEnd();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700425 checkAndSetNotification();
426 }
427 }
428 }, filter);
429
Irfan Sheriff227bec42011-02-15 19:30:27 -0800430 HandlerThread wifiThread = new HandlerThread("WifiService");
431 wifiThread.start();
432 mAsyncServiceHandler = new AsyncServiceHandler(wifiThread.getLooper());
433 mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
434
Irfan Sheriff0d255342010-07-28 09:35:20 -0700435 // Setting is in seconds
Christopher Tate6f5a9a92012-09-14 17:24:28 -0700436 NOTIFICATION_REPEAT_DELAY_MS = Settings.Global.getInt(context.getContentResolver(),
437 Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
Irfan Sheriff0d255342010-07-28 09:35:20 -0700438 mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler());
439 mNotificationEnabledSettingObserver.register();
Irfan Sheriff7b009782010-03-11 16:37:45 -0800440 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800441
Nick Pelly6ccaa542012-06-15 15:22:47 -0700442 /** Tell battery stats about a new WIFI scan */
443 private void noteScanStart() {
444 WorkSource scanWorkSource = null;
445 synchronized (WifiService.this) {
446 if (mScanWorkSource != null) {
447 // Scan already in progress, don't add this one to battery stats
448 return;
449 }
450 scanWorkSource = new WorkSource(Binder.getCallingUid());
451 mScanWorkSource = scanWorkSource;
452 }
453
454 long id = Binder.clearCallingIdentity();
455 try {
456 mBatteryStats.noteWifiScanStartedFromSource(scanWorkSource);
457 } catch (RemoteException e) {
458 Log.w(TAG, e);
459 } finally {
460 Binder.restoreCallingIdentity(id);
461 }
462 }
463
464 /** Tell battery stats that the current WIFI scan has completed */
465 private void noteScanEnd() {
466 WorkSource scanWorkSource = null;
467 synchronized (WifiService.this) {
468 scanWorkSource = mScanWorkSource;
469 mScanWorkSource = null;
470 }
471 if (scanWorkSource != null) {
472 try {
473 mBatteryStats.noteWifiScanStoppedFromSource(scanWorkSource);
474 } catch (RemoteException e) {
475 Log.w(TAG, e);
476 }
477 }
478 }
479
Irfan Sheriff7b009782010-03-11 16:37:45 -0800480 /**
481 * Check if Wi-Fi needs to be enabled and start
482 * if needed
Irfan Sheriff60e3ba02010-04-02 12:18:45 -0700483 *
484 * This function is used only at boot time
Irfan Sheriff7b009782010-03-11 16:37:45 -0800485 */
Irfan Sheriff0d255342010-07-28 09:35:20 -0700486 public void checkAndStartWifi() {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800487 mAirplaneModeOn.set(isAirplaneModeOn());
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800488 mPersistWifiState.set(getPersistedWifiState());
Irfan Sheriff658772f2011-03-08 14:52:31 -0800489 /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
490 boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
Irfan Sheriff7b009782010-03-11 16:37:45 -0800491 Slog.i(TAG, "WifiService starting up with Wi-Fi " +
492 (wifiEnabled ? "enabled" : "disabled"));
Irfan Sherifff03d6202012-05-17 12:33:46 -0700493
494 // If we are already disabled (could be due to airplane mode), avoid changing persist
495 // state here
496 if (wifiEnabled) setWifiEnabled(wifiEnabled);
Isaac Levybc7dfb52011-06-06 15:34:01 -0700497
Isaac Levy654f5092011-07-13 17:41:45 -0700498 mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
499 makeWifiWatchdogStateMachine(mContext);
500
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800501 }
502
Irfan Sheriffa3bd4092010-03-24 17:58:59 -0700503 private boolean testAndClearWifiSavedState() {
504 final ContentResolver cr = mContext.getContentResolver();
505 int wifiSavedState = 0;
506 try {
Christopher Tate6f5a9a92012-09-14 17:24:28 -0700507 wifiSavedState = Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE);
Irfan Sheriffa3bd4092010-03-24 17:58:59 -0700508 if(wifiSavedState == 1)
Christopher Tate6f5a9a92012-09-14 17:24:28 -0700509 Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
Irfan Sheriffa3bd4092010-03-24 17:58:59 -0700510 } catch (Settings.SettingNotFoundException e) {
511 ;
512 }
513 return (wifiSavedState == 1);
514 }
515
Irfan Sheriff658772f2011-03-08 14:52:31 -0800516 private int getPersistedWifiState() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 final ContentResolver cr = mContext.getContentResolver();
518 try {
Christopher Tate6f5a9a92012-09-14 17:24:28 -0700519 return Settings.Global.getInt(cr, Settings.Global.WIFI_ON);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 } catch (Settings.SettingNotFoundException e) {
Christopher Tate6f5a9a92012-09-14 17:24:28 -0700521 Settings.Global.putInt(cr, Settings.Global.WIFI_ON, WIFI_DISABLED);
Irfan Sheriff658772f2011-03-08 14:52:31 -0800522 return WIFI_DISABLED;
523 }
524 }
525
526 private boolean shouldWifiBeEnabled() {
527 if (mAirplaneModeOn.get()) {
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800528 return mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
Irfan Sheriff658772f2011-03-08 14:52:31 -0800529 } else {
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800530 return mPersistWifiState.get() != WIFI_DISABLED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 }
532 }
533
Irfan Sheriff42d73bb2012-05-17 14:14:44 -0700534 private void handleWifiToggled(boolean wifiEnabled) {
535 boolean airplaneEnabled = mAirplaneModeOn.get() && isAirplaneToggleable();
536 if (wifiEnabled) {
537 if (airplaneEnabled) {
Irfan Sherifff03d6202012-05-17 12:33:46 -0700538 persistWifiState(WIFI_ENABLED_AIRPLANE_OVERRIDE);
Irfan Sheriff658772f2011-03-08 14:52:31 -0800539 } else {
Irfan Sherifff03d6202012-05-17 12:33:46 -0700540 persistWifiState(WIFI_ENABLED);
Irfan Sheriff658772f2011-03-08 14:52:31 -0800541 }
542 } else {
Irfan Sherifff03d6202012-05-17 12:33:46 -0700543 // When wifi state is disabled, we do not care
544 // if airplane mode is on or not. The scenario of
545 // wifi being disabled due to airplane mode being turned on
546 // is handled handleAirplaneModeToggled()
547 persistWifiState(WIFI_DISABLED);
Irfan Sheriff658772f2011-03-08 14:52:31 -0800548 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 }
550
Irfan Sheriff42d73bb2012-05-17 14:14:44 -0700551 private void handleAirplaneModeToggled(boolean airplaneEnabled) {
552 if (airplaneEnabled) {
Irfan Sherifff03d6202012-05-17 12:33:46 -0700553 // Wifi disabled due to airplane on
554 if (mWifiEnabled) {
555 persistWifiState(WIFI_DISABLED_AIRPLANE_ON);
556 }
557 } else {
558 /* On airplane mode disable, restore wifi state if necessary */
559 if (testAndClearWifiSavedState() ||
560 mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE) {
561 persistWifiState(WIFI_ENABLED);
562 }
563 }
564 }
565
566 private void persistWifiState(int state) {
567 final ContentResolver cr = mContext.getContentResolver();
568 mPersistWifiState.set(state);
Christopher Tate6f5a9a92012-09-14 17:24:28 -0700569 Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state);
Irfan Sherifff03d6202012-05-17 12:33:46 -0700570 }
Irfan Sheriff658772f2011-03-08 14:52:31 -0800571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 /**
573 * see {@link android.net.wifi.WifiManager#pingSupplicant()}
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700574 * @return {@code true} if the operation succeeds, {@code false} otherwise
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 */
576 public boolean pingSupplicant() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700577 enforceAccessPermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800578 if (mWifiStateMachineChannel != null) {
579 return mWifiStateMachine.syncPingSupplicant(mWifiStateMachineChannel);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700580 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800581 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700582 return false;
583 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 }
585
586 /**
587 * see {@link android.net.wifi.WifiManager#startScan()}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700589 public void startScan(boolean forceActive) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700591 mWifiStateMachine.startScan(forceActive);
Nick Pelly6ccaa542012-06-15 15:22:47 -0700592 noteScanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 }
594
595 private void enforceAccessPermission() {
596 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
597 "WifiService");
598 }
599
600 private void enforceChangePermission() {
601 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
602 "WifiService");
603
604 }
605
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -0700606 private void enforceMulticastChangePermission() {
607 mContext.enforceCallingOrSelfPermission(
608 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
609 "WifiService");
610 }
611
Irfan Sheriffda6da092012-08-16 12:49:23 -0700612 private void enforceConnectivityInternalPermission() {
613 mContext.enforceCallingOrSelfPermission(
614 android.Manifest.permission.CONNECTIVITY_INTERNAL,
615 "ConnectivityService");
616 }
617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700619 * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
620 * @param enable {@code true} to enable, {@code false} to disable.
621 * @return {@code true} if the enable/disable operation was
622 * started or is already in the queue.
623 */
624 public synchronized boolean setWifiEnabled(boolean enable) {
625 enforceChangePermission();
Irfan Sheriffbd21b782012-05-16 13:13:54 -0700626 Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
627 + ", uid=" + Binder.getCallingUid());
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700628 if (DBG) {
Irfan Sheriff0d255342010-07-28 09:35:20 -0700629 Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700630 }
631
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700632 if (enable) {
633 reportStartWorkSource();
634 }
Irfan Sheriff0d255342010-07-28 09:35:20 -0700635 mWifiStateMachine.setWifiEnabled(enable);
Irfan Sheriff61180692010-08-18 16:07:39 -0700636
637 /*
638 * Caller might not have WRITE_SECURE_SETTINGS,
639 * only CHANGE_WIFI_STATE is enforced
640 */
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800641
Irfan Sherifff03d6202012-05-17 12:33:46 -0700642 long ident = Binder.clearCallingIdentity();
Irfan Sheriff3d33a632012-09-16 17:59:13 -0700643 try {
644 handleWifiToggled(enable);
645 } finally {
646 Binder.restoreCallingIdentity(ident);
647 }
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700648
649 if (enable) {
650 if (!mIsReceiverRegistered) {
651 registerForBroadcasts();
652 mIsReceiverRegistered = true;
653 }
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800654 } else if (mIsReceiverRegistered) {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700655 mContext.unregisterReceiver(mReceiver);
656 mIsReceiverRegistered = false;
657 }
658
659 return true;
660 }
661
662 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663 * see {@link WifiManager#getWifiState()}
664 * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
665 * {@link WifiManager#WIFI_STATE_DISABLING},
666 * {@link WifiManager#WIFI_STATE_ENABLED},
667 * {@link WifiManager#WIFI_STATE_ENABLING},
668 * {@link WifiManager#WIFI_STATE_UNKNOWN}
669 */
670 public int getWifiEnabledState() {
671 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700672 return mWifiStateMachine.syncGetWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 }
674
675 /**
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700676 * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800677 * @param wifiConfig SSID, security and channel details as
678 * part of WifiConfiguration
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700679 * @param enabled true to enable and false to disable
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800680 */
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700681 public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800682 enforceChangePermission();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700683 mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800684 }
685
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700686 /**
687 * see {@link WifiManager#getWifiApState()}
688 * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
689 * {@link WifiManager#WIFI_AP_STATE_DISABLING},
690 * {@link WifiManager#WIFI_AP_STATE_ENABLED},
691 * {@link WifiManager#WIFI_AP_STATE_ENABLING},
692 * {@link WifiManager#WIFI_AP_STATE_FAILED}
693 */
694 public int getWifiApEnabledState() {
Irfan Sheriff17b232b2010-06-24 11:32:26 -0700695 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700696 return mWifiStateMachine.syncGetWifiApState();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700697 }
698
699 /**
700 * see {@link WifiManager#getWifiApConfiguration()}
701 * @return soft access point configuration
702 */
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700703 public WifiConfiguration getWifiApConfiguration() {
704 enforceAccessPermission();
Irfan Sheriff9575a1b2011-11-07 10:34:54 -0800705 return mWifiStateMachine.syncGetWifiApConfiguration();
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800706 }
707
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700708 /**
709 * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
710 * @param wifiConfig WifiConfiguration details for soft access point
711 */
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700712 public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
Irfan Sheriff17b232b2010-06-24 11:32:26 -0700713 enforceChangePermission();
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800714 if (wifiConfig == null)
715 return;
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700716 mWifiStateMachine.setWifiApConfiguration(wifiConfig);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800717 }
718
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800719 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700720 * see {@link android.net.wifi.WifiManager#disconnect()}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800721 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700722 public void disconnect() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700723 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700724 mWifiStateMachine.disconnectCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800725 }
726
727 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700728 * see {@link android.net.wifi.WifiManager#reconnect()}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800729 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700730 public void reconnect() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700731 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700732 mWifiStateMachine.reconnectCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800733 }
734
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700735 /**
736 * see {@link android.net.wifi.WifiManager#reassociate()}
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700737 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700738 public void reassociate() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700739 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700740 mWifiStateMachine.reassociateCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800741 }
742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 /**
744 * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
745 * @return the list of configured networks
746 */
747 public List<WifiConfiguration> getConfiguredNetworks() {
748 enforceAccessPermission();
Irfan Sheriffe744cff2011-12-11 09:17:50 -0800749 if (mWifiStateMachineChannel != null) {
750 return mWifiStateMachine.syncGetConfiguredNetworks(mWifiStateMachineChannel);
751 } else {
752 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
753 return null;
754 }
Chung-yih Wanga8d15942009-10-09 11:01:49 +0800755 }
756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 /**
758 * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
759 * @return the supplicant-assigned identifier for the new or updated
760 * network if the operation succeeds, or {@code -1} if it fails
761 */
Irfan Sheriff7aac5542009-12-22 21:42:17 -0800762 public int addOrUpdateNetwork(WifiConfiguration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800764 if (mWifiStateMachineChannel != null) {
765 return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700766 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800767 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700768 return -1;
769 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 }
771
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700772 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
774 * @param netId the integer that identifies the network configuration
775 * to the supplicant
776 * @return {@code true} if the operation succeeded
777 */
778 public boolean removeNetwork(int netId) {
779 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800780 if (mWifiStateMachineChannel != null) {
781 return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
Wink Saville4b7ba092010-10-20 15:37:41 -0700782 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800783 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Wink Saville4b7ba092010-10-20 15:37:41 -0700784 return false;
785 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 }
787
788 /**
789 * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
790 * @param netId the integer that identifies the network configuration
791 * to the supplicant
792 * @param disableOthers if true, disable all other networks.
793 * @return {@code true} if the operation succeeded
794 */
795 public boolean enableNetwork(int netId, boolean disableOthers) {
796 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800797 if (mWifiStateMachineChannel != null) {
798 return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
799 disableOthers);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700800 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800801 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700802 return false;
803 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 }
805
806 /**
807 * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
808 * @param netId the integer that identifies the network configuration
809 * to the supplicant
810 * @return {@code true} if the operation succeeded
811 */
812 public boolean disableNetwork(int netId) {
813 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800814 if (mWifiStateMachineChannel != null) {
815 return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700816 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800817 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700818 return false;
819 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 }
821
822 /**
823 * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
824 * @return the Wi-Fi information, contained in {@link WifiInfo}.
825 */
826 public WifiInfo getConnectionInfo() {
827 enforceAccessPermission();
828 /*
829 * Make sure we have the latest information, by sending
830 * a status request to the supplicant.
831 */
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700832 return mWifiStateMachine.syncRequestConnectionInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833 }
834
835 /**
836 * Return the results of the most recent access point scan, in the form of
837 * a list of {@link ScanResult} objects.
838 * @return the list of results
839 */
840 public List<ScanResult> getScanResults() {
841 enforceAccessPermission();
Irfan Sheriffdb831da2012-09-16 17:39:26 -0700842 int userId = UserHandle.getCallingUserId();
843 long ident = Binder.clearCallingIdentity();
Irfan Sheriff3d33a632012-09-16 17:59:13 -0700844 try {
845 int currentUser = ActivityManager.getCurrentUser();
846 if (userId != currentUser) {
847 return new ArrayList<ScanResult>();
848 } else {
849 return mWifiStateMachine.syncGetScanResultsList();
850 }
851 } finally {
852 Binder.restoreCallingIdentity(ident);
Irfan Sheriff330b1872012-09-16 12:27:57 -0700853 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 }
855
856 /**
857 * Tell the supplicant to persist the current list of configured networks.
858 * @return {@code true} if the operation succeeded
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700859 *
860 * TODO: deprecate this
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 */
862 public boolean saveConfiguration() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700863 boolean result = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800865 if (mWifiStateMachineChannel != null) {
866 return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700867 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800868 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700869 return false;
870 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 }
872
873 /**
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700874 * Set the country code
875 * @param countryCode ISO 3166 country code.
Robert Greenwaltb5010cc2009-05-21 15:11:40 -0700876 * @param persist {@code true} if the setting should be remembered.
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700877 *
878 * The persist behavior exists so that wifi can fall back to the last
879 * persisted country code on a restart, when the locale information is
880 * not available from telephony.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 */
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700882 public void setCountryCode(String countryCode, boolean persist) {
883 Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
884 " with persist set to " + persist);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 enforceChangePermission();
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700886 mWifiStateMachine.setCountryCode(countryCode, persist);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 }
888
889 /**
Irfan Sheriff36f74132010-11-04 16:57:37 -0700890 * Set the operational frequency band
891 * @param band One of
892 * {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
893 * {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
894 * {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
895 * @param persist {@code true} if the setting should be remembered.
896 *
897 */
898 public void setFrequencyBand(int band, boolean persist) {
899 enforceChangePermission();
900 if (!isDualBandSupported()) return;
901 Slog.i(TAG, "WifiService trying to set frequency band to " + band +
902 " with persist set to " + persist);
903 mWifiStateMachine.setFrequencyBand(band, persist);
904 }
905
906
907 /**
908 * Get the operational frequency band
909 */
910 public int getFrequencyBand() {
911 enforceAccessPermission();
912 return mWifiStateMachine.getFrequencyBand();
913 }
914
915 public boolean isDualBandSupported() {
916 //TODO: Should move towards adding a driver API that checks at runtime
917 return mContext.getResources().getBoolean(
918 com.android.internal.R.bool.config_wifi_dual_band_support);
919 }
920
921 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 * Return the DHCP-assigned addresses from the last successful DHCP request,
923 * if any.
924 * @return the DHCP information
925 */
926 public DhcpInfo getDhcpInfo() {
927 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700928 return mWifiStateMachine.syncGetDhcpInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 }
930
Irfan Sheriff0d255342010-07-28 09:35:20 -0700931 /**
932 * see {@link android.net.wifi.WifiManager#startWifi}
933 *
934 */
935 public void startWifi() {
Irfan Sheriffda6da092012-08-16 12:49:23 -0700936 enforceConnectivityInternalPermission();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700937 /* TODO: may be add permissions for access only to connectivity service
938 * TODO: if a start issued, keep wifi alive until a stop issued irrespective
939 * of WifiLock & device idle status unless wifi enabled status is toggled
940 */
941
Irfan Sheriff4494c902011-12-08 10:47:54 -0800942 mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode);
Irfan Sheriff0d255342010-07-28 09:35:20 -0700943 mWifiStateMachine.reconnectCommand();
944 }
945
Irfan Sheriffda6da092012-08-16 12:49:23 -0700946 public void captivePortalCheckComplete() {
947 enforceConnectivityInternalPermission();
948 mWifiStateMachine.captivePortalCheckComplete();
949 }
950
Irfan Sheriff0d255342010-07-28 09:35:20 -0700951 /**
952 * see {@link android.net.wifi.WifiManager#stopWifi}
953 *
954 */
955 public void stopWifi() {
Irfan Sheriffda6da092012-08-16 12:49:23 -0700956 enforceConnectivityInternalPermission();
957 /*
Irfan Sheriff0d255342010-07-28 09:35:20 -0700958 * TODO: if a stop is issued, wifi is brought up only by startWifi
959 * unless wifi enabled status is toggled
960 */
Irfan Sheriff4494c902011-12-08 10:47:54 -0800961 mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode);
Irfan Sheriff0d255342010-07-28 09:35:20 -0700962 }
963
Irfan Sheriff0d255342010-07-28 09:35:20 -0700964 /**
965 * see {@link android.net.wifi.WifiManager#addToBlacklist}
966 *
967 */
968 public void addToBlacklist(String bssid) {
969 enforceChangePermission();
970
971 mWifiStateMachine.addToBlacklist(bssid);
972 }
973
974 /**
975 * see {@link android.net.wifi.WifiManager#clearBlacklist}
976 *
977 */
978 public void clearBlacklist() {
979 enforceChangePermission();
980
981 mWifiStateMachine.clearBlacklist();
982 }
983
Irfan Sheriff227bec42011-02-15 19:30:27 -0800984 /**
985 * Get a reference to handler. This is used by a client to establish
986 * an AsyncChannel communication with WifiService
987 */
Irfan Sheriff07573b32012-01-27 21:00:19 -0800988 public Messenger getWifiServiceMessenger() {
Irfan Sheriff35bbe272012-08-23 16:57:43 -0700989 enforceAccessPermission();
990 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800991 return new Messenger(mAsyncServiceHandler);
992 }
993
Irfan Sheriff07573b32012-01-27 21:00:19 -0800994 /** Get a reference to WifiStateMachine handler for AsyncChannel communication */
995 public Messenger getWifiStateMachineMessenger() {
996 enforceAccessPermission();
997 enforceChangePermission();
998 return mWifiStateMachine.getMessenger();
999 }
1000
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -08001001 /**
1002 * Get the IP and proxy configuration file
1003 */
1004 public String getConfigFile() {
1005 enforceAccessPermission();
1006 return mWifiStateMachine.getConfigFile();
1007 }
1008
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1010 @Override
1011 public void onReceive(Context context, Intent intent) {
1012 String action = intent.getAction();
1013
Doug Zongker43866e02010-01-07 12:09:54 -08001014 long idleMillis =
Christopher Tate6f5a9a92012-09-14 17:24:28 -07001015 Settings.Global.getLong(mContext.getContentResolver(),
1016 Settings.Global.WIFI_IDLE_MS, DEFAULT_IDLE_MS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 int stayAwakeConditions =
Christopher Tate6f5a9a92012-09-14 17:24:28 -07001018 Settings.Global.getInt(mContext.getContentResolver(),
1019 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Joe Onorato431bb222010-10-18 19:13:23 -04001021 if (DBG) {
1022 Slog.d(TAG, "ACTION_SCREEN_ON");
1023 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 mAlarmManager.cancel(mIdleIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 mScreenOff = false;
Irfan Sheriff227bec42011-02-15 19:30:27 -08001026 evaluateTrafficStatsPolling();
Irfan Sheriffe6daca52011-11-03 15:46:50 -07001027 setDeviceIdleAndUpdateWifi(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Joe Onorato431bb222010-10-18 19:13:23 -04001029 if (DBG) {
1030 Slog.d(TAG, "ACTION_SCREEN_OFF");
1031 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 mScreenOff = true;
Irfan Sheriff227bec42011-02-15 19:30:27 -08001033 evaluateTrafficStatsPolling();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 /*
1035 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
1036 * AND the "stay on while plugged in" setting doesn't match the
1037 * current power conditions (i.e, not plugged in, plugged in to USB,
1038 * or plugged in to AC).
1039 */
1040 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
Irfan Sheriffe6daca52011-11-03 15:46:50 -07001041 //Delayed shutdown if wifi is connected
1042 if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
1043 if (DBG) Slog.d(TAG, "setting ACTION_DEVICE_IDLE: " + idleMillis + " ms");
1044 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
1045 + idleMillis, mIdleIntent);
Mike Lockwoodd9c32bc2009-05-18 14:14:15 -04001046 } else {
Irfan Sheriffe6daca52011-11-03 15:46:50 -07001047 setDeviceIdleAndUpdateWifi(true);
Mike Lockwoodd9c32bc2009-05-18 14:14:15 -04001048 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 } else if (action.equals(ACTION_DEVICE_IDLE)) {
Irfan Sheriffe6daca52011-11-03 15:46:50 -07001051 setDeviceIdleAndUpdateWifi(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
1053 /*
1054 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
1055 * AND we are transitioning from a state in which the device was supposed
1056 * to stay awake to a state in which it is not supposed to stay awake.
1057 * If "stay awake" state is not changing, we do nothing, to avoid resetting
1058 * the already-set timer.
1059 */
1060 int pluggedType = intent.getIntExtra("plugged", 0);
Joe Onorato431bb222010-10-18 19:13:23 -04001061 if (DBG) {
1062 Slog.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType);
1063 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) &&
1065 !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) {
1066 long triggerTime = System.currentTimeMillis() + idleMillis;
Joe Onorato431bb222010-10-18 19:13:23 -04001067 if (DBG) {
1068 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
1069 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001071 }
Irfan Sheriff8cef0672011-12-13 17:03:59 -08001072
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 mPluggedType = pluggedType;
Irfan Sheriff65eaec82011-01-05 22:00:16 -08001074 } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
1075 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
1076 BluetoothAdapter.STATE_DISCONNECTED);
1077 mWifiStateMachine.sendBluetoothAdapterStateChange(state);
Irfan Sheriff616f3172011-09-11 19:59:01 -07001078 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
1079 mEmergencyCallbackMode = intent.getBooleanExtra("phoneinECMState", false);
1080 updateWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 }
1083
1084 /**
1085 * Determines whether the Wi-Fi chipset should stay awake or be put to
1086 * sleep. Looks at the setting for the sleep policy and the current
1087 * conditions.
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001088 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 * @see #shouldDeviceStayAwake(int, int)
1090 */
1091 private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) {
Irfan Sheriff739f6bc2011-01-28 16:43:12 -08001092 //Never sleep as long as the user has not changed the settings
Brian Muramatsu35d323a2012-09-20 19:52:34 -07001093 int wifiSleepPolicy = Settings.Global.getInt(mContext.getContentResolver(),
1094 Settings.Global.WIFI_SLEEP_POLICY,
1095 Settings.Global.WIFI_SLEEP_POLICY_NEVER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096
Brian Muramatsu35d323a2012-09-20 19:52:34 -07001097 if (wifiSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001098 // Never sleep
1099 return true;
Brian Muramatsu35d323a2012-09-20 19:52:34 -07001100 } else if ((wifiSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) &&
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 (pluggedType != 0)) {
1102 // Never sleep while plugged, and we're plugged
1103 return true;
1104 } else {
1105 // Default
1106 return shouldDeviceStayAwake(stayAwakeConditions, pluggedType);
1107 }
1108 }
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 /**
1111 * Determine whether the bit value corresponding to {@code pluggedType} is set in
1112 * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value
1113 * of {@code 0} isn't really a plugged type, but rather an indication that the
1114 * device isn't plugged in at all, there is no bit value corresponding to a
1115 * {@code pluggedType} value of {@code 0}. That is why we shift by
Ben Dodson4e8620f2010-08-25 10:55:47 -07001116 * {@code pluggedType - 1} instead of by {@code pluggedType}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 * @param stayAwakeConditions a bit string specifying which "plugged types" should
1118 * keep the device (and hence Wi-Fi) awake.
1119 * @param pluggedType the type of plug (USB, AC, or none) for which the check is
1120 * being made
1121 * @return {@code true} if {@code pluggedType} indicates that the device is
1122 * supposed to stay awake, {@code false} otherwise.
1123 */
1124 private boolean shouldDeviceStayAwake(int stayAwakeConditions, int pluggedType) {
1125 return (stayAwakeConditions & pluggedType) != 0;
1126 }
1127 };
1128
Irfan Sheriffe6daca52011-11-03 15:46:50 -07001129 private void setDeviceIdleAndUpdateWifi(boolean deviceIdle) {
1130 mDeviceIdle = deviceIdle;
1131 reportStartWorkSource();
1132 updateWifiState();
1133 }
1134
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001135 private synchronized void reportStartWorkSource() {
1136 mTmpWorkSource.clear();
1137 if (mDeviceIdle) {
1138 for (int i=0; i<mLocks.mList.size(); i++) {
1139 mTmpWorkSource.add(mLocks.mList.get(i).mWorkSource);
Dianne Hackborn58e0eef2010-09-16 01:22:10 -07001140 }
Dianne Hackborn58e0eef2010-09-16 01:22:10 -07001141 }
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001142 mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource);
Dianne Hackborn58e0eef2010-09-16 01:22:10 -07001143 }
Jaikumar Ganesh7440fc22010-09-27 17:04:14 -07001144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 private void updateWifiState() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 boolean lockHeld = mLocks.hasLocks();
Irfan Sheriff5876a422010-08-12 20:26:23 -07001147 int strongestLockMode = WifiManager.WIFI_MODE_FULL;
Irfan Sheriff616f3172011-09-11 19:59:01 -07001148 boolean wifiShouldBeStarted;
1149
1150 if (mEmergencyCallbackMode) {
1151 wifiShouldBeStarted = false;
1152 } else {
1153 wifiShouldBeStarted = !mDeviceIdle || lockHeld;
1154 }
Irfan Sheriff5876a422010-08-12 20:26:23 -07001155
1156 if (lockHeld) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 strongestLockMode = mLocks.getStrongestLockMode();
Irfan Sheriff5876a422010-08-12 20:26:23 -07001158 }
1159 /* If device is not idle, lockmode cannot be scan only */
1160 if (!mDeviceIdle && strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 strongestLockMode = WifiManager.WIFI_MODE_FULL;
1162 }
1163
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001164 /* Disable tethering when airplane mode is enabled */
Irfan Sheriff658772f2011-03-08 14:52:31 -08001165 if (mAirplaneModeOn.get()) {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001166 mWifiStateMachine.setWifiApEnabled(null, false);
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001167 }
Irfan Sheriffb2e6c012010-04-05 11:57:56 -07001168
Irfan Sheriff658772f2011-03-08 14:52:31 -08001169 if (shouldWifiBeEnabled()) {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001170 if (wifiShouldBeStarted) {
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001171 reportStartWorkSource();
Irfan Sheriff0d255342010-07-28 09:35:20 -07001172 mWifiStateMachine.setWifiEnabled(true);
1173 mWifiStateMachine.setScanOnlyMode(
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001174 strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
Irfan Sheriff4494c902011-12-08 10:47:54 -08001175 mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode);
Irfan Sheriff5876a422010-08-12 20:26:23 -07001176 mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode
1177 == WifiManager.WIFI_MODE_FULL_HIGH_PERF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178 } else {
Irfan Sheriff4494c902011-12-08 10:47:54 -08001179 mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 }
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001181 } else {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001182 mWifiStateMachine.setWifiEnabled(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001183 }
1184 }
1185
1186 private void registerForBroadcasts() {
1187 IntentFilter intentFilter = new IntentFilter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
1189 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
1190 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
1191 intentFilter.addAction(ACTION_DEVICE_IDLE);
Irfan Sheriff65eaec82011-01-05 22:00:16 -08001192 intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
Irfan Sheriff616f3172011-09-11 19:59:01 -07001193 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194 mContext.registerReceiver(mReceiver, intentFilter);
1195 }
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001197 private boolean isAirplaneSensitive() {
Christopher Tatec09cdce2012-09-10 16:50:14 -07001198 String airplaneModeRadios = Settings.Global.getString(mContext.getContentResolver(),
1199 Settings.Global.AIRPLANE_MODE_RADIOS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 return airplaneModeRadios == null
Christopher Tatec09cdce2012-09-10 16:50:14 -07001201 || airplaneModeRadios.contains(Settings.Global.RADIO_WIFI);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 }
1203
Mike Lockwoodbd5ddf02009-07-29 21:37:14 -07001204 private boolean isAirplaneToggleable() {
Christopher Tatec09cdce2012-09-10 16:50:14 -07001205 String toggleableRadios = Settings.Global.getString(mContext.getContentResolver(),
1206 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
Mike Lockwoodbd5ddf02009-07-29 21:37:14 -07001207 return toggleableRadios != null
Christopher Tatec09cdce2012-09-10 16:50:14 -07001208 && toggleableRadios.contains(Settings.Global.RADIO_WIFI);
Mike Lockwoodbd5ddf02009-07-29 21:37:14 -07001209 }
1210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 /**
1212 * Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is
1213 * currently on.
1214 * @return {@code true} if airplane mode is on.
1215 */
1216 private boolean isAirplaneModeOn() {
Christopher Tatec09cdce2012-09-10 16:50:14 -07001217 return isAirplaneSensitive() && Settings.Global.getInt(mContext.getContentResolver(),
1218 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 }
1220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221 @Override
1222 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1223 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1224 != PackageManager.PERMISSION_GRANTED) {
1225 pw.println("Permission Denial: can't dump WifiService from from pid="
1226 + Binder.getCallingPid()
1227 + ", uid=" + Binder.getCallingUid());
1228 return;
1229 }
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001230 pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231 pw.println("Stay-awake conditions: " +
Christopher Tatec09cdce2012-09-10 16:50:14 -07001232 Settings.Global.getInt(mContext.getContentResolver(),
1233 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 pw.println();
1235
1236 pw.println("Internal state:");
Irfan Sheriff0d255342010-07-28 09:35:20 -07001237 pw.println(mWifiStateMachine);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 pw.println();
1239 pw.println("Latest scan results:");
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001240 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001241 if (scanResults != null && scanResults.size() != 0) {
1242 pw.println(" BSSID Frequency RSSI Flags SSID");
1243 for (ScanResult r : scanResults) {
1244 pw.printf(" %17s %9d %5d %-16s %s%n",
1245 r.BSSID,
1246 r.frequency,
1247 r.level,
1248 r.capabilities,
1249 r.SSID == null ? "" : r.SSID);
1250 }
1251 }
1252 pw.println();
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001253 pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
Irfan Sheriff5876a422010-08-12 20:26:23 -07001254 mFullHighPerfLocksAcquired + " full high perf, " +
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001255 mScanLocksAcquired + " scan");
1256 pw.println("Locks released: " + mFullLocksReleased + " full, " +
Irfan Sheriff5876a422010-08-12 20:26:23 -07001257 mFullHighPerfLocksReleased + " full high perf, " +
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001258 mScanLocksReleased + " scan");
1259 pw.println();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 pw.println("Locks held:");
1261 mLocks.dump(pw);
Isaac Levybc7dfb52011-06-06 15:34:01 -07001262
1263 pw.println();
Isaac Levy654f5092011-07-13 17:41:45 -07001264 pw.println("WifiWatchdogStateMachine dump");
1265 mWifiWatchdogStateMachine.dump(pw);
Irfan Sheriff60792372012-04-16 16:47:10 -07001266 pw.println("WifiStateMachine dump");
1267 mWifiStateMachine.dump(fd, pw, args);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 }
1269
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001270 private class WifiLock extends DeathRecipient {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001271 WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
1272 super(lockMode, tag, binder, ws);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 }
1274
1275 public void binderDied() {
1276 synchronized (mLocks) {
1277 releaseWifiLockLocked(mBinder);
1278 }
1279 }
1280
1281 public String toString() {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001282 return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 }
1284 }
1285
1286 private class LockList {
1287 private List<WifiLock> mList;
1288
1289 private LockList() {
1290 mList = new ArrayList<WifiLock>();
1291 }
1292
1293 private synchronized boolean hasLocks() {
1294 return !mList.isEmpty();
1295 }
1296
1297 private synchronized int getStrongestLockMode() {
1298 if (mList.isEmpty()) {
1299 return WifiManager.WIFI_MODE_FULL;
1300 }
Irfan Sheriff5876a422010-08-12 20:26:23 -07001301
1302 if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
1303 return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001304 }
Irfan Sheriff5876a422010-08-12 20:26:23 -07001305
1306 if (mFullLocksAcquired > mFullLocksReleased) {
1307 return WifiManager.WIFI_MODE_FULL;
1308 }
1309
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 return WifiManager.WIFI_MODE_SCAN_ONLY;
1311 }
1312
1313 private void addLock(WifiLock lock) {
1314 if (findLockByBinder(lock.mBinder) < 0) {
1315 mList.add(lock);
1316 }
1317 }
1318
1319 private WifiLock removeLock(IBinder binder) {
1320 int index = findLockByBinder(binder);
1321 if (index >= 0) {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001322 WifiLock ret = mList.remove(index);
1323 ret.unlinkDeathRecipient();
1324 return ret;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325 } else {
1326 return null;
1327 }
1328 }
1329
1330 private int findLockByBinder(IBinder binder) {
1331 int size = mList.size();
1332 for (int i = size - 1; i >= 0; i--)
1333 if (mList.get(i).mBinder == binder)
1334 return i;
1335 return -1;
1336 }
1337
1338 private void dump(PrintWriter pw) {
1339 for (WifiLock l : mList) {
1340 pw.print(" ");
1341 pw.println(l);
1342 }
1343 }
1344 }
1345
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001346 void enforceWakeSourcePermission(int uid, int pid) {
Dianne Hackborne746f032010-09-13 16:02:57 -07001347 if (uid == android.os.Process.myUid()) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001348 return;
1349 }
1350 mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
1351 pid, uid, null);
1352 }
1353
1354 public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
Irfan Sheriff5876a422010-08-12 20:26:23 -07001356 if (lockMode != WifiManager.WIFI_MODE_FULL &&
1357 lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
1358 lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
1359 Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
1360 if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001361 return false;
1362 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001363 if (ws != null && ws.size() == 0) {
1364 ws = null;
1365 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001366 if (ws != null) {
1367 enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
1368 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001369 if (ws == null) {
1370 ws = new WorkSource(Binder.getCallingUid());
1371 }
1372 WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001373 synchronized (mLocks) {
1374 return acquireWifiLockLocked(wifiLock);
1375 }
1376 }
1377
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001378 private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
1379 switch(wifiLock.mMode) {
1380 case WifiManager.WIFI_MODE_FULL:
Irfan Sheriff5876a422010-08-12 20:26:23 -07001381 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001382 case WifiManager.WIFI_MODE_SCAN_ONLY:
Nick Pelly6ccaa542012-06-15 15:22:47 -07001383 mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001384 break;
1385 }
1386 }
1387
1388 private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
1389 switch(wifiLock.mMode) {
1390 case WifiManager.WIFI_MODE_FULL:
Irfan Sheriff5876a422010-08-12 20:26:23 -07001391 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001392 case WifiManager.WIFI_MODE_SCAN_ONLY:
Nick Pelly6ccaa542012-06-15 15:22:47 -07001393 mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001394 break;
1395 }
1396 }
1397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 private boolean acquireWifiLockLocked(WifiLock wifiLock) {
Irfan Sheriffc89dd542010-09-28 08:40:54 -07001399 if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 mLocks.addLock(wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001402
The Android Open Source Project10592532009-03-18 17:39:46 -07001403 long ident = Binder.clearCallingIdentity();
1404 try {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001405 noteAcquireWifiLock(wifiLock);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001406 switch(wifiLock.mMode) {
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001407 case WifiManager.WIFI_MODE_FULL:
1408 ++mFullLocksAcquired;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001409 break;
Irfan Sheriff5876a422010-08-12 20:26:23 -07001410 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1411 ++mFullHighPerfLocksAcquired;
1412 break;
1413
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001414 case WifiManager.WIFI_MODE_SCAN_ONLY:
1415 ++mScanLocksAcquired;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001416 break;
The Android Open Source Project10592532009-03-18 17:39:46 -07001417 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001418
1419 // Be aggressive about adding new locks into the accounted state...
1420 // we want to over-report rather than under-report.
1421 reportStartWorkSource();
1422
1423 updateWifiState();
1424 return true;
The Android Open Source Project10592532009-03-18 17:39:46 -07001425 } catch (RemoteException e) {
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001426 return false;
The Android Open Source Project10592532009-03-18 17:39:46 -07001427 } finally {
1428 Binder.restoreCallingIdentity(ident);
1429 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 }
1431
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001432 public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
1433 int uid = Binder.getCallingUid();
1434 int pid = Binder.getCallingPid();
1435 if (ws != null && ws.size() == 0) {
1436 ws = null;
1437 }
1438 if (ws != null) {
1439 enforceWakeSourcePermission(uid, pid);
1440 }
1441 long ident = Binder.clearCallingIdentity();
1442 try {
1443 synchronized (mLocks) {
1444 int index = mLocks.findLockByBinder(lock);
1445 if (index < 0) {
1446 throw new IllegalArgumentException("Wifi lock not active");
1447 }
1448 WifiLock wl = mLocks.mList.get(index);
1449 noteReleaseWifiLock(wl);
1450 wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
1451 noteAcquireWifiLock(wl);
1452 }
1453 } catch (RemoteException e) {
1454 } finally {
1455 Binder.restoreCallingIdentity(ident);
1456 }
1457 }
1458
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001459 public boolean releaseWifiLock(IBinder lock) {
1460 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1461 synchronized (mLocks) {
1462 return releaseWifiLockLocked(lock);
1463 }
1464 }
1465
1466 private boolean releaseWifiLockLocked(IBinder lock) {
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001467 boolean hadLock;
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001468
The Android Open Source Project10592532009-03-18 17:39:46 -07001469 WifiLock wifiLock = mLocks.removeLock(lock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001470
Irfan Sheriffc89dd542010-09-28 08:40:54 -07001471 if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001472
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001473 hadLock = (wifiLock != null);
1474
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001475 long ident = Binder.clearCallingIdentity();
1476 try {
1477 if (hadLock) {
Wink Savillece0ea1f2b2011-10-13 16:55:20 -07001478 noteReleaseWifiLock(wifiLock);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001479 switch(wifiLock.mMode) {
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001480 case WifiManager.WIFI_MODE_FULL:
1481 ++mFullLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001482 break;
Irfan Sheriff5876a422010-08-12 20:26:23 -07001483 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1484 ++mFullHighPerfLocksReleased;
1485 break;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001486 case WifiManager.WIFI_MODE_SCAN_ONLY:
1487 ++mScanLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001488 break;
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001489 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001490 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001491
1492 // TODO - should this only happen if you hadLock?
1493 updateWifiState();
1494
1495 } catch (RemoteException e) {
1496 } finally {
1497 Binder.restoreCallingIdentity(ident);
The Android Open Source Project10592532009-03-18 17:39:46 -07001498 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001499
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001500 return hadLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001502
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001503 private abstract class DeathRecipient
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001504 implements IBinder.DeathRecipient {
1505 String mTag;
1506 int mMode;
1507 IBinder mBinder;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001508 WorkSource mWorkSource;
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001509
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001510 DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001511 super();
1512 mTag = tag;
1513 mMode = mode;
1514 mBinder = binder;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001515 mWorkSource = ws;
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001516 try {
1517 mBinder.linkToDeath(this, 0);
1518 } catch (RemoteException e) {
1519 binderDied();
1520 }
1521 }
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001522
1523 void unlinkDeathRecipient() {
1524 mBinder.unlinkToDeath(this, 0);
1525 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001526 }
1527
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001528 private class Multicaster extends DeathRecipient {
1529 Multicaster(String tag, IBinder binder) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001530 super(Binder.getCallingUid(), tag, binder, null);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001531 }
1532
1533 public void binderDied() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001534 Slog.e(TAG, "Multicaster binderDied");
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001535 synchronized (mMulticasters) {
1536 int i = mMulticasters.indexOf(this);
1537 if (i != -1) {
1538 removeMulticasterLocked(i, mMode);
1539 }
1540 }
1541 }
1542
1543 public String toString() {
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001544 return "Multicaster{" + mTag + " binder=" + mBinder + "}";
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001545 }
1546
1547 public int getUid() {
1548 return mMode;
1549 }
1550 }
1551
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001552 public void initializeMulticastFiltering() {
1553 enforceMulticastChangePermission();
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001554
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001555 synchronized (mMulticasters) {
1556 // if anybody had requested filters be off, leave off
1557 if (mMulticasters.size() != 0) {
1558 return;
1559 } else {
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001560 mWifiStateMachine.startFilteringMulticastV4Packets();
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001561 }
1562 }
1563 }
1564
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -07001565 public void acquireMulticastLock(IBinder binder, String tag) {
1566 enforceMulticastChangePermission();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001567
1568 synchronized (mMulticasters) {
1569 mMulticastEnabled++;
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001570 mMulticasters.add(new Multicaster(tag, binder));
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001571 // Note that we could call stopFilteringMulticastV4Packets only when
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001572 // our new size == 1 (first call), but this function won't
1573 // be called often and by making the stopPacket call each
1574 // time we're less fragile and self-healing.
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001575 mWifiStateMachine.stopFilteringMulticastV4Packets();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001576 }
1577
1578 int uid = Binder.getCallingUid();
1579 Long ident = Binder.clearCallingIdentity();
1580 try {
1581 mBatteryStats.noteWifiMulticastEnabled(uid);
1582 } catch (RemoteException e) {
1583 } finally {
1584 Binder.restoreCallingIdentity(ident);
1585 }
1586 }
1587
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -07001588 public void releaseMulticastLock() {
1589 enforceMulticastChangePermission();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001590
1591 int uid = Binder.getCallingUid();
1592 synchronized (mMulticasters) {
1593 mMulticastDisabled++;
1594 int size = mMulticasters.size();
1595 for (int i = size - 1; i >= 0; i--) {
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001596 Multicaster m = mMulticasters.get(i);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001597 if ((m != null) && (m.getUid() == uid)) {
1598 removeMulticasterLocked(i, uid);
1599 }
1600 }
1601 }
1602 }
1603
1604 private void removeMulticasterLocked(int i, int uid)
1605 {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001606 Multicaster removed = mMulticasters.remove(i);
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001607
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001608 if (removed != null) {
1609 removed.unlinkDeathRecipient();
1610 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001611 if (mMulticasters.size() == 0) {
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001612 mWifiStateMachine.startFilteringMulticastV4Packets();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001613 }
1614
1615 Long ident = Binder.clearCallingIdentity();
1616 try {
1617 mBatteryStats.noteWifiMulticastDisabled(uid);
1618 } catch (RemoteException e) {
1619 } finally {
1620 Binder.restoreCallingIdentity(ident);
1621 }
1622 }
1623
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001624 public boolean isMulticastEnabled() {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001625 enforceAccessPermission();
1626
1627 synchronized (mMulticasters) {
1628 return (mMulticasters.size() > 0);
1629 }
1630 }
Irfan Sheriff0d255342010-07-28 09:35:20 -07001631
Irfan Sheriff227bec42011-02-15 19:30:27 -08001632 /**
1633 * Evaluate if traffic stats polling is needed based on
1634 * connection and screen on status
1635 */
1636 private void evaluateTrafficStatsPolling() {
1637 Message msg;
1638 if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED && !mScreenOff) {
Irfan Sheriffebe606f2011-02-24 11:39:15 -08001639 msg = Message.obtain(mAsyncServiceHandler,
Irfan Sheriffd3975a92012-02-24 10:54:13 -08001640 WifiManager.ENABLE_TRAFFIC_STATS_POLL, 1, 0);
Irfan Sheriff227bec42011-02-15 19:30:27 -08001641 } else {
Irfan Sheriffebe606f2011-02-24 11:39:15 -08001642 msg = Message.obtain(mAsyncServiceHandler,
Irfan Sheriffd3975a92012-02-24 10:54:13 -08001643 WifiManager.ENABLE_TRAFFIC_STATS_POLL, 0, 0);
Irfan Sheriff227bec42011-02-15 19:30:27 -08001644 }
1645 msg.sendToTarget();
1646 }
1647
1648 private void notifyOnDataActivity() {
1649 long sent, received;
1650 long preTxPkts = mTxPkts, preRxPkts = mRxPkts;
1651 int dataActivity = WifiManager.DATA_ACTIVITY_NONE;
1652
1653 mTxPkts = TrafficStats.getTxPackets(mInterfaceName);
1654 mRxPkts = TrafficStats.getRxPackets(mInterfaceName);
1655
1656 if (preTxPkts > 0 || preRxPkts > 0) {
1657 sent = mTxPkts - preTxPkts;
1658 received = mRxPkts - preRxPkts;
1659 if (sent > 0) {
1660 dataActivity |= WifiManager.DATA_ACTIVITY_OUT;
1661 }
1662 if (received > 0) {
1663 dataActivity |= WifiManager.DATA_ACTIVITY_IN;
1664 }
1665
1666 if (dataActivity != mDataActivity && !mScreenOff) {
1667 mDataActivity = dataActivity;
1668 for (AsyncChannel client : mClients) {
1669 client.sendMessage(WifiManager.DATA_ACTIVITY_NOTIFICATION, mDataActivity);
1670 }
1671 }
1672 }
1673 }
1674
1675
Irfan Sheriff0d255342010-07-28 09:35:20 -07001676 private void checkAndSetNotification() {
1677 // If we shouldn't place a notification on available networks, then
1678 // don't bother doing any of the following
1679 if (!mNotificationEnabled) return;
1680
1681 State state = mNetworkInfo.getState();
1682 if ((state == NetworkInfo.State.DISCONNECTED)
1683 || (state == NetworkInfo.State.UNKNOWN)) {
1684 // Look for an open network
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001685 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
Irfan Sheriff0d255342010-07-28 09:35:20 -07001686 if (scanResults != null) {
1687 int numOpenNetworks = 0;
1688 for (int i = scanResults.size() - 1; i >= 0; i--) {
1689 ScanResult scanResult = scanResults.get(i);
1690
Irfan Sherifffdd5f952011-08-04 16:55:54 -07001691 //A capability of [ESS] represents an open access point
1692 //that is available for an STA to connect
1693 if (scanResult.capabilities != null &&
1694 scanResult.capabilities.equals("[ESS]")) {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001695 numOpenNetworks++;
1696 }
1697 }
1698
1699 if (numOpenNetworks > 0) {
1700 if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
1701 /*
1702 * We've scanned continuously at least
1703 * NUM_SCANS_BEFORE_NOTIFICATION times. The user
1704 * probably does not have a remembered network in range,
1705 * since otherwise supplicant would have tried to
1706 * associate and thus resetting this counter.
1707 */
1708 setNotificationVisible(true, numOpenNetworks, false, 0);
1709 }
1710 return;
1711 }
1712 }
1713 }
1714
1715 // No open networks in range, remove the notification
1716 setNotificationVisible(false, 0, false, 0);
1717 }
1718
1719 /**
1720 * Clears variables related to tracking whether a notification has been
1721 * shown recently and clears the current notification.
1722 */
1723 private void resetNotification() {
1724 mNotificationRepeatTime = 0;
1725 mNumScansSinceNetworkStateChange = 0;
1726 setNotificationVisible(false, 0, false, 0);
1727 }
1728
1729 /**
1730 * Display or don't display a notification that there are open Wi-Fi networks.
1731 * @param visible {@code true} if notification should be visible, {@code false} otherwise
1732 * @param numNetworks the number networks seen
1733 * @param force {@code true} to force notification to be shown/not-shown,
1734 * even if it is already shown/not-shown.
1735 * @param delay time in milliseconds after which the notification should be made
1736 * visible or invisible.
1737 */
1738 private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
1739 int delay) {
1740
1741 // Since we use auto cancel on the notification, when the
1742 // mNetworksAvailableNotificationShown is true, the notification may
1743 // have actually been canceled. However, when it is false we know
1744 // for sure that it is not being shown (it will not be shown any other
1745 // place than here)
1746
1747 // If it should be hidden and it is already hidden, then noop
1748 if (!visible && !mNotificationShown && !force) {
1749 return;
1750 }
1751
1752 NotificationManager notificationManager = (NotificationManager) mContext
1753 .getSystemService(Context.NOTIFICATION_SERVICE);
1754
1755 Message message;
1756 if (visible) {
1757
1758 // Not enough time has passed to show the notification again
1759 if (System.currentTimeMillis() < mNotificationRepeatTime) {
1760 return;
1761 }
1762
1763 if (mNotification == null) {
Wink Savillec7a98342010-08-13 16:11:42 -07001764 // Cache the Notification object.
Irfan Sheriff0d255342010-07-28 09:35:20 -07001765 mNotification = new Notification();
1766 mNotification.when = 0;
1767 mNotification.icon = ICON_NETWORKS_AVAILABLE;
1768 mNotification.flags = Notification.FLAG_AUTO_CANCEL;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001769 mNotification.contentIntent = PendingIntent.getActivityAsUser(mContext, 0,
1770 new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK), 0,
1771 null, UserHandle.CURRENT);
Irfan Sheriff0d255342010-07-28 09:35:20 -07001772 }
1773
1774 CharSequence title = mContext.getResources().getQuantityText(
1775 com.android.internal.R.plurals.wifi_available, numNetworks);
1776 CharSequence details = mContext.getResources().getQuantityText(
1777 com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
1778 mNotification.tickerText = title;
1779 mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
1780
1781 mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
1782
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001783 notificationManager.notifyAsUser(null, ICON_NETWORKS_AVAILABLE, mNotification,
1784 UserHandle.ALL);
Irfan Sheriff0d255342010-07-28 09:35:20 -07001785 } else {
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001786 notificationManager.cancelAsUser(null, ICON_NETWORKS_AVAILABLE, UserHandle.ALL);
Irfan Sheriff0d255342010-07-28 09:35:20 -07001787 }
1788
Irfan Sheriff0d255342010-07-28 09:35:20 -07001789 mNotificationShown = visible;
1790 }
1791
1792 private class NotificationEnabledSettingObserver extends ContentObserver {
1793
1794 public NotificationEnabledSettingObserver(Handler handler) {
1795 super(handler);
1796 }
1797
1798 public void register() {
1799 ContentResolver cr = mContext.getContentResolver();
Christopher Tate6f5a9a92012-09-14 17:24:28 -07001800 cr.registerContentObserver(Settings.Global.getUriFor(
1801 Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
Irfan Sheriff0d255342010-07-28 09:35:20 -07001802 mNotificationEnabled = getValue();
1803 }
1804
1805 @Override
1806 public void onChange(boolean selfChange) {
1807 super.onChange(selfChange);
1808
1809 mNotificationEnabled = getValue();
1810 resetNotification();
1811 }
1812
1813 private boolean getValue() {
Christopher Tate6f5a9a92012-09-14 17:24:28 -07001814 return Settings.Global.getInt(mContext.getContentResolver(),
1815 Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
Irfan Sheriff0d255342010-07-28 09:35:20 -07001816 }
1817 }
1818
1819
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001820}