From 977aad5a654ebd2cfbc73db8c6e4020c4bedad97 Mon Sep 17 00:00:00 2001 From: "Yohei, Oshima" Date: Thu, 8 Dec 2016 13:39:20 +0900 Subject: [PATCH] Fix dead lock in Tethering state machine This fix is for tethering from N MR1. It reserves the same idea originally in e4bdfd8ad86a013c5a2ee8964119393cea1ec4a3. Tethering is animated by two state machines. If an error occurs, one of the state machine notifies the other and definitely stays in the error state while the other retries the tether operation after having treated the error. An example is when dnsmasq is started by calling tether(), but while it hasn't finished starting yet untether() is called asynchronously by a different tethering. Then "Setting DNS forwarders failed!" error occurs and device can't be tethered anymore without reboot. This patch allows to clear the error of the blocked state machine from the other one and thus recover a normal cycle. Test: fastly switching USB/Wi-Fi tethering On/Off repeatedly Test: manually kill dnsmasq during BT tethering then turn on Wi-Fi tethering Change-Id: Ide062dd4c15a0e7c72eced9a5fe807f845d4ea9c --- .../com/android/server/connectivity/Tethering.java | 12 ++++++++++++ .../tethering/TetherInterfaceStateMachine.java | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index b0e45097aff69..8e55ea5b90d4b 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -950,6 +950,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering // Events from NetworkCallbacks that we process on the master state // machine thread on behalf of the UpstreamNetworkMonitor. static final int EVENT_UPSTREAM_CALLBACK = BASE_MASTER + 5; + // we treated the error and want now to clear it + static final int CMD_CLEAR_ERROR = BASE_MASTER + 6; private State mInitialState; private State mTetherModeAliveState; @@ -1487,6 +1489,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj; who.sendMessage(mErrorNotification); break; + case CMD_CLEAR_ERROR: + mErrorNotification = ConnectivityManager.TETHER_ERROR_NO_ERROR; + transitionTo(mInitialState); + break; default: retValue = false; } @@ -1631,6 +1637,12 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering // Not really very much we can do here. } + // If TetherMasterSM is in ErrorState, TetherMasterSM stays there. + // Thus we give a chance for TetherMasterSM to recover to InitialState + // by sending CMD_CLEAR_ERROR + if (error == ConnectivityManager.TETHER_ERROR_MASTER_ERROR) { + mTetherMasterSM.sendMessage(TetherMasterSM.CMD_CLEAR_ERROR, who); + } switch (state) { case IControlsTethering.STATE_UNAVAILABLE: case IControlsTethering.STATE_AVAILABLE: diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java index 37221a971ad19..e8a7ddb34f10e 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java @@ -167,7 +167,8 @@ public class TetherInterfaceStateMachine extends StateMachine { private void maybeLogMessage(State state, int what) { if (DBG) { Log.d(TAG, state.getName() + " got " + - sMagicDecoderRing.get(what, Integer.toString(what))); + sMagicDecoderRing.get(what, Integer.toString(what)) + ", Iface = " + + mIfaceName); } }