diff options
Diffstat (limited to 'services/core/java/com/android/server/wifi/WifiController.java')
-rw-r--r-- | services/core/java/com/android/server/wifi/WifiController.java | 751 |
1 files changed, 751 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/wifi/WifiController.java b/services/core/java/com/android/server/wifi/WifiController.java new file mode 100644 index 0000000..a3d514e --- /dev/null +++ b/services/core/java/com/android/server/wifi/WifiController.java @@ -0,0 +1,751 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wifi; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.database.ContentObserver; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import static android.net.wifi.WifiManager.WIFI_MODE_FULL; +import static android.net.wifi.WifiManager.WIFI_MODE_FULL_HIGH_PERF; +import static android.net.wifi.WifiManager.WIFI_MODE_SCAN_ONLY; +import android.net.wifi.WifiStateMachine; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.SystemClock; +import android.os.WorkSource; +import android.provider.Settings; +import android.util.Slog; + +import com.android.internal.util.Protocol; +import com.android.internal.util.State; +import com.android.internal.util.StateMachine; +import com.android.server.wifi.WifiService.LockList; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +class WifiController extends StateMachine { + private static final String TAG = "WifiController"; + private static final boolean DBG = false; + private Context mContext; + private boolean mScreenOff; + private boolean mDeviceIdle; + private int mPluggedType; + private int mStayAwakeConditions; + private long mIdleMillis; + private int mSleepPolicy; + private boolean mFirstUserSignOnSeen = false; + + private AlarmManager mAlarmManager; + private PendingIntent mIdleIntent; + private static final int IDLE_REQUEST = 0; + + /** + * See {@link Settings.Global#WIFI_IDLE_MS}. This is the default value if a + * Settings.Global value is not present. This timeout value is chosen as + * the approximate point at which the battery drain caused by Wi-Fi + * being enabled but not active exceeds the battery drain caused by + * re-establishing a connection to the mobile data network. + */ + private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */ + + /** + * See {@link Settings.Global#WIFI_REENABLE_DELAY_MS}. This is the default value if a + * Settings.Global value is not present. This is the minimum time after wifi is disabled + * we'll act on an enable. Enable requests received before this delay will be deferred. + */ + private static final long DEFAULT_REENABLE_DELAY_MS = 500; + + // finding that delayed messages can sometimes be delivered earlier than expected + // probably rounding errors.. add a margin to prevent problems + private static final long DEFER_MARGIN_MS = 5; + + NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", ""); + + private static final String ACTION_DEVICE_IDLE = + "com.android.server.WifiManager.action.DEVICE_IDLE"; + + /* References to values tracked in WifiService */ + final WifiStateMachine mWifiStateMachine; + final WifiSettingsStore mSettingsStore; + final LockList mLocks; + + /** + * Temporary for computing UIDS that are responsible for starting WIFI. + * Protected by mWifiStateTracker lock. + */ + private final WorkSource mTmpWorkSource = new WorkSource(); + + private long mReEnableDelayMillis; + + private static final int BASE = Protocol.BASE_WIFI_CONTROLLER; + + static final int CMD_EMERGENCY_MODE_CHANGED = BASE + 1; + static final int CMD_SCREEN_ON = BASE + 2; + static final int CMD_SCREEN_OFF = BASE + 3; + static final int CMD_BATTERY_CHANGED = BASE + 4; + static final int CMD_DEVICE_IDLE = BASE + 5; + static final int CMD_LOCKS_CHANGED = BASE + 6; + static final int CMD_SCAN_ALWAYS_MODE_CHANGED = BASE + 7; + static final int CMD_WIFI_TOGGLED = BASE + 8; + static final int CMD_AIRPLANE_TOGGLED = BASE + 9; + static final int CMD_SET_AP = BASE + 10; + static final int CMD_DEFERRED_TOGGLE = BASE + 11; + static final int CMD_USER_PRESENT = BASE + 12; + + private DefaultState mDefaultState = new DefaultState(); + private StaEnabledState mStaEnabledState = new StaEnabledState(); + private ApStaDisabledState mApStaDisabledState = new ApStaDisabledState(); + private StaDisabledWithScanState mStaDisabledWithScanState = new StaDisabledWithScanState(); + private ApEnabledState mApEnabledState = new ApEnabledState(); + private DeviceActiveState mDeviceActiveState = new DeviceActiveState(); + private DeviceInactiveState mDeviceInactiveState = new DeviceInactiveState(); + private ScanOnlyLockHeldState mScanOnlyLockHeldState = new ScanOnlyLockHeldState(); + private FullLockHeldState mFullLockHeldState = new FullLockHeldState(); + private FullHighPerfLockHeldState mFullHighPerfLockHeldState = new FullHighPerfLockHeldState(); + private NoLockHeldState mNoLockHeldState = new NoLockHeldState(); + private EcmState mEcmState = new EcmState(); + + WifiController(Context context, WifiService service, Looper looper) { + super(TAG, looper); + mContext = context; + mWifiStateMachine = service.mWifiStateMachine; + mSettingsStore = service.mSettingsStore; + mLocks = service.mLocks; + + mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); + Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null); + mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0); + + addState(mDefaultState); + addState(mApStaDisabledState, mDefaultState); + addState(mStaEnabledState, mDefaultState); + addState(mDeviceActiveState, mStaEnabledState); + addState(mDeviceInactiveState, mStaEnabledState); + addState(mScanOnlyLockHeldState, mDeviceInactiveState); + addState(mFullLockHeldState, mDeviceInactiveState); + addState(mFullHighPerfLockHeldState, mDeviceInactiveState); + addState(mNoLockHeldState, mDeviceInactiveState); + addState(mStaDisabledWithScanState, mDefaultState); + addState(mApEnabledState, mDefaultState); + addState(mEcmState, mDefaultState); + if (mSettingsStore.isScanAlwaysAvailable()) { + setInitialState(mStaDisabledWithScanState); + } else { + setInitialState(mApStaDisabledState); + } + setLogRecSize(100); + setLogOnlyTransitions(false); + + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_DEVICE_IDLE); + filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + mContext.registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(ACTION_DEVICE_IDLE)) { + sendMessage(CMD_DEVICE_IDLE); + } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { + mNetworkInfo = (NetworkInfo) intent.getParcelableExtra( + WifiManager.EXTRA_NETWORK_INFO); + } + } + }, + new IntentFilter(filter)); + + initializeAndRegisterForSettingsChange(looper); + } + + private void initializeAndRegisterForSettingsChange(Looper looper) { + Handler handler = new Handler(looper); + readStayAwakeConditions(); + registerForStayAwakeModeChange(handler); + readWifiIdleTime(); + registerForWifiIdleTimeChange(handler); + readWifiSleepPolicy(); + registerForWifiSleepPolicyChange(handler); + readWifiReEnableDelay(); + } + + private void readStayAwakeConditions() { + mStayAwakeConditions = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0); + } + + private void readWifiIdleTime() { + mIdleMillis = Settings.Global.getLong(mContext.getContentResolver(), + Settings.Global.WIFI_IDLE_MS, DEFAULT_IDLE_MS); + } + + private void readWifiSleepPolicy() { + mSleepPolicy = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.WIFI_SLEEP_POLICY, + Settings.Global.WIFI_SLEEP_POLICY_NEVER); + } + + private void readWifiReEnableDelay() { + mReEnableDelayMillis = Settings.Global.getLong(mContext.getContentResolver(), + Settings.Global.WIFI_REENABLE_DELAY_MS, DEFAULT_REENABLE_DELAY_MS); + } + + /** + * Observes settings changes to scan always mode. + */ + private void registerForStayAwakeModeChange(Handler handler) { + ContentObserver contentObserver = new ContentObserver(handler) { + @Override + public void onChange(boolean selfChange) { + readStayAwakeConditions(); + } + }; + + mContext.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(Settings.Global.STAY_ON_WHILE_PLUGGED_IN), + false, contentObserver); + } + + /** + * Observes settings changes to scan always mode. + */ + private void registerForWifiIdleTimeChange(Handler handler) { + ContentObserver contentObserver = new ContentObserver(handler) { + @Override + public void onChange(boolean selfChange) { + readWifiIdleTime(); + } + }; + + mContext.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(Settings.Global.WIFI_IDLE_MS), + false, contentObserver); + } + + /** + * Observes changes to wifi sleep policy + */ + private void registerForWifiSleepPolicyChange(Handler handler) { + ContentObserver contentObserver = new ContentObserver(handler) { + @Override + public void onChange(boolean selfChange) { + readWifiSleepPolicy(); + } + }; + mContext.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(Settings.Global.WIFI_SLEEP_POLICY), + false, contentObserver); + } + + /** + * Determines whether the Wi-Fi chipset should stay awake or be put to + * sleep. Looks at the setting for the sleep policy and the current + * conditions. + * + * @see #shouldDeviceStayAwake(int) + */ + private boolean shouldWifiStayAwake(int pluggedType) { + if (mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER) { + // Never sleep + return true; + } else if ((mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) && + (pluggedType != 0)) { + // Never sleep while plugged, and we're plugged + return true; + } else { + // Default + return shouldDeviceStayAwake(pluggedType); + } + } + + /** + * Determine whether the bit value corresponding to {@code pluggedType} is set in + * the bit string mStayAwakeConditions. This determines whether the device should + * stay awake based on the current plugged type. + * + * @param pluggedType the type of plug (USB, AC, or none) for which the check is + * being made + * @return {@code true} if {@code pluggedType} indicates that the device is + * supposed to stay awake, {@code false} otherwise. + */ + private boolean shouldDeviceStayAwake(int pluggedType) { + return (mStayAwakeConditions & pluggedType) != 0; + } + + private void updateBatteryWorkSource() { + mTmpWorkSource.clear(); + if (mDeviceIdle) { + mLocks.updateWorkSource(mTmpWorkSource); + } + mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource); + } + + class DefaultState extends State { + @Override + public boolean processMessage(Message msg) { + switch (msg.what) { + case CMD_SCREEN_ON: + mAlarmManager.cancel(mIdleIntent); + mScreenOff = false; + mDeviceIdle = false; + updateBatteryWorkSource(); + break; + case CMD_SCREEN_OFF: + mScreenOff = true; + /* + * Set a timer to put Wi-Fi to sleep, but only if the screen is off + * AND the "stay on while plugged in" setting doesn't match the + * current power conditions (i.e, not plugged in, plugged in to USB, + * or plugged in to AC). + */ + if (!shouldWifiStayAwake(mPluggedType)) { + //Delayed shutdown if wifi is connected + if (mNetworkInfo.getDetailedState() == + NetworkInfo.DetailedState.CONNECTED) { + if (DBG) Slog.d(TAG, "set idle timer: " + mIdleMillis + " ms"); + mAlarmManager.set(AlarmManager.RTC_WAKEUP, + System.currentTimeMillis() + mIdleMillis, mIdleIntent); + } else { + sendMessage(CMD_DEVICE_IDLE); + } + } + break; + case CMD_DEVICE_IDLE: + mDeviceIdle = true; + updateBatteryWorkSource(); + break; + case CMD_BATTERY_CHANGED: + /* + * Set a timer to put Wi-Fi to sleep, but only if the screen is off + * AND we are transitioning from a state in which the device was supposed + * to stay awake to a state in which it is not supposed to stay awake. + * If "stay awake" state is not changing, we do nothing, to avoid resetting + * the already-set timer. + */ + int pluggedType = msg.arg1; + if (DBG) Slog.d(TAG, "battery changed pluggedType: " + pluggedType); + if (mScreenOff && shouldWifiStayAwake(mPluggedType) && + !shouldWifiStayAwake(pluggedType)) { + long triggerTime = System.currentTimeMillis() + mIdleMillis; + if (DBG) Slog.d(TAG, "set idle timer for " + mIdleMillis + "ms"); + mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); + } + + mPluggedType = pluggedType; + break; + case CMD_SET_AP: + case CMD_SCAN_ALWAYS_MODE_CHANGED: + case CMD_LOCKS_CHANGED: + case CMD_WIFI_TOGGLED: + case CMD_AIRPLANE_TOGGLED: + case CMD_EMERGENCY_MODE_CHANGED: + break; + case CMD_USER_PRESENT: + mFirstUserSignOnSeen = true; + break; + case CMD_DEFERRED_TOGGLE: + log("DEFERRED_TOGGLE ignored due to state change"); + break; + default: + throw new RuntimeException("WifiController.handleMessage " + msg.what); + } + return HANDLED; + } + + } + + class ApStaDisabledState extends State { + private int mDeferredEnableSerialNumber = 0; + private boolean mHaveDeferredEnable = false; + private long mDisabledTimestamp; + + @Override + public void enter() { + mWifiStateMachine.setSupplicantRunning(false); + // Supplicant can't restart right away, so not the time we switched off + mDisabledTimestamp = SystemClock.elapsedRealtime(); + mDeferredEnableSerialNumber++; + mHaveDeferredEnable = false; + } + @Override + public boolean processMessage(Message msg) { + switch (msg.what) { + case CMD_WIFI_TOGGLED: + case CMD_AIRPLANE_TOGGLED: + if (mSettingsStore.isWifiToggleEnabled()) { + if (doDeferEnable(msg)) { + if (mHaveDeferredEnable) { + // have 2 toggles now, inc serial number an ignore both + mDeferredEnableSerialNumber++; + } + mHaveDeferredEnable = !mHaveDeferredEnable; + break; + } + if (mDeviceIdle == false) { + transitionTo(mDeviceActiveState); + } else { + checkLocksAndTransitionWhenDeviceIdle(); + } + } + break; + case CMD_SCAN_ALWAYS_MODE_CHANGED: + if (mSettingsStore.isScanAlwaysAvailable()) { + transitionTo(mStaDisabledWithScanState); + } + break; + case CMD_SET_AP: + if (msg.arg1 == 1) { + mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj, + true); + transitionTo(mApEnabledState); + } + break; + case CMD_DEFERRED_TOGGLE: + if (msg.arg1 != mDeferredEnableSerialNumber) { + log("DEFERRED_TOGGLE ignored due to serial mismatch"); + break; + } + log("DEFERRED_TOGGLE handled"); + sendMessage((Message)(msg.obj)); + break; + default: + return NOT_HANDLED; + } + return HANDLED; + } + + private boolean doDeferEnable(Message msg) { + long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp; + if (delaySoFar >= mReEnableDelayMillis) { + return false; + } + + log("WifiController msg " + msg + " deferred for " + + (mReEnableDelayMillis - delaySoFar) + "ms"); + + // need to defer this action. + Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE); + deferredMsg.obj = Message.obtain(msg); + deferredMsg.arg1 = ++mDeferredEnableSerialNumber; + sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS); + return true; + } + + } + + class StaEnabledState extends State { + @Override + public void enter() { + mWifiStateMachine.setSupplicantRunning(true); + } + @Override + public boolean processMessage(Message msg) { + switch (msg.what) { + case CMD_WIFI_TOGGLED: + if (! mSettingsStore.isWifiToggleEnabled()) { + if (mSettingsStore.isScanAlwaysAvailable()) { + transitionTo(mStaDisabledWithScanState); + } else { + transitionTo(mApStaDisabledState); + } + } + break; + case CMD_AIRPLANE_TOGGLED: + /* When wi-fi is turned off due to airplane, + * disable entirely (including scan) + */ + if (! mSettingsStore.isWifiToggleEnabled()) { + transitionTo(mApStaDisabledState); + } + break; + case CMD_EMERGENCY_MODE_CHANGED: + if (msg.arg1 == 1) { + transitionTo(mEcmState); + break; + } + default: + return NOT_HANDLED; + + } + return HANDLED; + } + } + + class StaDisabledWithScanState extends State { + private int mDeferredEnableSerialNumber = 0; + private boolean mHaveDeferredEnable = false; + private long mDisabledTimestamp; + + @Override + public void enter() { + mWifiStateMachine.setSupplicantRunning(true); + mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE); + mWifiStateMachine.setDriverStart(true); + // Supplicant can't restart right away, so not the time we switched off + mDisabledTimestamp = SystemClock.elapsedRealtime(); + mDeferredEnableSerialNumber++; + mHaveDeferredEnable = false; + } + + @Override + public boolean processMessage(Message msg) { + switch (msg.what) { + case CMD_WIFI_TOGGLED: + if (mSettingsStore.isWifiToggleEnabled()) { + if (doDeferEnable(msg)) { + if (mHaveDeferredEnable) { + // have 2 toggles now, inc serial number and ignore both + mDeferredEnableSerialNumber++; + } + mHaveDeferredEnable = !mHaveDeferredEnable; + break; + } + if (mDeviceIdle == false) { + transitionTo(mDeviceActiveState); + } else { + checkLocksAndTransitionWhenDeviceIdle(); + } + } + break; + case CMD_AIRPLANE_TOGGLED: + if (mSettingsStore.isAirplaneModeOn() && + ! mSettingsStore.isWifiToggleEnabled()) { + transitionTo(mApStaDisabledState); + } + case CMD_SCAN_ALWAYS_MODE_CHANGED: + if (! mSettingsStore.isScanAlwaysAvailable()) { + transitionTo(mApStaDisabledState); + } + break; + case CMD_SET_AP: + // Before starting tethering, turn off supplicant for scan mode + if (msg.arg1 == 1) { + deferMessage(msg); + transitionTo(mApStaDisabledState); + } + break; + case CMD_DEFERRED_TOGGLE: + if (msg.arg1 != mDeferredEnableSerialNumber) { + log("DEFERRED_TOGGLE ignored due to serial mismatch"); + break; + } + logd("DEFERRED_TOGGLE handled"); + sendMessage((Message)(msg.obj)); + break; + default: + return NOT_HANDLED; + } + return HANDLED; + } + + private boolean doDeferEnable(Message msg) { + long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp; + if (delaySoFar >= mReEnableDelayMillis) { + return false; + } + + log("WifiController msg " + msg + " deferred for " + + (mReEnableDelayMillis - delaySoFar) + "ms"); + + // need to defer this action. + Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE); + deferredMsg.obj = Message.obtain(msg); + deferredMsg.arg1 = ++mDeferredEnableSerialNumber; + sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS); + return true; + } + + } + + class ApEnabledState extends State { + @Override + public boolean processMessage(Message msg) { + switch (msg.what) { + case CMD_AIRPLANE_TOGGLED: + if (mSettingsStore.isAirplaneModeOn()) { + mWifiStateMachine.setHostApRunning(null, false); + transitionTo(mApStaDisabledState); + } + break; + case CMD_SET_AP: + if (msg.arg1 == 0) { + mWifiStateMachine.setHostApRunning(null, false); + transitionTo(mApStaDisabledState); + } + break; + default: + return NOT_HANDLED; + } + return HANDLED; + } + } + + class EcmState extends State { + @Override + public void enter() { + mWifiStateMachine.setSupplicantRunning(false); + } + + @Override + public boolean processMessage(Message msg) { + if (msg.what == CMD_EMERGENCY_MODE_CHANGED && msg.arg1 == 0) { + if (mSettingsStore.isWifiToggleEnabled()) { + if (mDeviceIdle == false) { + transitionTo(mDeviceActiveState); + } else { + checkLocksAndTransitionWhenDeviceIdle(); + } + } else if (mSettingsStore.isScanAlwaysAvailable()) { + transitionTo(mStaDisabledWithScanState); + } else { + transitionTo(mApStaDisabledState); + } + return HANDLED; + } else { + return NOT_HANDLED; + } + } + } + + /* Parent: StaEnabledState */ + class DeviceActiveState extends State { + @Override + public void enter() { + mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); + mWifiStateMachine.setDriverStart(true); + mWifiStateMachine.setHighPerfModeEnabled(false); + } + + @Override + public boolean processMessage(Message msg) { + if (msg.what == CMD_DEVICE_IDLE) { + checkLocksAndTransitionWhenDeviceIdle(); + // We let default state handle the rest of work + } else if (msg.what == CMD_USER_PRESENT) { + // TLS networks can't connect until user unlocks keystore. KeyStore + // unlocks when the user punches PIN after the reboot. So use this + // trigger to get those networks connected. + if (mFirstUserSignOnSeen == false) { + mWifiStateMachine.reloadTlsNetworksAndReconnect(); + } + mFirstUserSignOnSeen = true; + return HANDLED; + } + return NOT_HANDLED; + } + } + + /* Parent: StaEnabledState */ + class DeviceInactiveState extends State { + @Override + public boolean processMessage(Message msg) { + switch (msg.what) { + case CMD_LOCKS_CHANGED: + checkLocksAndTransitionWhenDeviceIdle(); + updateBatteryWorkSource(); + return HANDLED; + case CMD_SCREEN_ON: + transitionTo(mDeviceActiveState); + // More work in default state + return NOT_HANDLED; + default: + return NOT_HANDLED; + } + } + } + + /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a scan only lock. */ + class ScanOnlyLockHeldState extends State { + @Override + public void enter() { + mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE); + mWifiStateMachine.setDriverStart(true); + } + } + + /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a full lock. */ + class FullLockHeldState extends State { + @Override + public void enter() { + mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); + mWifiStateMachine.setDriverStart(true); + mWifiStateMachine.setHighPerfModeEnabled(false); + } + } + + /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a high perf lock. */ + class FullHighPerfLockHeldState extends State { + @Override + public void enter() { + mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); + mWifiStateMachine.setDriverStart(true); + mWifiStateMachine.setHighPerfModeEnabled(true); + } + } + + /* Parent: DeviceInactiveState. Device is inactive and no app is holding a wifi lock. */ + class NoLockHeldState extends State { + @Override + public void enter() { + mWifiStateMachine.setDriverStart(false); + } + } + + private void checkLocksAndTransitionWhenDeviceIdle() { + if (mLocks.hasLocks()) { + switch (mLocks.getStrongestLockMode()) { + case WIFI_MODE_FULL: + transitionTo(mFullLockHeldState); + break; + case WIFI_MODE_FULL_HIGH_PERF: + transitionTo(mFullHighPerfLockHeldState); + break; + case WIFI_MODE_SCAN_ONLY: + transitionTo(mScanOnlyLockHeldState); + break; + default: + loge("Illegal lock " + mLocks.getStrongestLockMode()); + } + } else { + if (mSettingsStore.isScanAlwaysAvailable()) { + transitionTo(mScanOnlyLockHeldState); + } else { + transitionTo(mNoLockHeldState); + } + } + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + super.dump(fd, pw, args); + + pw.println("mScreenOff " + mScreenOff); + pw.println("mDeviceIdle " + mDeviceIdle); + pw.println("mPluggedType " + mPluggedType); + pw.println("mIdleMillis " + mIdleMillis); + pw.println("mSleepPolicy " + mSleepPolicy); + } +} |