From e741403b6199bdfefd2ec5c27548a8ebf7a7f148 Mon Sep 17 00:00:00 2001 From: Ang Li Date: Fri, 15 Dec 2017 13:14:10 -0800 Subject: Handle a possible race condition in wifi/bt toggle. (#91) E.g. if BT was in the process of turning off when we called `btEnable`, BT would finish turning off before turning on again, but the `btEnable` call would timeout before that. Same situation for `btDisable` and wifi toggles. --- .../mobly/snippet/bundled/WifiManagerSnippet.java | 37 +++++++++++++++++++--- .../bundled/bluetooth/BluetoothAdapterSnippet.java | 35 +++++++++++++++++--- 2 files changed, 64 insertions(+), 8 deletions(-) (limited to 'src/main') diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/WifiManagerSnippet.java b/src/main/java/com/google/android/mobly/snippet/bundled/WifiManagerSnippet.java index 83a42f6..f6de71e 100644 --- a/src/main/java/com/google/android/mobly/snippet/bundled/WifiManagerSnippet.java +++ b/src/main/java/com/google/android/mobly/snippet/bundled/WifiManagerSnippet.java @@ -50,6 +50,7 @@ public class WifiManagerSnippet implements Snippet { } } + private static final int TIMEOUT_TOGGLE_STATE = 30; private final WifiManager mWifiManager; private final Context mContext; private final JsonSerializer mJsonSerializer = new JsonSerializer(); @@ -86,23 +87,51 @@ public class WifiManagerSnippet implements Snippet { @Rpc(description = "Turns on Wi-Fi with a 30s timeout.") public void wifiEnable() throws InterruptedException, WifiManagerSnippetException { + if (mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED) { + return; + } + // If Wi-Fi is trying to turn off, wait for that to complete before continuing. + if (mWifiManager.getWifiState() == WifiManager.WIFI_STATE_DISABLING) { + if (!Utils.waitUntil( + () -> mWifiManager.getWifiState() == WifiManager.WIFI_STATE_DISABLED, + TIMEOUT_TOGGLE_STATE)) { + Log.e(String.format("Wi-Fi failed to stabilize after %ss.", TIMEOUT_TOGGLE_STATE)); + } + } if (!mWifiManager.setWifiEnabled(true)) { throw new WifiManagerSnippetException("Failed to initiate enabling Wi-Fi."); } if (!Utils.waitUntil( - () -> mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED, 30)) { - throw new WifiManagerSnippetException("Failed to enable Wi-Fi after 30s, timeout!"); + () -> mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED, + TIMEOUT_TOGGLE_STATE)) { + throw new WifiManagerSnippetException( + String.format( + "Failed to enable Wi-Fi after %ss, timeout!", TIMEOUT_TOGGLE_STATE)); } } @Rpc(description = "Turns off Wi-Fi with a 30s timeout.") public void wifiDisable() throws InterruptedException, WifiManagerSnippetException { + if (mWifiManager.getWifiState() == WifiManager.WIFI_STATE_DISABLED) { + return; + } + // If Wi-Fi is trying to turn on, wait for that to complete before continuing. + if (mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING) { + if (!Utils.waitUntil( + () -> mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED, + TIMEOUT_TOGGLE_STATE)) { + Log.e(String.format("Wi-Fi failed to stabilize after %ss.", TIMEOUT_TOGGLE_STATE)); + } + } if (!mWifiManager.setWifiEnabled(false)) { throw new WifiManagerSnippetException("Failed to initiate disabling Wi-Fi."); } if (!Utils.waitUntil( - () -> mWifiManager.getWifiState() == WifiManager.WIFI_STATE_DISABLED, 30)) { - throw new WifiManagerSnippetException("Failed to disable Wi-Fi after 30s, timeout!"); + () -> mWifiManager.getWifiState() == WifiManager.WIFI_STATE_DISABLED, + TIMEOUT_TOGGLE_STATE)) { + throw new WifiManagerSnippetException( + String.format( + "Failed to disable Wi-Fi after %ss, timeout!", TIMEOUT_TOGGLE_STATE)); } } diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/BluetoothAdapterSnippet.java b/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/BluetoothAdapterSnippet.java index 0685923..ffaf1af 100644 --- a/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/BluetoothAdapterSnippet.java +++ b/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/BluetoothAdapterSnippet.java @@ -28,6 +28,7 @@ import com.google.android.mobly.snippet.Snippet; import com.google.android.mobly.snippet.bundled.utils.JsonSerializer; import com.google.android.mobly.snippet.bundled.utils.Utils; import com.google.android.mobly.snippet.rpc.Rpc; +import com.google.android.mobly.snippet.util.Log; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; @@ -44,6 +45,8 @@ public class BluetoothAdapterSnippet implements Snippet { } } + // Default timeout in seconds. + private static final int TIMEOUT_TOGGLE_STATE = 30; private final Context mContext; private static final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); private final JsonSerializer mJsonSerializer = new JsonSerializer(); @@ -87,21 +90,45 @@ public class BluetoothAdapterSnippet implements Snippet { @Rpc(description = "Enable bluetooth with a 30s timeout.") public void btEnable() throws BluetoothAdapterSnippetException, InterruptedException { + if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) { + return; + } + // If bt is trying to turn off, wait for that to finish before continuing. + if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_TURNING_OFF) { + if (!Utils.waitUntil( + () -> mBluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF, + TIMEOUT_TOGGLE_STATE)) { + Log.e(String.format("BT failed to stabilize after %ss.", TIMEOUT_TOGGLE_STATE)); + } + } if (!mBluetoothAdapter.enable()) { throw new BluetoothAdapterSnippetException("Failed to start enabling bluetooth"); } - if (!Utils.waitUntil(() -> mBluetoothAdapter.isEnabled(), 30)) { - throw new BluetoothAdapterSnippetException("Bluetooth did not turn on within 30s."); + if (!Utils.waitUntil(() -> mBluetoothAdapter.isEnabled(), TIMEOUT_TOGGLE_STATE)) { + throw new BluetoothAdapterSnippetException( + String.format("Bluetooth did not turn on within %ss.", TIMEOUT_TOGGLE_STATE)); } } @Rpc(description = "Disable bluetooth with a 30s timeout.") public void btDisable() throws BluetoothAdapterSnippetException, InterruptedException { + if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) { + return; + } + // If bt is trying to turn on, wait for that to finish before continuing. + if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_TURNING_ON) { + if (!Utils.waitUntil( + () -> mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON, + TIMEOUT_TOGGLE_STATE)) { + Log.e(String.format("BT failed to stabilize after %ss.", TIMEOUT_TOGGLE_STATE)); + } + } if (!mBluetoothAdapter.disable()) { throw new BluetoothAdapterSnippetException("Failed to start disabling bluetooth"); } - if (!Utils.waitUntil(() -> !mBluetoothAdapter.isEnabled(), 30)) { - throw new BluetoothAdapterSnippetException("Bluetooth did not turn off within 30s."); + if (!Utils.waitUntil(() -> !mBluetoothAdapter.isEnabled(), TIMEOUT_TOGGLE_STATE)) { + throw new BluetoothAdapterSnippetException( + String.format("Bluetooth did not turn off within %ss.", TIMEOUT_TOGGLE_STATE)); } } -- cgit v1.2.3