Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2013 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package com.android.server.wifi; |
| 18 | |
| 19 | import android.app.AlarmManager; |
| 20 | import android.app.PendingIntent; |
| 21 | import android.content.BroadcastReceiver; |
| 22 | import android.content.Context; |
| 23 | import android.content.Intent; |
| 24 | import android.content.IntentFilter; |
| 25 | import android.database.ContentObserver; |
| 26 | import android.net.ConnectivityManager; |
| 27 | import android.net.NetworkInfo; |
| 28 | import android.net.wifi.WifiConfiguration; |
| 29 | import android.net.wifi.WifiManager; |
| 30 | import static android.net.wifi.WifiManager.WIFI_MODE_FULL; |
| 31 | import static android.net.wifi.WifiManager.WIFI_MODE_FULL_HIGH_PERF; |
| 32 | import static android.net.wifi.WifiManager.WIFI_MODE_SCAN_ONLY; |
| 33 | import android.net.wifi.WifiStateMachine; |
| 34 | import android.os.Handler; |
| 35 | import android.os.Looper; |
| 36 | import android.os.Message; |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 37 | import android.os.SystemClock; |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 38 | import android.os.WorkSource; |
| 39 | import android.provider.Settings; |
| 40 | import android.util.Slog; |
| 41 | |
| 42 | import com.android.internal.util.Protocol; |
| 43 | import com.android.internal.util.State; |
| 44 | import com.android.internal.util.StateMachine; |
| 45 | import com.android.server.wifi.WifiService.LockList; |
| 46 | |
| 47 | import java.io.FileDescriptor; |
| 48 | import java.io.PrintWriter; |
| 49 | |
| 50 | class WifiController extends StateMachine { |
| 51 | private static final String TAG = "WifiController"; |
| 52 | private static final boolean DBG = false; |
| 53 | private Context mContext; |
| 54 | private boolean mScreenOff; |
| 55 | private boolean mDeviceIdle; |
| 56 | private int mPluggedType; |
| 57 | private int mStayAwakeConditions; |
| 58 | private long mIdleMillis; |
| 59 | private int mSleepPolicy; |
Vinit Deshapnde | a3038b2 | 2013-10-02 17:26:05 -0700 | [diff] [blame] | 60 | private boolean mFirstUserSignOnSeen = false; |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 61 | |
| 62 | private AlarmManager mAlarmManager; |
| 63 | private PendingIntent mIdleIntent; |
| 64 | private static final int IDLE_REQUEST = 0; |
| 65 | |
| 66 | /** |
| 67 | * See {@link Settings.Global#WIFI_IDLE_MS}. This is the default value if a |
| 68 | * Settings.Global value is not present. This timeout value is chosen as |
| 69 | * the approximate point at which the battery drain caused by Wi-Fi |
| 70 | * being enabled but not active exceeds the battery drain caused by |
| 71 | * re-establishing a connection to the mobile data network. |
| 72 | */ |
| 73 | private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */ |
| 74 | |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 75 | /** |
| 76 | * See {@link Settings.Global#WIFI_REENABLE_DELAY_MS}. This is the default value if a |
| 77 | * Settings.Global value is not present. This is the minimum time after wifi is disabled |
| 78 | * we'll act on an enable. Enable requests received before this delay will be deferred. |
| 79 | */ |
| 80 | private static final long DEFAULT_REENABLE_DELAY_MS = 500; |
| 81 | |
Robert Greenwalt | e47d7d4 | 2013-05-20 11:49:46 -0700 | [diff] [blame] | 82 | // finding that delayed messages can sometimes be delivered earlier than expected |
| 83 | // probably rounding errors.. add a margin to prevent problems |
| 84 | private static final long DEFER_MARGIN_MS = 5; |
| 85 | |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 86 | NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", ""); |
| 87 | |
| 88 | private static final String ACTION_DEVICE_IDLE = |
| 89 | "com.android.server.WifiManager.action.DEVICE_IDLE"; |
| 90 | |
| 91 | /* References to values tracked in WifiService */ |
| 92 | final WifiStateMachine mWifiStateMachine; |
| 93 | final WifiSettingsStore mSettingsStore; |
| 94 | final LockList mLocks; |
| 95 | |
| 96 | /** |
| 97 | * Temporary for computing UIDS that are responsible for starting WIFI. |
| 98 | * Protected by mWifiStateTracker lock. |
| 99 | */ |
| 100 | private final WorkSource mTmpWorkSource = new WorkSource(); |
| 101 | |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 102 | private long mReEnableDelayMillis; |
| 103 | |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 104 | private static final int BASE = Protocol.BASE_WIFI_CONTROLLER; |
| 105 | |
| 106 | static final int CMD_EMERGENCY_MODE_CHANGED = BASE + 1; |
| 107 | static final int CMD_SCREEN_ON = BASE + 2; |
| 108 | static final int CMD_SCREEN_OFF = BASE + 3; |
| 109 | static final int CMD_BATTERY_CHANGED = BASE + 4; |
| 110 | static final int CMD_DEVICE_IDLE = BASE + 5; |
| 111 | static final int CMD_LOCKS_CHANGED = BASE + 6; |
| 112 | static final int CMD_SCAN_ALWAYS_MODE_CHANGED = BASE + 7; |
| 113 | static final int CMD_WIFI_TOGGLED = BASE + 8; |
| 114 | static final int CMD_AIRPLANE_TOGGLED = BASE + 9; |
| 115 | static final int CMD_SET_AP = BASE + 10; |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 116 | static final int CMD_DEFERRED_TOGGLE = BASE + 11; |
Vinit Deshapnde | a3038b2 | 2013-10-02 17:26:05 -0700 | [diff] [blame] | 117 | static final int CMD_USER_PRESENT = BASE + 12; |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 118 | |
| 119 | private DefaultState mDefaultState = new DefaultState(); |
| 120 | private StaEnabledState mStaEnabledState = new StaEnabledState(); |
| 121 | private ApStaDisabledState mApStaDisabledState = new ApStaDisabledState(); |
| 122 | private StaDisabledWithScanState mStaDisabledWithScanState = new StaDisabledWithScanState(); |
| 123 | private ApEnabledState mApEnabledState = new ApEnabledState(); |
| 124 | private DeviceActiveState mDeviceActiveState = new DeviceActiveState(); |
| 125 | private DeviceInactiveState mDeviceInactiveState = new DeviceInactiveState(); |
| 126 | private ScanOnlyLockHeldState mScanOnlyLockHeldState = new ScanOnlyLockHeldState(); |
| 127 | private FullLockHeldState mFullLockHeldState = new FullLockHeldState(); |
| 128 | private FullHighPerfLockHeldState mFullHighPerfLockHeldState = new FullHighPerfLockHeldState(); |
| 129 | private NoLockHeldState mNoLockHeldState = new NoLockHeldState(); |
| 130 | private EcmState mEcmState = new EcmState(); |
| 131 | |
| 132 | WifiController(Context context, WifiService service, Looper looper) { |
| 133 | super(TAG, looper); |
| 134 | mContext = context; |
| 135 | mWifiStateMachine = service.mWifiStateMachine; |
| 136 | mSettingsStore = service.mSettingsStore; |
| 137 | mLocks = service.mLocks; |
| 138 | |
| 139 | mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); |
| 140 | Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null); |
| 141 | mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0); |
| 142 | |
| 143 | addState(mDefaultState); |
| 144 | addState(mApStaDisabledState, mDefaultState); |
| 145 | addState(mStaEnabledState, mDefaultState); |
| 146 | addState(mDeviceActiveState, mStaEnabledState); |
| 147 | addState(mDeviceInactiveState, mStaEnabledState); |
| 148 | addState(mScanOnlyLockHeldState, mDeviceInactiveState); |
| 149 | addState(mFullLockHeldState, mDeviceInactiveState); |
| 150 | addState(mFullHighPerfLockHeldState, mDeviceInactiveState); |
| 151 | addState(mNoLockHeldState, mDeviceInactiveState); |
| 152 | addState(mStaDisabledWithScanState, mDefaultState); |
| 153 | addState(mApEnabledState, mDefaultState); |
| 154 | addState(mEcmState, mDefaultState); |
Robert Greenwalt | 05caa2a | 2013-06-01 10:59:29 -0700 | [diff] [blame] | 155 | if (mSettingsStore.isScanAlwaysAvailable()) { |
| 156 | setInitialState(mStaDisabledWithScanState); |
| 157 | } else { |
| 158 | setInitialState(mApStaDisabledState); |
| 159 | } |
Robert Greenwalt | 02ba86f | 2013-05-18 11:24:22 -0700 | [diff] [blame] | 160 | setLogRecSize(100); |
| 161 | setLogOnlyTransitions(false); |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 162 | |
| 163 | IntentFilter filter = new IntentFilter(); |
| 164 | filter.addAction(ACTION_DEVICE_IDLE); |
| 165 | filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); |
| 166 | mContext.registerReceiver( |
| 167 | new BroadcastReceiver() { |
| 168 | @Override |
| 169 | public void onReceive(Context context, Intent intent) { |
| 170 | String action = intent.getAction(); |
| 171 | if (action.equals(ACTION_DEVICE_IDLE)) { |
| 172 | sendMessage(CMD_DEVICE_IDLE); |
| 173 | } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { |
| 174 | mNetworkInfo = (NetworkInfo) intent.getParcelableExtra( |
| 175 | WifiManager.EXTRA_NETWORK_INFO); |
| 176 | } |
| 177 | } |
| 178 | }, |
| 179 | new IntentFilter(filter)); |
| 180 | |
| 181 | initializeAndRegisterForSettingsChange(looper); |
| 182 | } |
| 183 | |
| 184 | private void initializeAndRegisterForSettingsChange(Looper looper) { |
| 185 | Handler handler = new Handler(looper); |
| 186 | readStayAwakeConditions(); |
| 187 | registerForStayAwakeModeChange(handler); |
| 188 | readWifiIdleTime(); |
| 189 | registerForWifiIdleTimeChange(handler); |
Irfan Sheriff | 9f2e831 | 2013-03-19 14:32:11 -0700 | [diff] [blame] | 190 | readWifiSleepPolicy(); |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 191 | registerForWifiSleepPolicyChange(handler); |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 192 | readWifiReEnableDelay(); |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 193 | } |
| 194 | |
| 195 | private void readStayAwakeConditions() { |
| 196 | mStayAwakeConditions = Settings.Global.getInt(mContext.getContentResolver(), |
| 197 | Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0); |
| 198 | } |
| 199 | |
| 200 | private void readWifiIdleTime() { |
| 201 | mIdleMillis = Settings.Global.getLong(mContext.getContentResolver(), |
| 202 | Settings.Global.WIFI_IDLE_MS, DEFAULT_IDLE_MS); |
| 203 | } |
| 204 | |
| 205 | private void readWifiSleepPolicy() { |
| 206 | mSleepPolicy = Settings.Global.getInt(mContext.getContentResolver(), |
| 207 | Settings.Global.WIFI_SLEEP_POLICY, |
| 208 | Settings.Global.WIFI_SLEEP_POLICY_NEVER); |
| 209 | } |
| 210 | |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 211 | private void readWifiReEnableDelay() { |
| 212 | mReEnableDelayMillis = Settings.Global.getLong(mContext.getContentResolver(), |
| 213 | Settings.Global.WIFI_REENABLE_DELAY_MS, DEFAULT_REENABLE_DELAY_MS); |
| 214 | } |
| 215 | |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 216 | /** |
| 217 | * Observes settings changes to scan always mode. |
| 218 | */ |
| 219 | private void registerForStayAwakeModeChange(Handler handler) { |
| 220 | ContentObserver contentObserver = new ContentObserver(handler) { |
| 221 | @Override |
| 222 | public void onChange(boolean selfChange) { |
| 223 | readStayAwakeConditions(); |
| 224 | } |
| 225 | }; |
| 226 | |
| 227 | mContext.getContentResolver().registerContentObserver( |
| 228 | Settings.Global.getUriFor(Settings.Global.STAY_ON_WHILE_PLUGGED_IN), |
| 229 | false, contentObserver); |
| 230 | } |
| 231 | |
| 232 | /** |
| 233 | * Observes settings changes to scan always mode. |
| 234 | */ |
| 235 | private void registerForWifiIdleTimeChange(Handler handler) { |
| 236 | ContentObserver contentObserver = new ContentObserver(handler) { |
| 237 | @Override |
| 238 | public void onChange(boolean selfChange) { |
| 239 | readWifiIdleTime(); |
| 240 | } |
| 241 | }; |
| 242 | |
| 243 | mContext.getContentResolver().registerContentObserver( |
| 244 | Settings.Global.getUriFor(Settings.Global.WIFI_IDLE_MS), |
| 245 | false, contentObserver); |
| 246 | } |
| 247 | |
| 248 | /** |
| 249 | * Observes changes to wifi sleep policy |
| 250 | */ |
| 251 | private void registerForWifiSleepPolicyChange(Handler handler) { |
| 252 | ContentObserver contentObserver = new ContentObserver(handler) { |
| 253 | @Override |
| 254 | public void onChange(boolean selfChange) { |
| 255 | readWifiSleepPolicy(); |
| 256 | } |
| 257 | }; |
| 258 | mContext.getContentResolver().registerContentObserver( |
| 259 | Settings.Global.getUriFor(Settings.Global.WIFI_SLEEP_POLICY), |
| 260 | false, contentObserver); |
| 261 | } |
| 262 | |
| 263 | /** |
| 264 | * Determines whether the Wi-Fi chipset should stay awake or be put to |
| 265 | * sleep. Looks at the setting for the sleep policy and the current |
| 266 | * conditions. |
| 267 | * |
| 268 | * @see #shouldDeviceStayAwake(int) |
| 269 | */ |
| 270 | private boolean shouldWifiStayAwake(int pluggedType) { |
| 271 | if (mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER) { |
| 272 | // Never sleep |
| 273 | return true; |
| 274 | } else if ((mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) && |
| 275 | (pluggedType != 0)) { |
| 276 | // Never sleep while plugged, and we're plugged |
| 277 | return true; |
| 278 | } else { |
| 279 | // Default |
| 280 | return shouldDeviceStayAwake(pluggedType); |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | /** |
| 285 | * Determine whether the bit value corresponding to {@code pluggedType} is set in |
| 286 | * the bit string mStayAwakeConditions. This determines whether the device should |
| 287 | * stay awake based on the current plugged type. |
| 288 | * |
| 289 | * @param pluggedType the type of plug (USB, AC, or none) for which the check is |
| 290 | * being made |
| 291 | * @return {@code true} if {@code pluggedType} indicates that the device is |
| 292 | * supposed to stay awake, {@code false} otherwise. |
| 293 | */ |
| 294 | private boolean shouldDeviceStayAwake(int pluggedType) { |
| 295 | return (mStayAwakeConditions & pluggedType) != 0; |
| 296 | } |
| 297 | |
| 298 | private void updateBatteryWorkSource() { |
| 299 | mTmpWorkSource.clear(); |
| 300 | if (mDeviceIdle) { |
| 301 | mLocks.updateWorkSource(mTmpWorkSource); |
| 302 | } |
| 303 | mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource); |
| 304 | } |
| 305 | |
| 306 | class DefaultState extends State { |
| 307 | @Override |
| 308 | public boolean processMessage(Message msg) { |
| 309 | switch (msg.what) { |
| 310 | case CMD_SCREEN_ON: |
| 311 | mAlarmManager.cancel(mIdleIntent); |
| 312 | mScreenOff = false; |
| 313 | mDeviceIdle = false; |
| 314 | updateBatteryWorkSource(); |
| 315 | break; |
| 316 | case CMD_SCREEN_OFF: |
| 317 | mScreenOff = true; |
| 318 | /* |
| 319 | * Set a timer to put Wi-Fi to sleep, but only if the screen is off |
| 320 | * AND the "stay on while plugged in" setting doesn't match the |
| 321 | * current power conditions (i.e, not plugged in, plugged in to USB, |
| 322 | * or plugged in to AC). |
| 323 | */ |
| 324 | if (!shouldWifiStayAwake(mPluggedType)) { |
| 325 | //Delayed shutdown if wifi is connected |
| 326 | if (mNetworkInfo.getDetailedState() == |
| 327 | NetworkInfo.DetailedState.CONNECTED) { |
| 328 | if (DBG) Slog.d(TAG, "set idle timer: " + mIdleMillis + " ms"); |
| 329 | mAlarmManager.set(AlarmManager.RTC_WAKEUP, |
| 330 | System.currentTimeMillis() + mIdleMillis, mIdleIntent); |
| 331 | } else { |
| 332 | sendMessage(CMD_DEVICE_IDLE); |
| 333 | } |
| 334 | } |
| 335 | break; |
| 336 | case CMD_DEVICE_IDLE: |
| 337 | mDeviceIdle = true; |
| 338 | updateBatteryWorkSource(); |
| 339 | break; |
| 340 | case CMD_BATTERY_CHANGED: |
| 341 | /* |
| 342 | * Set a timer to put Wi-Fi to sleep, but only if the screen is off |
| 343 | * AND we are transitioning from a state in which the device was supposed |
| 344 | * to stay awake to a state in which it is not supposed to stay awake. |
| 345 | * If "stay awake" state is not changing, we do nothing, to avoid resetting |
| 346 | * the already-set timer. |
| 347 | */ |
| 348 | int pluggedType = msg.arg1; |
| 349 | if (DBG) Slog.d(TAG, "battery changed pluggedType: " + pluggedType); |
| 350 | if (mScreenOff && shouldWifiStayAwake(mPluggedType) && |
| 351 | !shouldWifiStayAwake(pluggedType)) { |
| 352 | long triggerTime = System.currentTimeMillis() + mIdleMillis; |
| 353 | if (DBG) Slog.d(TAG, "set idle timer for " + mIdleMillis + "ms"); |
| 354 | mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); |
| 355 | } |
| 356 | |
| 357 | mPluggedType = pluggedType; |
| 358 | break; |
| 359 | case CMD_SET_AP: |
| 360 | case CMD_SCAN_ALWAYS_MODE_CHANGED: |
| 361 | case CMD_LOCKS_CHANGED: |
| 362 | case CMD_WIFI_TOGGLED: |
| 363 | case CMD_AIRPLANE_TOGGLED: |
| 364 | case CMD_EMERGENCY_MODE_CHANGED: |
Robert Greenwalt | 02ba86f | 2013-05-18 11:24:22 -0700 | [diff] [blame] | 365 | break; |
Vinit Deshapnde | a3038b2 | 2013-10-02 17:26:05 -0700 | [diff] [blame] | 366 | case CMD_USER_PRESENT: |
| 367 | mFirstUserSignOnSeen = true; |
| 368 | break; |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 369 | case CMD_DEFERRED_TOGGLE: |
Robert Greenwalt | 02ba86f | 2013-05-18 11:24:22 -0700 | [diff] [blame] | 370 | log("DEFERRED_TOGGLE ignored due to state change"); |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 371 | break; |
| 372 | default: |
| 373 | throw new RuntimeException("WifiController.handleMessage " + msg.what); |
| 374 | } |
| 375 | return HANDLED; |
| 376 | } |
| 377 | |
| 378 | } |
| 379 | |
| 380 | class ApStaDisabledState extends State { |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 381 | private int mDeferredEnableSerialNumber = 0; |
| 382 | private boolean mHaveDeferredEnable = false; |
| 383 | private long mDisabledTimestamp; |
| 384 | |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 385 | @Override |
| 386 | public void enter() { |
| 387 | mWifiStateMachine.setSupplicantRunning(false); |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 388 | // Supplicant can't restart right away, so not the time we switched off |
| 389 | mDisabledTimestamp = SystemClock.elapsedRealtime(); |
| 390 | mDeferredEnableSerialNumber++; |
| 391 | mHaveDeferredEnable = false; |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 392 | } |
| 393 | @Override |
| 394 | public boolean processMessage(Message msg) { |
| 395 | switch (msg.what) { |
| 396 | case CMD_WIFI_TOGGLED: |
| 397 | case CMD_AIRPLANE_TOGGLED: |
| 398 | if (mSettingsStore.isWifiToggleEnabled()) { |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 399 | if (doDeferEnable(msg)) { |
| 400 | if (mHaveDeferredEnable) { |
| 401 | // have 2 toggles now, inc serial number an ignore both |
| 402 | mDeferredEnableSerialNumber++; |
| 403 | } |
| 404 | mHaveDeferredEnable = !mHaveDeferredEnable; |
| 405 | break; |
| 406 | } |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 407 | if (mDeviceIdle == false) { |
| 408 | transitionTo(mDeviceActiveState); |
| 409 | } else { |
| 410 | checkLocksAndTransitionWhenDeviceIdle(); |
| 411 | } |
| 412 | } |
| 413 | break; |
| 414 | case CMD_SCAN_ALWAYS_MODE_CHANGED: |
| 415 | if (mSettingsStore.isScanAlwaysAvailable()) { |
| 416 | transitionTo(mStaDisabledWithScanState); |
| 417 | } |
| 418 | break; |
| 419 | case CMD_SET_AP: |
| 420 | if (msg.arg1 == 1) { |
| 421 | mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj, |
| 422 | true); |
| 423 | transitionTo(mApEnabledState); |
| 424 | } |
| 425 | break; |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 426 | case CMD_DEFERRED_TOGGLE: |
Robert Greenwalt | 02ba86f | 2013-05-18 11:24:22 -0700 | [diff] [blame] | 427 | if (msg.arg1 != mDeferredEnableSerialNumber) { |
| 428 | log("DEFERRED_TOGGLE ignored due to serial mismatch"); |
| 429 | break; |
| 430 | } |
| 431 | log("DEFERRED_TOGGLE handled"); |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 432 | sendMessage((Message)(msg.obj)); |
| 433 | break; |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 434 | default: |
| 435 | return NOT_HANDLED; |
| 436 | } |
| 437 | return HANDLED; |
| 438 | } |
| 439 | |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 440 | private boolean doDeferEnable(Message msg) { |
| 441 | long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp; |
Robert Greenwalt | 5c11e8e | 2013-05-20 09:28:08 -0700 | [diff] [blame] | 442 | if (delaySoFar >= mReEnableDelayMillis) { |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 443 | return false; |
| 444 | } |
| 445 | |
Robert Greenwalt | 02ba86f | 2013-05-18 11:24:22 -0700 | [diff] [blame] | 446 | log("WifiController msg " + msg + " deferred for " + |
| 447 | (mReEnableDelayMillis - delaySoFar) + "ms"); |
| 448 | |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 449 | // need to defer this action. |
| 450 | Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE); |
| 451 | deferredMsg.obj = Message.obtain(msg); |
| 452 | deferredMsg.arg1 = ++mDeferredEnableSerialNumber; |
Robert Greenwalt | e47d7d4 | 2013-05-20 11:49:46 -0700 | [diff] [blame] | 453 | sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS); |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 454 | return true; |
| 455 | } |
| 456 | |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 457 | } |
| 458 | |
| 459 | class StaEnabledState extends State { |
| 460 | @Override |
| 461 | public void enter() { |
| 462 | mWifiStateMachine.setSupplicantRunning(true); |
| 463 | } |
| 464 | @Override |
| 465 | public boolean processMessage(Message msg) { |
| 466 | switch (msg.what) { |
| 467 | case CMD_WIFI_TOGGLED: |
| 468 | if (! mSettingsStore.isWifiToggleEnabled()) { |
| 469 | if (mSettingsStore.isScanAlwaysAvailable()) { |
| 470 | transitionTo(mStaDisabledWithScanState); |
| 471 | } else { |
| 472 | transitionTo(mApStaDisabledState); |
| 473 | } |
| 474 | } |
| 475 | break; |
| 476 | case CMD_AIRPLANE_TOGGLED: |
| 477 | /* When wi-fi is turned off due to airplane, |
| 478 | * disable entirely (including scan) |
| 479 | */ |
| 480 | if (! mSettingsStore.isWifiToggleEnabled()) { |
| 481 | transitionTo(mApStaDisabledState); |
| 482 | } |
| 483 | break; |
| 484 | case CMD_EMERGENCY_MODE_CHANGED: |
| 485 | if (msg.arg1 == 1) { |
| 486 | transitionTo(mEcmState); |
| 487 | break; |
| 488 | } |
| 489 | default: |
| 490 | return NOT_HANDLED; |
| 491 | |
| 492 | } |
| 493 | return HANDLED; |
| 494 | } |
| 495 | } |
| 496 | |
| 497 | class StaDisabledWithScanState extends State { |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 498 | private int mDeferredEnableSerialNumber = 0; |
| 499 | private boolean mHaveDeferredEnable = false; |
| 500 | private long mDisabledTimestamp; |
| 501 | |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 502 | @Override |
| 503 | public void enter() { |
| 504 | mWifiStateMachine.setSupplicantRunning(true); |
| 505 | mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE); |
| 506 | mWifiStateMachine.setDriverStart(true); |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 507 | // Supplicant can't restart right away, so not the time we switched off |
| 508 | mDisabledTimestamp = SystemClock.elapsedRealtime(); |
| 509 | mDeferredEnableSerialNumber++; |
| 510 | mHaveDeferredEnable = false; |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 511 | } |
| 512 | |
| 513 | @Override |
| 514 | public boolean processMessage(Message msg) { |
| 515 | switch (msg.what) { |
| 516 | case CMD_WIFI_TOGGLED: |
| 517 | if (mSettingsStore.isWifiToggleEnabled()) { |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 518 | if (doDeferEnable(msg)) { |
| 519 | if (mHaveDeferredEnable) { |
| 520 | // have 2 toggles now, inc serial number and ignore both |
| 521 | mDeferredEnableSerialNumber++; |
| 522 | } |
| 523 | mHaveDeferredEnable = !mHaveDeferredEnable; |
| 524 | break; |
| 525 | } |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 526 | if (mDeviceIdle == false) { |
| 527 | transitionTo(mDeviceActiveState); |
| 528 | } else { |
| 529 | checkLocksAndTransitionWhenDeviceIdle(); |
| 530 | } |
| 531 | } |
| 532 | break; |
| 533 | case CMD_AIRPLANE_TOGGLED: |
| 534 | if (mSettingsStore.isAirplaneModeOn() && |
| 535 | ! mSettingsStore.isWifiToggleEnabled()) { |
| 536 | transitionTo(mApStaDisabledState); |
| 537 | } |
| 538 | case CMD_SCAN_ALWAYS_MODE_CHANGED: |
| 539 | if (! mSettingsStore.isScanAlwaysAvailable()) { |
| 540 | transitionTo(mApStaDisabledState); |
| 541 | } |
| 542 | break; |
| 543 | case CMD_SET_AP: |
| 544 | // Before starting tethering, turn off supplicant for scan mode |
| 545 | if (msg.arg1 == 1) { |
| 546 | deferMessage(msg); |
| 547 | transitionTo(mApStaDisabledState); |
| 548 | } |
| 549 | break; |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 550 | case CMD_DEFERRED_TOGGLE: |
Robert Greenwalt | 02ba86f | 2013-05-18 11:24:22 -0700 | [diff] [blame] | 551 | if (msg.arg1 != mDeferredEnableSerialNumber) { |
| 552 | log("DEFERRED_TOGGLE ignored due to serial mismatch"); |
| 553 | break; |
| 554 | } |
| 555 | logd("DEFERRED_TOGGLE handled"); |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 556 | sendMessage((Message)(msg.obj)); |
| 557 | break; |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 558 | default: |
| 559 | return NOT_HANDLED; |
| 560 | } |
| 561 | return HANDLED; |
| 562 | } |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 563 | |
| 564 | private boolean doDeferEnable(Message msg) { |
| 565 | long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp; |
Robert Greenwalt | 5c11e8e | 2013-05-20 09:28:08 -0700 | [diff] [blame] | 566 | if (delaySoFar >= mReEnableDelayMillis) { |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 567 | return false; |
| 568 | } |
Robert Greenwalt | 02ba86f | 2013-05-18 11:24:22 -0700 | [diff] [blame] | 569 | |
| 570 | log("WifiController msg " + msg + " deferred for " + |
| 571 | (mReEnableDelayMillis - delaySoFar) + "ms"); |
| 572 | |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 573 | // need to defer this action. |
| 574 | Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE); |
| 575 | deferredMsg.obj = Message.obtain(msg); |
| 576 | deferredMsg.arg1 = ++mDeferredEnableSerialNumber; |
Robert Greenwalt | e47d7d4 | 2013-05-20 11:49:46 -0700 | [diff] [blame] | 577 | sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS); |
Robert Greenwalt | c12783a | 2013-05-16 12:48:20 -0700 | [diff] [blame] | 578 | return true; |
| 579 | } |
| 580 | |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 581 | } |
| 582 | |
| 583 | class ApEnabledState extends State { |
| 584 | @Override |
| 585 | public boolean processMessage(Message msg) { |
| 586 | switch (msg.what) { |
| 587 | case CMD_AIRPLANE_TOGGLED: |
| 588 | if (mSettingsStore.isAirplaneModeOn()) { |
| 589 | mWifiStateMachine.setHostApRunning(null, false); |
| 590 | transitionTo(mApStaDisabledState); |
| 591 | } |
| 592 | break; |
| 593 | case CMD_SET_AP: |
| 594 | if (msg.arg1 == 0) { |
| 595 | mWifiStateMachine.setHostApRunning(null, false); |
| 596 | transitionTo(mApStaDisabledState); |
| 597 | } |
| 598 | break; |
| 599 | default: |
| 600 | return NOT_HANDLED; |
| 601 | } |
| 602 | return HANDLED; |
| 603 | } |
| 604 | } |
| 605 | |
| 606 | class EcmState extends State { |
| 607 | @Override |
| 608 | public void enter() { |
| 609 | mWifiStateMachine.setSupplicantRunning(false); |
| 610 | } |
| 611 | |
| 612 | @Override |
| 613 | public boolean processMessage(Message msg) { |
| 614 | if (msg.what == CMD_EMERGENCY_MODE_CHANGED && msg.arg1 == 0) { |
| 615 | if (mSettingsStore.isWifiToggleEnabled()) { |
| 616 | if (mDeviceIdle == false) { |
| 617 | transitionTo(mDeviceActiveState); |
| 618 | } else { |
| 619 | checkLocksAndTransitionWhenDeviceIdle(); |
| 620 | } |
| 621 | } else if (mSettingsStore.isScanAlwaysAvailable()) { |
| 622 | transitionTo(mStaDisabledWithScanState); |
| 623 | } else { |
| 624 | transitionTo(mApStaDisabledState); |
| 625 | } |
| 626 | return HANDLED; |
| 627 | } else { |
| 628 | return NOT_HANDLED; |
| 629 | } |
| 630 | } |
| 631 | } |
| 632 | |
| 633 | /* Parent: StaEnabledState */ |
| 634 | class DeviceActiveState extends State { |
| 635 | @Override |
| 636 | public void enter() { |
| 637 | mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); |
| 638 | mWifiStateMachine.setDriverStart(true); |
| 639 | mWifiStateMachine.setHighPerfModeEnabled(false); |
| 640 | } |
| 641 | |
| 642 | @Override |
| 643 | public boolean processMessage(Message msg) { |
| 644 | if (msg.what == CMD_DEVICE_IDLE) { |
| 645 | checkLocksAndTransitionWhenDeviceIdle(); |
| 646 | // We let default state handle the rest of work |
Vinit Deshapnde | a3038b2 | 2013-10-02 17:26:05 -0700 | [diff] [blame] | 647 | } else if (msg.what == CMD_USER_PRESENT) { |
| 648 | // TLS networks can't connect until user unlocks keystore. KeyStore |
| 649 | // unlocks when the user punches PIN after the reboot. So use this |
| 650 | // trigger to get those networks connected. |
| 651 | if (mFirstUserSignOnSeen == false) { |
| 652 | mWifiStateMachine.reloadTlsNetworksAndReconnect(); |
| 653 | } |
| 654 | mFirstUserSignOnSeen = true; |
| 655 | return HANDLED; |
Irfan Sheriff | 11aefad | 2013-03-06 07:57:41 -0800 | [diff] [blame] | 656 | } |
| 657 | return NOT_HANDLED; |
| 658 | } |
| 659 | } |
| 660 | |
| 661 | /* Parent: StaEnabledState */ |
| 662 | class DeviceInactiveState extends State { |
| 663 | @Override |
| 664 | public boolean processMessage(Message msg) { |
| 665 | switch (msg.what) { |
| 666 | case CMD_LOCKS_CHANGED: |
| 667 | checkLocksAndTransitionWhenDeviceIdle(); |
| 668 | updateBatteryWorkSource(); |
| 669 | return HANDLED; |
| 670 | case CMD_SCREEN_ON: |
| 671 | transitionTo(mDeviceActiveState); |
| 672 | // More work in default state |
| 673 | return NOT_HANDLED; |
| 674 | default: |
| 675 | return NOT_HANDLED; |
| 676 | } |
| 677 | } |
| 678 | } |
| 679 | |
| 680 | /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a scan only lock. */ |
| 681 | class ScanOnlyLockHeldState extends State { |
| 682 | @Override |
| 683 | public void enter() { |
| 684 | mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE); |
| 685 | mWifiStateMachine.setDriverStart(true); |
| 686 | } |
| 687 | } |
| 688 | |
| 689 | /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a full lock. */ |
| 690 | class FullLockHeldState extends State { |
| 691 | @Override |
| 692 | public void enter() { |
| 693 | mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); |
| 694 | mWifiStateMachine.setDriverStart(true); |
| 695 | mWifiStateMachine.setHighPerfModeEnabled(false); |
| 696 | } |
| 697 | } |
| 698 | |
| 699 | /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a high perf lock. */ |
| 700 | class FullHighPerfLockHeldState extends State { |
| 701 | @Override |
| 702 | public void enter() { |
| 703 | mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); |
| 704 | mWifiStateMachine.setDriverStart(true); |
| 705 | mWifiStateMachine.setHighPerfModeEnabled(true); |
| 706 | } |
| 707 | } |
| 708 | |
| 709 | /* Parent: DeviceInactiveState. Device is inactive and no app is holding a wifi lock. */ |
| 710 | class NoLockHeldState extends State { |
| 711 | @Override |
| 712 | public void enter() { |
| 713 | mWifiStateMachine.setDriverStart(false); |
| 714 | } |
| 715 | } |
| 716 | |
| 717 | private void checkLocksAndTransitionWhenDeviceIdle() { |
| 718 | if (mLocks.hasLocks()) { |
| 719 | switch (mLocks.getStrongestLockMode()) { |
| 720 | case WIFI_MODE_FULL: |
| 721 | transitionTo(mFullLockHeldState); |
| 722 | break; |
| 723 | case WIFI_MODE_FULL_HIGH_PERF: |
| 724 | transitionTo(mFullHighPerfLockHeldState); |
| 725 | break; |
| 726 | case WIFI_MODE_SCAN_ONLY: |
| 727 | transitionTo(mScanOnlyLockHeldState); |
| 728 | break; |
| 729 | default: |
| 730 | loge("Illegal lock " + mLocks.getStrongestLockMode()); |
| 731 | } |
| 732 | } else { |
| 733 | if (mSettingsStore.isScanAlwaysAvailable()) { |
| 734 | transitionTo(mScanOnlyLockHeldState); |
| 735 | } else { |
| 736 | transitionTo(mNoLockHeldState); |
| 737 | } |
| 738 | } |
| 739 | } |
| 740 | |
| 741 | @Override |
| 742 | public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { |
| 743 | super.dump(fd, pw, args); |
| 744 | |
| 745 | pw.println("mScreenOff " + mScreenOff); |
| 746 | pw.println("mDeviceIdle " + mDeviceIdle); |
| 747 | pw.println("mPluggedType " + mPluggedType); |
| 748 | pw.println("mIdleMillis " + mIdleMillis); |
| 749 | pw.println("mSleepPolicy " + mSleepPolicy); |
| 750 | } |
| 751 | } |