diff options
author | Irfan Sheriff <isheriff@google.com> | 2013-03-06 07:57:41 -0800 |
---|---|---|
committer | Irfan Sheriff <isheriff@google.com> | 2013-03-14 13:55:56 -0700 |
commit | 11aefad94de6569c4c7394e7bc5fdeb0ae60d5bb (patch) | |
tree | 4df4926fa0f9b8bf577b182fd52078a6b0ea8eb1 | |
parent | 1c80a05176c9a6cdef2975cc655f34588275194e (diff) | |
download | frameworks_base-11aefad94de6569c4c7394e7bc5fdeb0ae60d5bb.zip frameworks_base-11aefad94de6569c4c7394e7bc5fdeb0ae60d5bb.tar.gz frameworks_base-11aefad94de6569c4c7394e7bc5fdeb0ae60d5bb.tar.bz2 |
Add support for scan always available mode
Modify WifiService to add a controller to track the various
desired states and let the WifiStatemachine actually control
the bring up.
Bug: 8141918
Change-Id: I6e98fd5a29b43c3c50c315eff5255cd0a3eaebcd
-rw-r--r-- | core/java/android/provider/Settings.java | 8 | ||||
-rw-r--r-- | core/java/com/android/internal/util/Protocol.java | 1 | ||||
-rw-r--r-- | services/java/com/android/server/wifi/README.txt | 12 | ||||
-rw-r--r-- | services/java/com/android/server/wifi/WifiController.java | 626 | ||||
-rw-r--r-- | services/java/com/android/server/wifi/WifiService.java | 318 | ||||
-rw-r--r-- | services/java/com/android/server/wifi/WifiSettingsStore.java | 23 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/IWifiManager.aidl | 4 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiConfigStore.java | 17 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiStateMachine.java | 361 |
9 files changed, 952 insertions, 418 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 266d0d3..d251ca2 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -4784,6 +4784,13 @@ public final class Settings { public static final String WIFI_ON = "wifi_on"; /** + * Setting to allow scans to be enabled even wifi is turned off for connectivity. + * @hide + */ + public static final String WIFI_SCAN_ALWAYS_AVAILABLE = + "wifi_scan_always_enabled"; + + /** * Used to save the Wifi_ON state prior to tethering. * This state will be checked to restore Wifi after * the user turns off tethering. @@ -5345,6 +5352,7 @@ public final class Settings { WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED, + WIFI_SCAN_ALWAYS_AVAILABLE, WIFI_NUM_OPEN_NETWORKS_KEPT, EMERGENCY_TONE, CALL_AUTO_RETRY, diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java index 7c2b1b5..91b109e 100644 --- a/core/java/com/android/internal/util/Protocol.java +++ b/core/java/com/android/internal/util/Protocol.java @@ -45,6 +45,7 @@ public class Protocol { public static final int BASE_WIFI_P2P_SERVICE = 0x00023000; public static final int BASE_WIFI_MONITOR = 0x00024000; public static final int BASE_WIFI_MANAGER = 0x00025000; + public static final int BASE_WIFI_CONTROLLER = 0x00026000; public static final int BASE_DHCP = 0x00030000; public static final int BASE_DATA_CONNECTION = 0x00040000; public static final int BASE_DATA_CONNECTION_AC = 0x00041000; diff --git a/services/java/com/android/server/wifi/README.txt b/services/java/com/android/server/wifi/README.txt new file mode 100644 index 0000000..c03bff5 --- /dev/null +++ b/services/java/com/android/server/wifi/README.txt @@ -0,0 +1,12 @@ +WifiService: Implements the IWifiManager 3rd party API. The API and the device state information (screen on/off, battery state, sleep policy) go as input into the WifiController which tracks high level states as to whether STA or AP mode is operational and controls the WifiStateMachine to handle bringup and shut down. + +WifiController: Acts as a controller to the WifiStateMachine based on various inputs (API and device state). Runs on the same thread created in WifiService. + +WifiSettingsStore: Tracks the various settings (wifi toggle, airplane toggle, tethering toggle, scan mode toggle) and provides API to figure if wifi should be turned on or off. + +WifiTrafficPoller: Polls traffic on wifi and notifies apps listening on it. + +WifiNotificationController: Controls whether the open network notification is displayed or not based on the scan results. + +WifiStateMachine: Tracks the various states on STA and AP connectivity and handles bring up and shut down. + diff --git a/services/java/com/android/server/wifi/WifiController.java b/services/java/com/android/server/wifi/WifiController.java new file mode 100644 index 0000000..4d7c434 --- /dev/null +++ b/services/java/com/android/server/wifi/WifiController.java @@ -0,0 +1,626 @@ +/* + * 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.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 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 */ + + 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 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; + + 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); + setInitialState(mApStaDisabledState); + setLogRecSize(25); + setLogOnlyTransitions(true); + + 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); + readStayAwakeConditions(); + registerForWifiSleepPolicyChange(handler); + } + + 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); + } + + /** + * 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; + default: + throw new RuntimeException("WifiController.handleMessage " + msg.what); + } + return HANDLED; + } + + } + + class ApStaDisabledState extends State { + @Override + public void enter() { + mWifiStateMachine.setSupplicantRunning(false); + } + @Override + public boolean processMessage(Message msg) { + switch (msg.what) { + case CMD_WIFI_TOGGLED: + case CMD_AIRPLANE_TOGGLED: + if (mSettingsStore.isWifiToggleEnabled()) { + 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; + default: + return NOT_HANDLED; + } + return HANDLED; + } + + } + + 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 { + @Override + public void enter() { + mWifiStateMachine.setSupplicantRunning(true); + mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE); + mWifiStateMachine.setDriverStart(true); + } + + @Override + public boolean processMessage(Message msg) { + switch (msg.what) { + case CMD_WIFI_TOGGLED: + if (mSettingsStore.isWifiToggleEnabled()) { + 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; + default: + return NOT_HANDLED; + } + return HANDLED; + } + } + + 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 + } + 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); + } +} diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java index d675822..bc6bdaf 100644 --- a/services/java/com/android/server/wifi/WifiService.java +++ b/services/java/com/android/server/wifi/WifiService.java @@ -17,15 +17,14 @@ package com.android.server.wifi; import android.app.ActivityManager; -import android.app.AlarmManager; import android.app.AppOpsManager; -import android.app.PendingIntent; import android.bluetooth.BluetoothAdapter; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.database.ContentObserver; import android.net.wifi.IWifiManager; import android.net.wifi.ScanResult; import android.net.wifi.WifiInfo; @@ -33,12 +32,9 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiStateMachine; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiWatchdogStateMachine; -import android.net.ConnectivityManager; import android.net.DhcpInfo; import android.net.DhcpResults; import android.net.LinkAddress; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; import android.net.NetworkUtils; import android.net.RouteInfo; import android.os.Binder; @@ -63,39 +59,35 @@ import java.net.Inet4Address; import java.util.ArrayList; import java.util.List; +import com.android.internal.R; import com.android.internal.app.IBatteryStats; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.AsyncChannel; import com.android.server.am.BatteryStatsService; -import com.android.internal.R; - +import static com.android.server.wifi.WifiController.CMD_AIRPLANE_TOGGLED; +import static com.android.server.wifi.WifiController.CMD_BATTERY_CHANGED; +import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED; +import static com.android.server.wifi.WifiController.CMD_LOCKS_CHANGED; +import static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED; +import static com.android.server.wifi.WifiController.CMD_SCREEN_OFF; +import static com.android.server.wifi.WifiController.CMD_SCREEN_ON; +import static com.android.server.wifi.WifiController.CMD_SET_AP; +import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED; /** * WifiService handles remote WiFi operation requests by implementing * the IWifiManager interface. * * @hide */ -//TODO: Clean up multiple locks and implement WifiService -// as a SM to track soft AP/client/adhoc bring up based -// on device idle state, airplane mode and boot. - public final class WifiService extends IWifiManager.Stub { private static final String TAG = "WifiService"; private static final boolean DBG = false; - private final WifiStateMachine mWifiStateMachine; + final WifiStateMachine mWifiStateMachine; private final Context mContext; - private AlarmManager mAlarmManager; - private PendingIntent mIdleIntent; - private static final int IDLE_REQUEST = 0; - private boolean mScreenOff; - private boolean mDeviceIdle; - private boolean mEmergencyCallbackMode = false; - private int mPluggedType; - - private final LockList mLocks = new LockList(); + final LockList mLocks = new LockList(); // some wifi lock statistics private int mFullHighPerfLocksAcquired; private int mFullHighPerfLocksReleased; @@ -119,19 +111,7 @@ public final class WifiService extends IWifiManager.Stub { /* Polls traffic stats and notifies clients */ private WifiTrafficPoller mTrafficPoller; /* Tracks the persisted states for wi-fi & airplane mode */ - private WifiSettingsStore mSettingsStore; - - /** - * 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 */ - - private static final String ACTION_DEVICE_IDLE = - "com.android.server.WifiManager.action.DEVICE_IDLE"; + final WifiSettingsStore mSettingsStore; /* The work source (UID) that triggered the current WIFI scan, synchronized * on this */ @@ -139,8 +119,6 @@ public final class WifiService extends IWifiManager.Stub { private boolean mIsReceiverRegistered = false; - NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", ""); - /** * Asynchronous channel to WifiStateMachine */ @@ -195,7 +173,7 @@ public final class WifiService extends IWifiManager.Stub { break; } default: { - Slog.d(TAG, "WifiServicehandler.handleMessage ignoring msg=" + msg); + Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg); break; } } @@ -243,11 +221,6 @@ public final class WifiService extends IWifiManager.Stub { } WifiStateMachineHandler mWifiStateMachineHandler; - /** - * Temporary for computing UIDS that are responsible for starting WIFI. - * Protected by mWifiStateTracker lock. - */ - private final WorkSource mTmpWorkSource = new WorkSource(); private WifiWatchdogStateMachine mWifiWatchdogStateMachine; public WifiService(Context context) { @@ -260,20 +233,24 @@ public final class WifiService extends IWifiManager.Stub { mBatteryStats = BatteryStatsService.getService(); mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); - mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); - Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null); - mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0); - mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine); mTrafficPoller = new WifiTrafficPoller(mContext, mInterfaceName); mSettingsStore = new WifiSettingsStore(mContext); + HandlerThread wifiThread = new HandlerThread("WifiService"); + wifiThread.start(); + mClientHandler = new ClientHandler(wifiThread.getLooper()); + mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper()); + mWifiController = new WifiController(mContext, this, wifiThread.getLooper()); + mWifiController.start(); + + registerForScanModeChange(); mContext.registerReceiver( new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (mSettingsStore.handleAirplaneModeToggled()) { - updateWifiState(); + mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED); } } }, @@ -289,13 +266,10 @@ public final class WifiService extends IWifiManager.Stub { } } }, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); - - HandlerThread wifiThread = new HandlerThread("WifiService"); - wifiThread.start(); - mClientHandler = new ClientHandler(wifiThread.getLooper()); - mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper()); } + private WifiController mWifiController; + /** Tell battery stats about a new WIFI scan */ private void noteScanStart() { WorkSource scanWorkSource = null; @@ -342,7 +316,7 @@ public final class WifiService extends IWifiManager.Stub { */ public void checkAndStartWifi() { /* Check if wi-fi needs to be enabled */ - boolean wifiEnabled = mSettingsStore.shouldWifiBeEnabled(); + boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled(); Slog.i(TAG, "WifiService starting up with Wi-Fi " + (wifiEnabled ? "enabled" : "disabled")); @@ -430,11 +404,7 @@ public final class WifiService extends IWifiManager.Stub { Binder.restoreCallingIdentity(ident); } - if (enable) { - reportStartWorkSource(); - } - - mWifiStateMachine.setWifiEnabled(enable); + mWifiController.sendMessage(CMD_WIFI_TOGGLED); if (enable) { if (!mIsReceiverRegistered) { @@ -470,7 +440,7 @@ public final class WifiService extends IWifiManager.Stub { */ public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) { enforceChangePermission(); - mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled); + mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget(); } /** @@ -507,6 +477,26 @@ public final class WifiService extends IWifiManager.Stub { } /** + * @param enable {@code true} to enable, {@code false} to disable. + * @return {@code true} if the enable/disable operation was + * started or is already in the queue. + */ + public boolean isScanningAlwaysAvailable() { + // TODO: implement + return true; + } + + /** + * @param enable {@code true} to enable, {@code false} to disable. + * @return {@code true} if the enable/disable operation was + * started or is already in the queue. + */ + public void setScanningAlwaysAvailable(boolean enable) { + // TODO: implement + } + + + /** * see {@link android.net.wifi.WifiManager#disconnect()} */ public void disconnect() { @@ -777,7 +767,7 @@ public final class WifiService extends IWifiManager.Stub { * of WifiLock & device idle status unless wifi enabled status is toggled */ - mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode); + mWifiStateMachine.setDriverStart(true); mWifiStateMachine.reconnectCommand(); } @@ -796,7 +786,7 @@ public final class WifiService extends IWifiManager.Stub { * TODO: if a stop is issued, wifi is brought up only by startWifi * unless wifi enabled status is toggled */ - mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode); + mWifiStateMachine.setDriverStart(false); } /** @@ -848,175 +838,39 @@ public final class WifiService extends IWifiManager.Stub { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - - long idleMillis = - Settings.Global.getLong(mContext.getContentResolver(), - Settings.Global.WIFI_IDLE_MS, DEFAULT_IDLE_MS); - int stayAwakeConditions = - Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0); if (action.equals(Intent.ACTION_SCREEN_ON)) { - if (DBG) { - Slog.d(TAG, "ACTION_SCREEN_ON"); - } - mAlarmManager.cancel(mIdleIntent); - mScreenOff = false; - setDeviceIdleAndUpdateWifi(false); + mWifiController.sendMessage(CMD_SCREEN_ON); } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { - if (DBG) { - Slog.d(TAG, "ACTION_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(stayAwakeConditions, mPluggedType)) { - //Delayed shutdown if wifi is connected - if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { - if (DBG) Slog.d(TAG, "setting ACTION_DEVICE_IDLE: " + idleMillis + " ms"); - mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() - + idleMillis, mIdleIntent); - } else { - setDeviceIdleAndUpdateWifi(true); - } - } - } else if (action.equals(ACTION_DEVICE_IDLE)) { - setDeviceIdleAndUpdateWifi(true); + mWifiController.sendMessage(CMD_SCREEN_OFF); } else if (action.equals(Intent.ACTION_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 = intent.getIntExtra("plugged", 0); - if (DBG) { - Slog.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType); - } - if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) && - !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) { - long triggerTime = System.currentTimeMillis() + idleMillis; - if (DBG) { - Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms"); - } - mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); - } - - mPluggedType = pluggedType; + mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null); } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) { int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, BluetoothAdapter.STATE_DISCONNECTED); mWifiStateMachine.sendBluetoothAdapterStateChange(state); } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { - mEmergencyCallbackMode = intent.getBooleanExtra("phoneinECMState", false); - updateWifiState(); + boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false); + mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0); } } - - /** - * 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, int) - */ - private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) { - //Never sleep as long as the user has not changed the settings - int wifiSleepPolicy = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.WIFI_SLEEP_POLICY, - Settings.Global.WIFI_SLEEP_POLICY_NEVER); - - if (wifiSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER) { - // Never sleep - return true; - } else if ((wifiSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) && - (pluggedType != 0)) { - // Never sleep while plugged, and we're plugged - return true; - } else { - // Default - return shouldDeviceStayAwake(stayAwakeConditions, pluggedType); - } - } - - /** - * Determine whether the bit value corresponding to {@code pluggedType} is set in - * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value - * of {@code 0} isn't really a plugged type, but rather an indication that the - * device isn't plugged in at all, there is no bit value corresponding to a - * {@code pluggedType} value of {@code 0}. That is why we shift by - * {@code pluggedType - 1} instead of by {@code pluggedType}. - * @param stayAwakeConditions a bit string specifying which "plugged types" should - * keep the device (and hence Wi-Fi) awake. - * @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 stayAwakeConditions, int pluggedType) { - return (stayAwakeConditions & pluggedType) != 0; - } }; - private void setDeviceIdleAndUpdateWifi(boolean deviceIdle) { - mDeviceIdle = deviceIdle; - reportStartWorkSource(); - updateWifiState(); - } - - private synchronized void reportStartWorkSource() { - mTmpWorkSource.clear(); - if (mDeviceIdle) { - for (int i=0; i<mLocks.mList.size(); i++) { - mTmpWorkSource.add(mLocks.mList.get(i).mWorkSource); + /** + * Observes settings changes to scan always mode. + */ + private void registerForScanModeChange() { + ContentObserver contentObserver = new ContentObserver(null) { + @Override + public void onChange(boolean selfChange) { + mSettingsStore.handleWifiScanAlwaysAvailableToggled(); + mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED); } - } - mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource); - } - - private void updateWifiState() { - boolean lockHeld = mLocks.hasLocks(); - int strongestLockMode = WifiManager.WIFI_MODE_FULL; - boolean wifiShouldBeStarted; - - if (mEmergencyCallbackMode) { - wifiShouldBeStarted = false; - } else { - wifiShouldBeStarted = !mDeviceIdle || lockHeld; - } - - if (lockHeld) { - strongestLockMode = mLocks.getStrongestLockMode(); - } - /* If device is not idle, lockmode cannot be scan only */ - if (!mDeviceIdle && strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY) { - strongestLockMode = WifiManager.WIFI_MODE_FULL; - } - - /* Disable tethering when airplane mode is enabled */ - if (mSettingsStore.isAirplaneModeOn()) { - mWifiStateMachine.setWifiApEnabled(null, false); - } + }; - if (mSettingsStore.shouldWifiBeEnabled()) { - if (wifiShouldBeStarted) { - reportStartWorkSource(); - mWifiStateMachine.setWifiEnabled(true); - mWifiStateMachine.setScanOnlyMode( - strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY); - mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode); - mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode - == WifiManager.WIFI_MODE_FULL_HIGH_PERF); - } else { - mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode); - } - } else { - mWifiStateMachine.setWifiEnabled(false); - } + mContext.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE), + false, contentObserver); } private void registerForBroadcasts() { @@ -1024,7 +878,7 @@ public final class WifiService extends IWifiManager.Stub { intentFilter.addAction(Intent.ACTION_SCREEN_ON); intentFilter.addAction(Intent.ACTION_SCREEN_OFF); intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); - intentFilter.addAction(ACTION_DEVICE_IDLE); + intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); mContext.registerReceiver(mReceiver, intentFilter); @@ -1043,12 +897,9 @@ public final class WifiService extends IWifiManager.Stub { pw.println("Stay-awake conditions: " + Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0)); - pw.println("mScreenOff " + mScreenOff); - pw.println("mDeviceIdle " + mDeviceIdle); - pw.println("mPluggedType " + mPluggedType); - pw.println("mEmergencyCallbackMode " + mEmergencyCallbackMode); pw.println("mMulticastEnabled " + mMulticastEnabled); pw.println("mMulticastDisabled " + mMulticastDisabled); + mWifiController.dump(fd, pw, args); mSettingsStore.dump(fd, pw, args); mNotificationController.dump(fd, pw, args); mTrafficPoller.dump(fd, pw, args); @@ -1099,18 +950,18 @@ public final class WifiService extends IWifiManager.Stub { } } - private class LockList { + class LockList { private List<WifiLock> mList; private LockList() { mList = new ArrayList<WifiLock>(); } - private synchronized boolean hasLocks() { + synchronized boolean hasLocks() { return !mList.isEmpty(); } - private synchronized int getStrongestLockMode() { + synchronized int getStrongestLockMode() { if (mList.isEmpty()) { return WifiManager.WIFI_MODE_FULL; } @@ -1126,6 +977,12 @@ public final class WifiService extends IWifiManager.Stub { return WifiManager.WIFI_MODE_SCAN_ONLY; } + synchronized void updateWorkSource(WorkSource ws) { + for (int i = 0; i < mLocks.mList.size(); i++) { + ws.add(mLocks.mList.get(i).mWorkSource); + } + } + private void addLock(WifiLock lock) { if (findLockByBinder(lock.mBinder) < 0) { mList.add(lock); @@ -1145,9 +1002,10 @@ public final class WifiService extends IWifiManager.Stub { private int findLockByBinder(IBinder binder) { int size = mList.size(); - for (int i = size - 1; i >= 0; i--) + for (int i = size - 1; i >= 0; i--) { if (mList.get(i).mBinder == binder) return i; + } return -1; } @@ -1231,12 +1089,7 @@ public final class WifiService extends IWifiManager.Stub { ++mScanLocksAcquired; break; } - - // Be aggressive about adding new locks into the accounted state... - // we want to over-report rather than under-report. - reportStartWorkSource(); - - updateWifiState(); + mWifiController.sendMessage(CMD_LOCKS_CHANGED); return true; } catch (RemoteException e) { return false; @@ -1303,11 +1156,8 @@ public final class WifiService extends IWifiManager.Stub { ++mScanLocksReleased; break; } + mWifiController.sendMessage(CMD_LOCKS_CHANGED); } - - // TODO - should this only happen if you hadLock? - updateWifiState(); - } catch (RemoteException e) { } finally { Binder.restoreCallingIdentity(ident); diff --git a/services/java/com/android/server/wifi/WifiSettingsStore.java b/services/java/com/android/server/wifi/WifiSettingsStore.java index d7c8752..3ff8061 100644 --- a/services/java/com/android/server/wifi/WifiSettingsStore.java +++ b/services/java/com/android/server/wifi/WifiSettingsStore.java @@ -37,7 +37,11 @@ final class WifiSettingsStore { private int mPersistWifiState = WIFI_DISABLED; /* Tracks current airplane mode state */ private boolean mAirplaneModeOn = false; - /* Tracks whether wifi is enabled from WifiStateMachine's perspective */ + + /* Tracks the setting of scan being available even when wi-fi is turned off + */ + private boolean mScanAlwaysAvailable; + private final Context mContext; /* Tracks if we have checked the saved wi-fi state after boot */ @@ -47,9 +51,10 @@ final class WifiSettingsStore { mContext = context; mAirplaneModeOn = getPersistedAirplaneModeOn(); mPersistWifiState = getPersistedWifiState(); + mScanAlwaysAvailable = getPersistedScanAlwaysAvailable(); } - synchronized boolean shouldWifiBeEnabled() { + synchronized boolean isWifiToggleEnabled() { if (!mCheckSavedStateAtBoot) { mCheckSavedStateAtBoot = true; if (testAndClearWifiSavedState()) return true; @@ -70,6 +75,10 @@ final class WifiSettingsStore { return mAirplaneModeOn; } + synchronized boolean isScanAlwaysAvailable() { + return mScanAlwaysAvailable; + } + synchronized boolean handleWifiToggled(boolean wifiEnabled) { // Can Wi-Fi be toggled in airplane mode ? if (mAirplaneModeOn && !isAirplaneToggleable()) { @@ -114,6 +123,10 @@ final class WifiSettingsStore { return true; } + synchronized void handleWifiScanAlwaysAvailableToggled() { + mScanAlwaysAvailable = getPersistedScanAlwaysAvailable(); + } + void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("mPersistWifiState " + mPersistWifiState); pw.println("mAirplaneModeOn " + mAirplaneModeOn); @@ -175,4 +188,10 @@ final class WifiSettingsStore { return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) == 1; } + + private boolean getPersistedScanAlwaysAvailable() { + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, + 0) == 1; + } } diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index bef5824..e0684fb 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -71,6 +71,10 @@ interface IWifiManager DhcpInfo getDhcpInfo(); + boolean isScanningAlwaysAvailable(); + + void setScanningAlwaysAvailable(boolean enable); + boolean acquireWifiLock(IBinder lock, int lockType, String tag, in WorkSource ws); void updateWifiLockWorkSource(IBinder lock, in WorkSource ws); diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java index eb2f74c..2385c24 100644 --- a/wifi/java/android/net/wifi/WifiConfigStore.java +++ b/wifi/java/android/net/wifi/WifiConfigStore.java @@ -395,6 +395,23 @@ class WifiConfigStore { return ret; } + void disableAllNetworks() { + boolean networkDisabled = false; + for(WifiConfiguration config : mConfiguredNetworks.values()) { + if(config != null && config.status != Status.DISABLED) { + if(mWifiNative.disableNetwork(config.networkId)) { + networkDisabled = true; + config.status = Status.DISABLED; + } else { + loge("Disable network failed on " + config.networkId); + } + } + } + + if (networkDisabled) { + sendConfiguredNetworksChangedBroadcast(); + } + } /** * Disable a network. Note that there is no saveConfig operation. * @param netId network to be disabled diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index ed5d22c..bb628c8 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -134,7 +134,12 @@ public class WifiStateMachine extends StateMachine { private boolean mEnableBackgroundScan = false; private int mRssiPollToken = 0; private int mReconnectCount = 0; - private boolean mIsScanMode = false; + /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE + * In CONNECT_MODE, the STA can scan and connect to an access point + * In SCAN_ONLY_MODE, the STA can only scan for access points + * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off + */ + private int mOperationalMode = CONNECT_MODE; private boolean mScanResultIsPending = false; /* Tracks if state machine has received any screen state change broadcast yet. * We can miss one of these at boot. @@ -285,8 +290,8 @@ public class WifiStateMachine extends StateMachine { /* Supplicant commands after driver start*/ /* Initiate a scan */ static final int CMD_START_SCAN = BASE + 71; - /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */ - static final int CMD_SET_SCAN_MODE = BASE + 72; + /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */ + static final int CMD_SET_OPERATIONAL_MODE = BASE + 72; /* Disconnect from a network */ static final int CMD_DISCONNECT = BASE + 73; /* Reconnect to a network */ @@ -342,16 +347,13 @@ public class WifiStateMachine extends StateMachine { public static final int CMD_DISABLE_P2P_REQ = BASE + 132; public static final int CMD_DISABLE_P2P_RSP = BASE + 133; - private static final int CONNECT_MODE = 1; - private static final int SCAN_ONLY_MODE = 2; + public static final int CONNECT_MODE = 1; + public static final int SCAN_ONLY_MODE = 2; + public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3; private static final int SUCCESS = 1; private static final int FAILURE = -1; - /* Phone in emergency call back mode */ - private static final int IN_ECM_STATE = 1; - private static final int NOT_IN_ECM_STATE = 0; - /** * The maximum number of times we will retry a connection to an access point * for which we have failed in acquiring an IP address from DHCP. A value of @@ -496,9 +498,6 @@ public class WifiStateMachine extends StateMachine { */ private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED); - private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid()); - private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid()); - private static final int SCAN_REQUEST = 0; private static final String ACTION_START_SCAN = "com.android.server.WifiManager.action.START_SCAN"; @@ -623,7 +622,7 @@ public class WifiStateMachine extends StateMachine { @Override public void onReceive(Context context, Intent intent) { int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0); - sendMessage(obtainMessage(CMD_DELAYED_STOP_DRIVER, counter, 0)); + sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0); } }, new IntentFilter(ACTION_DELAYED_DRIVER_STOP)); @@ -714,8 +713,7 @@ public class WifiStateMachine extends StateMachine { /** * TODO: doc */ - public void setWifiEnabled(boolean enable) { - mLastEnableUid.set(Binder.getCallingUid()); + public void setSupplicantRunning(boolean enable) { if (enable) { sendMessage(CMD_START_SUPPLICANT); } else { @@ -726,10 +724,9 @@ public class WifiStateMachine extends StateMachine { /** * TODO: doc */ - public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) { - mLastApEnableUid.set(Binder.getCallingUid()); + public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) { if (enable) { - sendMessage(obtainMessage(CMD_START_AP, wifiConfig)); + sendMessage(CMD_START_AP, wifiConfig); } else { sendMessage(CMD_STOP_AP); } @@ -818,27 +815,23 @@ public class WifiStateMachine extends StateMachine { /** * TODO: doc */ - public void setDriverStart(boolean enable, boolean ecm) { + public void setDriverStart(boolean enable) { if (enable) { sendMessage(CMD_START_DRIVER); } else { - sendMessage(obtainMessage(CMD_STOP_DRIVER, ecm ? IN_ECM_STATE : NOT_IN_ECM_STATE, 0)); + sendMessage(CMD_STOP_DRIVER); } } public void captivePortalCheckComplete() { - sendMessage(obtainMessage(CMD_CAPTIVE_CHECK_COMPLETE)); + sendMessage(CMD_CAPTIVE_CHECK_COMPLETE); } /** * TODO: doc */ - public void setScanOnlyMode(boolean enable) { - if (enable) { - sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0)); - } else { - sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0)); - } + public void setOperationalMode(int mode) { + sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0); } /** @@ -941,7 +934,7 @@ public class WifiStateMachine extends StateMachine { * @param bssid BSSID of the network */ public void addToBlacklist(String bssid) { - sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid)); + sendMessage(CMD_BLACKLIST_NETWORK, bssid); } /** @@ -949,15 +942,15 @@ public class WifiStateMachine extends StateMachine { * */ public void clearBlacklist() { - sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST)); + sendMessage(CMD_CLEAR_BLACKLIST); } public void enableRssiPolling(boolean enabled) { - sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0)); + sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0); } public void enableBackgroundScanCommand(boolean enabled) { - sendMessage(obtainMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0)); + sendMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0); } public void enableAllNetworks() { @@ -969,7 +962,7 @@ public class WifiStateMachine extends StateMachine { */ public void startFilteringMulticastV4Packets() { mFilteringMulticastV4Packets.set(true); - sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0)); + sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0); } /** @@ -977,21 +970,21 @@ public class WifiStateMachine extends StateMachine { */ public void stopFilteringMulticastV4Packets() { mFilteringMulticastV4Packets.set(false); - sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0)); + sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0); } /** * Start filtering Multicast v4 packets */ public void startFilteringMulticastV6Packets() { - sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0)); + sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0); } /** * Stop filtering Multicast v4 packets */ public void stopFilteringMulticastV6Packets() { - sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0)); + sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0); } /** @@ -1001,7 +994,7 @@ public class WifiStateMachine extends StateMachine { * @param enable true if enable, false otherwise */ public void setHighPerfModeEnabled(boolean enable) { - sendMessage(obtainMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0)); + sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0); } /** @@ -1015,7 +1008,7 @@ public class WifiStateMachine extends StateMachine { Settings.Global.WIFI_COUNTRY_CODE, countryCode); } - sendMessage(obtainMessage(CMD_SET_COUNTRY_CODE, countryCode)); + sendMessage(CMD_SET_COUNTRY_CODE, countryCode); } /** @@ -1029,7 +1022,7 @@ public class WifiStateMachine extends StateMachine { Settings.Global.WIFI_FREQUENCY_BAND, band); } - sendMessage(obtainMessage(CMD_SET_FREQUENCY_BAND, band, 0)); + sendMessage(CMD_SET_FREQUENCY_BAND, band, 0); } /** @@ -1050,7 +1043,7 @@ public class WifiStateMachine extends StateMachine { * Send a message indicating bluetooth adapter connection state changed */ public void sendBluetoothAdapterStateChange(int state) { - sendMessage(obtainMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0)); + sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0); } /** @@ -1114,7 +1107,7 @@ public class WifiStateMachine extends StateMachine { pw.println("mLastBssid " + mLastBssid); pw.println("mLastNetworkId " + mLastNetworkId); pw.println("mReconnectCount " + mReconnectCount); - pw.println("mIsScanMode " + mIsScanMode); + pw.println("mOperationalMode " + mOperationalMode); pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt); pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); pw.println("Supplicant status " + mWifiNative.status()); @@ -1136,11 +1129,11 @@ public class WifiStateMachine extends StateMachine { if (screenOn) enableAllNetworks(); if (mUserWantsSuspendOpt.get()) { if (screenOn) { - sendMessage(obtainMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0)); + sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0); } else { //Allow 2s for suspend optimizations to be set mSuspendWakeLock.acquire(2000); - sendMessage(obtainMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0)); + sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0); } } mScreenBroadcastReceived.set(true); @@ -1914,7 +1907,7 @@ public class WifiStateMachine extends StateMachine { case WifiMonitor.WPS_OVERLAP_EVENT: case CMD_BLACKLIST_NETWORK: case CMD_CLEAR_BLACKLIST: - case CMD_SET_SCAN_MODE: + case CMD_SET_OPERATIONAL_MODE: case CMD_SET_COUNTRY_CODE: case CMD_SET_FREQUENCY_BAND: case CMD_RSSI_POLL: @@ -1929,6 +1922,7 @@ public class WifiStateMachine extends StateMachine { case WifiWatchdogStateMachine.POOR_LINK_DETECTED: case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: case CMD_NO_NETWORKS_PERIODIC_SCAN: + case CMD_DISABLE_P2P_RSP: break; case DhcpStateMachine.CMD_ON_QUIT: mDhcpStateMachine = null; @@ -1942,8 +1936,8 @@ public class WifiStateMachine extends StateMachine { } break; case WifiMonitor.DRIVER_HUNG_EVENT: - setWifiEnabled(false); - setWifiEnabled(true); + setSupplicantRunning(false); + setSupplicantRunning(true); break; case WifiManager.CONNECT_NETWORK: replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, @@ -2143,7 +2137,7 @@ public class WifiStateMachine extends StateMachine { case CMD_STOP_AP: case CMD_START_DRIVER: case CMD_STOP_DRIVER: - case CMD_SET_SCAN_MODE: + case CMD_SET_OPERATIONAL_MODE: case CMD_SET_COUNTRY_CODE: case CMD_SET_FREQUENCY_BAND: case CMD_START_PACKET_FILTERING: @@ -2160,8 +2154,6 @@ public class WifiStateMachine extends StateMachine { class SupplicantStartedState extends State { @Override public void enter() { - /* Initialize for connect mode operation at start */ - mIsScanMode = false; /* Wifi is available as long as we have a connection to supplicant */ mNetworkInfo.setIsAvailable(true); @@ -2176,7 +2168,6 @@ public class WifiStateMachine extends StateMachine { } @Override public boolean processMessage(Message message) { - WifiConfiguration config; switch(message.what) { case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ if (mP2pSupported) { @@ -2206,87 +2197,13 @@ public class WifiStateMachine extends StateMachine { boolean ok = mWifiNative.ping(); replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); break; - case CMD_ADD_OR_UPDATE_NETWORK: - config = (WifiConfiguration) message.obj; - replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, - mWifiConfigStore.addOrUpdateNetwork(config)); - break; - case CMD_REMOVE_NETWORK: - ok = mWifiConfigStore.removeNetwork(message.arg1); - replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); - break; - case CMD_ENABLE_NETWORK: - ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); - replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); - break; - case CMD_ENABLE_ALL_NETWORKS: - long time = android.os.SystemClock.elapsedRealtime(); - if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { - mWifiConfigStore.enableAllNetworks(); - mLastEnableAllNetworksTime = time; - } - break; - case WifiManager.DISABLE_NETWORK: - if (mWifiConfigStore.disableNetwork(message.arg1, - WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) { - replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); - } else { - replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, - WifiManager.ERROR); - } - break; - case CMD_BLACKLIST_NETWORK: - mWifiNative.addToBlacklist((String)message.obj); - break; - case CMD_CLEAR_BLACKLIST: - mWifiNative.clearBlacklist(); - break; - case CMD_SAVE_CONFIG: - ok = mWifiConfigStore.saveConfig(); - replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); - - // Inform the backup manager about a data change - IBackupManager ibm = IBackupManager.Stub.asInterface( - ServiceManager.getService(Context.BACKUP_SERVICE)); - if (ibm != null) { - try { - ibm.dataChanged("com.android.providers.settings"); - } catch (Exception e) { - // Try again later - } - } - break; - case CMD_GET_CONFIGURED_NETWORKS: - replyToMessage(message, message.what, - mWifiConfigStore.getConfiguredNetworks()); - break; /* Cannot start soft AP while in client mode */ case CMD_START_AP: loge("Failed to start soft AP with a running supplicant"); setWifiApState(WIFI_AP_STATE_FAILED); break; - case CMD_SET_SCAN_MODE: - mIsScanMode = (message.arg1 == SCAN_ONLY_MODE); - break; - case WifiManager.SAVE_NETWORK: - config = (WifiConfiguration) message.obj; - NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); - if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { - replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); - } else { - loge("Failed to save network"); - replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, - WifiManager.ERROR); - } - break; - case WifiManager.FORGET_NETWORK: - if (mWifiConfigStore.forgetNetwork(message.arg1)) { - replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); - } else { - loge("Failed to forget network"); - replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, - WifiManager.ERROR); - } + case CMD_SET_OPERATIONAL_MODE: + mOperationalMode = message.arg1; break; default: return NOT_HANDLED; @@ -2344,7 +2261,7 @@ public class WifiStateMachine extends StateMachine { case CMD_STOP_AP: case CMD_START_DRIVER: case CMD_STOP_DRIVER: - case CMD_SET_SCAN_MODE: + case CMD_SET_OPERATIONAL_MODE: case CMD_SET_COUNTRY_CODE: case CMD_SET_FREQUENCY_BAND: case CMD_START_PACKET_FILTERING: @@ -2452,7 +2369,7 @@ public class WifiStateMachine extends StateMachine { mWifiNative.stopFilteringMulticastV4Packets(); } - if (mIsScanMode) { + if (mOperationalMode != CONNECT_MODE) { mWifiNative.disconnect(); transitionTo(mScanModeState); } else { @@ -2510,8 +2427,8 @@ public class WifiStateMachine extends StateMachine { case CMD_STOP_DRIVER: int mode = message.arg1; - /* Already doing a delayed stop && not in ecm state */ - if (mInDelayedStop && mode != IN_ECM_STATE) { + /* Already doing a delayed stop */ + if (mInDelayedStop) { if (DBG) log("Already in delayed stop"); break; } @@ -2519,20 +2436,15 @@ public class WifiStateMachine extends StateMachine { mDelayedStopCounter++; if (DBG) log("Delayed stop message " + mDelayedStopCounter); - if (mode == IN_ECM_STATE) { - /* send a shut down immediately */ - sendMessage(obtainMessage(CMD_DELAYED_STOP_DRIVER, mDelayedStopCounter, 0)); - } else { - /* send regular delayed shut down */ - Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); - driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); - mDriverStopIntent = PendingIntent.getBroadcast(mContext, - DRIVER_STOP_REQUEST, driverStopIntent, - PendingIntent.FLAG_UPDATE_CURRENT); + /* send regular delayed shut down */ + Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); + driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); + mDriverStopIntent = PendingIntent.getBroadcast(mContext, + DRIVER_STOP_REQUEST, driverStopIntent, + PendingIntent.FLAG_UPDATE_CURRENT); - mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() - + mDriverStopDelayMs, mDriverStopIntent); - } + mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + + mDriverStopDelayMs, mDriverStopIntent); break; case CMD_START_DRIVER: if (mInDelayedStop) { @@ -2638,7 +2550,7 @@ public class WifiStateMachine extends StateMachine { case CMD_STOP_AP: case CMD_START_DRIVER: case CMD_STOP_DRIVER: - case CMD_SET_SCAN_MODE: + case CMD_SET_OPERATIONAL_MODE: case CMD_SET_COUNTRY_CODE: case CMD_SET_FREQUENCY_BAND: case CMD_START_PACKET_FILTERING: @@ -2713,30 +2625,42 @@ public class WifiStateMachine extends StateMachine { } class ScanModeState extends State { + private int mLastOperationMode; + @Override + public void enter() { + mWifiConfigStore.disableAllNetworks(); + mLastOperationMode = mOperationalMode; + if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { + mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); + setWifiState(WIFI_STATE_DISABLED); + } + } + @Override + public void exit() { + if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { + setWifiState(WIFI_STATE_ENABLED); + mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P); + } + mWifiConfigStore.enableAllNetworks(); + mWifiNative.reconnect(); + } @Override public boolean processMessage(Message message) { switch(message.what) { - case CMD_SET_SCAN_MODE: - if (message.arg1 == SCAN_ONLY_MODE) { - /* Ignore */ - return HANDLED; - } else { - mWifiNative.reconnect(); - mIsScanMode = false; + case CMD_SET_OPERATIONAL_MODE: + if (message.arg1 == CONNECT_MODE) { + mOperationalMode = CONNECT_MODE; transitionTo(mDisconnectedState); + } else { + // Nothing to do + return HANDLED; } break; + // Handle scan. All the connection related commands are + // handled only in ConnectModeState case CMD_START_SCAN: startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP); break; - /* Ignore */ - case CMD_DISCONNECT: - case CMD_RECONNECT: - case CMD_REASSOCIATE: - case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - case WifiMonitor.NETWORK_CONNECTION_EVENT: - case WifiMonitor.NETWORK_DISCONNECTION_EVENT: - break; default: return NOT_HANDLED; } @@ -2747,7 +2671,8 @@ public class WifiStateMachine extends StateMachine { class ConnectModeState extends State { @Override public boolean processMessage(Message message) { - StateChangeResult stateChangeResult; + WifiConfiguration config; + boolean ok; switch(message.what) { case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT); @@ -2787,6 +2712,60 @@ public class WifiStateMachine extends StateMachine { mTemporarilyDisconnectWifi = false; } break; + case CMD_ADD_OR_UPDATE_NETWORK: + config = (WifiConfiguration) message.obj; + replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, + mWifiConfigStore.addOrUpdateNetwork(config)); + break; + case CMD_REMOVE_NETWORK: + ok = mWifiConfigStore.removeNetwork(message.arg1); + replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); + break; + case CMD_ENABLE_NETWORK: + ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); + replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); + break; + case CMD_ENABLE_ALL_NETWORKS: + long time = android.os.SystemClock.elapsedRealtime(); + if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { + mWifiConfigStore.enableAllNetworks(); + mLastEnableAllNetworksTime = time; + } + break; + case WifiManager.DISABLE_NETWORK: + if (mWifiConfigStore.disableNetwork(message.arg1, + WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) { + replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); + } else { + replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, + WifiManager.ERROR); + } + break; + case CMD_BLACKLIST_NETWORK: + mWifiNative.addToBlacklist((String)message.obj); + break; + case CMD_CLEAR_BLACKLIST: + mWifiNative.clearBlacklist(); + break; + case CMD_SAVE_CONFIG: + ok = mWifiConfigStore.saveConfig(); + replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); + + // Inform the backup manager about a data change + IBackupManager ibm = IBackupManager.Stub.asInterface( + ServiceManager.getService(Context.BACKUP_SERVICE)); + if (ibm != null) { + try { + ibm.dataChanged("com.android.providers.settings"); + } catch (Exception e) { + // Try again later + } + } + break; + case CMD_GET_CONFIGURED_NETWORKS: + replyToMessage(message, message.what, + mWifiConfigStore.getConfiguredNetworks()); + break; /* Do a redundant disconnect without transition */ case CMD_DISCONNECT: mWifiNative.disconnect(); @@ -2804,7 +2783,7 @@ public class WifiStateMachine extends StateMachine { * For an existing network, a network id is passed */ int netId = message.arg1; - WifiConfiguration config = (WifiConfiguration) message.obj; + config = (WifiConfiguration) message.obj; /* Save the network config */ if (config != null) { @@ -2826,26 +2805,46 @@ public class WifiStateMachine extends StateMachine { break; } break; + case WifiManager.SAVE_NETWORK: + config = (WifiConfiguration) message.obj; + NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); + if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { + replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); + } else { + loge("Failed to save network"); + replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, + WifiManager.ERROR); + } + break; + case WifiManager.FORGET_NETWORK: + if (mWifiConfigStore.forgetNetwork(message.arg1)) { + replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); + } else { + loge("Failed to forget network"); + replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, + WifiManager.ERROR); + } + break; case WifiManager.START_WPS: WpsInfo wpsInfo = (WpsInfo) message.obj; - WpsResult result; + WpsResult wpsResult; switch (wpsInfo.setup) { case WpsInfo.PBC: - result = mWifiConfigStore.startWpsPbc(wpsInfo); + wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo); break; case WpsInfo.KEYPAD: - result = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); + wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); break; case WpsInfo.DISPLAY: - result = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); + wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); break; default: - result = new WpsResult(Status.FAILURE); + wpsResult = new WpsResult(Status.FAILURE); loge("Invalid setup for WPS"); break; } - if (result.status == Status.SUCCESS) { - replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, result); + if (wpsResult.status == Status.SUCCESS) { + replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult); transitionTo(mWpsRunningState); } else { loge("Failed to start WPS with config " + wpsInfo.toString()); @@ -2881,7 +2880,7 @@ public class WifiStateMachine extends StateMachine { public void enter() { mRssiPollToken++; if (mEnableRssiPolling) { - sendMessage(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0)); + sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0); } } @@ -2915,8 +2914,8 @@ public class WifiStateMachine extends StateMachine { transitionTo(mDisconnectingState); } break; - case CMD_SET_SCAN_MODE: - if (message.arg1 == SCAN_ONLY_MODE) { + case CMD_SET_OPERATIONAL_MODE: + if (message.arg1 != CONNECT_MODE) { sendMessage(CMD_DISCONNECT); deferMessage(message); } @@ -3152,8 +3151,8 @@ public class WifiStateMachine extends StateMachine { @Override public boolean processMessage(Message message) { switch (message.what) { - case CMD_SET_SCAN_MODE: - if (message.arg1 == SCAN_ONLY_MODE) { + case CMD_SET_OPERATIONAL_MODE: + if (message.arg1 != CONNECT_MODE) { deferMessage(message); } break; @@ -3259,11 +3258,9 @@ public class WifiStateMachine extends StateMachine { ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); ret = NOT_HANDLED; break; - case CMD_SET_SCAN_MODE: - if (message.arg1 == SCAN_ONLY_MODE) { - //Supplicant disconnect to prevent further connects - mWifiNative.disconnect(); - mIsScanMode = true; + case CMD_SET_OPERATIONAL_MODE: + if (message.arg1 != CONNECT_MODE) { + mOperationalMode = message.arg1; transitionTo(mScanModeState); } break; @@ -3396,7 +3393,7 @@ public class WifiStateMachine extends StateMachine { * or put the state machine out of connect mode */ case CMD_STOP_DRIVER: - case CMD_SET_SCAN_MODE: + case CMD_SET_OPERATIONAL_MODE: case WifiManager.CONNECT_NETWORK: case CMD_ENABLE_NETWORK: case CMD_RECONNECT: @@ -3459,7 +3456,7 @@ public class WifiStateMachine extends StateMachine { case CMD_STOP_AP: case CMD_START_DRIVER: case CMD_STOP_DRIVER: - case CMD_SET_SCAN_MODE: + case CMD_SET_OPERATIONAL_MODE: case CMD_SET_COUNTRY_CODE: case CMD_SET_FREQUENCY_BAND: case CMD_START_PACKET_FILTERING: @@ -3556,7 +3553,7 @@ public class WifiStateMachine extends StateMachine { case CMD_STOP_AP: case CMD_START_DRIVER: case CMD_STOP_DRIVER: - case CMD_SET_SCAN_MODE: + case CMD_SET_OPERATIONAL_MODE: case CMD_SET_COUNTRY_CODE: case CMD_SET_FREQUENCY_BAND: case CMD_START_PACKET_FILTERING: @@ -3578,7 +3575,7 @@ public class WifiStateMachine extends StateMachine { TetherStateChange stateChange = (TetherStateChange) message.obj; if (!isWifiTethered(stateChange.active)) { loge("Tethering reports wifi as untethered!, shut down soft Ap"); - setWifiApEnabled(null, false); + setHostApRunning(null, false); } return HANDLED; case CMD_STOP_AP: @@ -3627,7 +3624,7 @@ public class WifiStateMachine extends StateMachine { case CMD_STOP_AP: case CMD_START_DRIVER: case CMD_STOP_DRIVER: - case CMD_SET_SCAN_MODE: + case CMD_SET_OPERATIONAL_MODE: case CMD_SET_COUNTRY_CODE: case CMD_SET_FREQUENCY_BAND: case CMD_START_PACKET_FILTERING: |