Loading services/core/java/com/android/server/vcn/VcnGatewayConnection.java +136 −22 Original line number Original line Diff line number Diff line Loading @@ -123,7 +123,7 @@ public class VcnGatewayConnection extends StateMachine { private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST = private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST = "Underlying Network lost"; "Underlying Network lost"; private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel"; private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel"; private static final int TOKEN_ANY = Integer.MIN_VALUE; private static final int TOKEN_ALL = Integer.MIN_VALUE; private static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30; private static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30; private static final int TEARDOWN_TIMEOUT_SECONDS = 5; private static final int TEARDOWN_TIMEOUT_SECONDS = 5; Loading @@ -139,7 +139,7 @@ public class VcnGatewayConnection extends StateMachine { * * * <p>In the Connected state, this MAY indicate a mobility even occurred. * <p>In the Connected state, this MAY indicate a mobility even occurred. * * * @param arg1 The "any" token; this event is always applicable. * @param arg1 The "all" token; this event is always applicable. * @param obj @NonNull An EventUnderlyingNetworkChangedInfo instance with relevant data. * @param obj @NonNull An EventUnderlyingNetworkChangedInfo instance with relevant data. */ */ private static final int EVENT_UNDERLYING_NETWORK_CHANGED = 1; private static final int EVENT_UNDERLYING_NETWORK_CHANGED = 1; Loading Loading @@ -175,7 +175,7 @@ public class VcnGatewayConnection extends StateMachine { * <p>Upon receipt of this signal, the state machine will transition from the Retry-timeout * <p>Upon receipt of this signal, the state machine will transition from the Retry-timeout * state to the Connecting state. * state to the Connecting state. * * * @param arg1 The "any" token; no sessions are active in the RetryTimeoutState. * @param arg1 The "all" token; no sessions are active in the RetryTimeoutState. */ */ private static final int EVENT_RETRY_TIMEOUT_EXPIRED = 2; private static final int EVENT_RETRY_TIMEOUT_EXPIRED = 2; Loading Loading @@ -318,7 +318,7 @@ public class VcnGatewayConnection extends StateMachine { * <p>Upon receipt of this signal, the state machine MUST tear down all active sessions, cancel * <p>Upon receipt of this signal, the state machine MUST tear down all active sessions, cancel * any pending work items, and move to the Disconnected state. * any pending work items, and move to the Disconnected state. * * * @param arg1 The "any" token; this signal is always honored. * @param arg1 The "all" token; this signal is always honored. * @param obj @NonNull An EventDisconnectRequestedInfo instance with relevant data. * @param obj @NonNull An EventDisconnectRequestedInfo instance with relevant data. */ */ private static final int EVENT_DISCONNECT_REQUESTED = 7; private static final int EVENT_DISCONNECT_REQUESTED = 7; Loading Loading @@ -504,16 +504,9 @@ public class VcnGatewayConnection extends StateMachine { * <p>Once torn down, this VcnTunnel CANNOT be started again. * <p>Once torn down, this VcnTunnel CANNOT be started again. */ */ public void teardownAsynchronously() { public void teardownAsynchronously() { mUnderlyingNetworkTracker.teardown(); // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. if (mTunnelIface != null) { mTunnelIface.close(); } sendMessage( sendMessage( EVENT_DISCONNECT_REQUESTED, EVENT_DISCONNECT_REQUESTED, TOKEN_ANY, TOKEN_ALL, new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN)); new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN)); quit(); quit(); Loading @@ -521,6 +514,16 @@ public class VcnGatewayConnection extends StateMachine { // is also called asynchronously when a NetworkAgent becomes unwanted // is also called asynchronously when a NetworkAgent becomes unwanted } } @Override protected void onQuitting() { // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. if (mTunnelIface != null) { mTunnelIface.close(); } mUnderlyingNetworkTracker.teardown(); } private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback { private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback { @Override @Override public void onSelectedUnderlyingNetworkChanged( public void onSelectedUnderlyingNetworkChanged( Loading @@ -530,26 +533,24 @@ public class VcnGatewayConnection extends StateMachine { if (underlying == null) { if (underlying == null) { sendMessageDelayed( sendMessageDelayed( EVENT_DISCONNECT_REQUESTED, EVENT_DISCONNECT_REQUESTED, TOKEN_ANY, TOKEN_ALL, new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST), new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST), TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS)); TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS)); return; } else if (getHandler() != null) { } // Cancel any existing disconnect due to loss of underlying network // Cancel any existing disconnect due to loss of underlying network // getHandler() can return null if the state machine has already quit. Since this is // getHandler() can return null if the state machine has already quit. Since this is // called // called from other classes, this condition must be verified. // from other classes, this condition must be verified. if (getHandler() != null) { getHandler() getHandler() .removeEqualMessages( .removeEqualMessages( EVENT_DISCONNECT_REQUESTED, EVENT_DISCONNECT_REQUESTED, new EventDisconnectRequestedInfo( new EventDisconnectRequestedInfo( DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); } } sendMessage( sendMessage( EVENT_UNDERLYING_NETWORK_CHANGED, EVENT_UNDERLYING_NETWORK_CHANGED, TOKEN_ANY, TOKEN_ALL, new EventUnderlyingNetworkChangedInfo(underlying)); new EventUnderlyingNetworkChangedInfo(underlying)); } } } } Loading Loading @@ -594,10 +595,101 @@ public class VcnGatewayConnection extends StateMachine { } } private abstract class BaseState extends State { private abstract class BaseState extends State { @Override public void enter() { try { enterState(); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); sendMessage( EVENT_DISCONNECT_REQUESTED, TOKEN_ALL, new EventDisconnectRequestedInfo( DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); } } protected void enterState() throws Exception {} protected void enterState() throws Exception {} /** * Top-level processMessage with safeguards to prevent crashing the System Server on non-eng * builds. */ @Override public boolean processMessage(Message msg) { try { processStateMsg(msg); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); sendMessage( EVENT_DISCONNECT_REQUESTED, TOKEN_ALL, new EventDisconnectRequestedInfo( DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); } return HANDLED; } protected abstract void processStateMsg(Message msg) throws Exception; protected abstract void processStateMsg(Message msg) throws Exception; protected void logUnhandledMessage(Message msg) { // Log as unexpected all known messages, and log all else as unknown. switch (msg.what) { case EVENT_UNDERLYING_NETWORK_CHANGED: // Fallthrough case EVENT_RETRY_TIMEOUT_EXPIRED: // Fallthrough case EVENT_SESSION_LOST: // Fallthrough case EVENT_SESSION_CLOSED: // Fallthrough case EVENT_TRANSFORM_CREATED: // Fallthrough case EVENT_SETUP_COMPLETED: // Fallthrough case EVENT_DISCONNECT_REQUESTED: // Fallthrough case EVENT_TEARDOWN_TIMEOUT_EXPIRED: logUnexpectedEvent(msg.what); break; default: logWtfUnknownEvent(msg.what); break; } } protected void teardownNetwork() { if (mNetworkAgent != null) { mNetworkAgent.sendNetworkInfo(buildNetworkInfo(false /* isConnected */)); mNetworkAgent = null; } } protected void teardownIke() { if (mIkeSession != null) { mIkeSession.close(); } } protected void handleDisconnectRequested(String msg) { Slog.v(TAG, "Tearing down. Cause: " + msg); teardownNetwork(); teardownIke(); if (mIkeSession == null) { // Already disconnected, go straight to DisconnectedState transitionTo(mDisconnectedState); } else { // Still need to wait for full closure transitionTo(mDisconnectingState); } } } protected void logUnexpectedEvent(int what) { Slog.d(TAG, String.format( "Unexpected event code %d in state %s", what, this.getClass().getSimpleName())); } protected void logWtfUnknownEvent(int what) { Slog.wtf(TAG, String.format( "Unknown event code %d in state %s", what, this.getClass().getSimpleName())); } } /** /** * State representing the a disconnected VCN tunnel. * State representing the a disconnected VCN tunnel. * * Loading @@ -608,7 +700,29 @@ public class VcnGatewayConnection extends StateMachine { protected void processStateMsg(Message msg) {} protected void processStateMsg(Message msg) {} } } private abstract class ActiveBaseState extends BaseState {} private abstract class ActiveBaseState extends BaseState { /** * Handles all incoming messages, discarding messages for previous networks. * * <p>States that handle mobility events may need to override this method to receive * messages for all underlying networks. */ @Override public boolean processMessage(Message msg) { final int token = msg.arg1; // Only process if a valid token is presented. if (isValidToken(token)) { return super.processMessage(msg); } Slog.v(TAG, "Message called with obsolete token: " + token + "; what: " + msg.what); return HANDLED; } protected boolean isValidToken(int token) { return (token == TOKEN_ALL || token == mCurrentToken); } } /** /** * Transitive state representing a VCN that is tearing down an IKE session. * Transitive state representing a VCN that is tearing down an IKE session. Loading Loading
services/core/java/com/android/server/vcn/VcnGatewayConnection.java +136 −22 Original line number Original line Diff line number Diff line Loading @@ -123,7 +123,7 @@ public class VcnGatewayConnection extends StateMachine { private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST = private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST = "Underlying Network lost"; "Underlying Network lost"; private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel"; private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel"; private static final int TOKEN_ANY = Integer.MIN_VALUE; private static final int TOKEN_ALL = Integer.MIN_VALUE; private static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30; private static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30; private static final int TEARDOWN_TIMEOUT_SECONDS = 5; private static final int TEARDOWN_TIMEOUT_SECONDS = 5; Loading @@ -139,7 +139,7 @@ public class VcnGatewayConnection extends StateMachine { * * * <p>In the Connected state, this MAY indicate a mobility even occurred. * <p>In the Connected state, this MAY indicate a mobility even occurred. * * * @param arg1 The "any" token; this event is always applicable. * @param arg1 The "all" token; this event is always applicable. * @param obj @NonNull An EventUnderlyingNetworkChangedInfo instance with relevant data. * @param obj @NonNull An EventUnderlyingNetworkChangedInfo instance with relevant data. */ */ private static final int EVENT_UNDERLYING_NETWORK_CHANGED = 1; private static final int EVENT_UNDERLYING_NETWORK_CHANGED = 1; Loading Loading @@ -175,7 +175,7 @@ public class VcnGatewayConnection extends StateMachine { * <p>Upon receipt of this signal, the state machine will transition from the Retry-timeout * <p>Upon receipt of this signal, the state machine will transition from the Retry-timeout * state to the Connecting state. * state to the Connecting state. * * * @param arg1 The "any" token; no sessions are active in the RetryTimeoutState. * @param arg1 The "all" token; no sessions are active in the RetryTimeoutState. */ */ private static final int EVENT_RETRY_TIMEOUT_EXPIRED = 2; private static final int EVENT_RETRY_TIMEOUT_EXPIRED = 2; Loading Loading @@ -318,7 +318,7 @@ public class VcnGatewayConnection extends StateMachine { * <p>Upon receipt of this signal, the state machine MUST tear down all active sessions, cancel * <p>Upon receipt of this signal, the state machine MUST tear down all active sessions, cancel * any pending work items, and move to the Disconnected state. * any pending work items, and move to the Disconnected state. * * * @param arg1 The "any" token; this signal is always honored. * @param arg1 The "all" token; this signal is always honored. * @param obj @NonNull An EventDisconnectRequestedInfo instance with relevant data. * @param obj @NonNull An EventDisconnectRequestedInfo instance with relevant data. */ */ private static final int EVENT_DISCONNECT_REQUESTED = 7; private static final int EVENT_DISCONNECT_REQUESTED = 7; Loading Loading @@ -504,16 +504,9 @@ public class VcnGatewayConnection extends StateMachine { * <p>Once torn down, this VcnTunnel CANNOT be started again. * <p>Once torn down, this VcnTunnel CANNOT be started again. */ */ public void teardownAsynchronously() { public void teardownAsynchronously() { mUnderlyingNetworkTracker.teardown(); // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. if (mTunnelIface != null) { mTunnelIface.close(); } sendMessage( sendMessage( EVENT_DISCONNECT_REQUESTED, EVENT_DISCONNECT_REQUESTED, TOKEN_ANY, TOKEN_ALL, new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN)); new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN)); quit(); quit(); Loading @@ -521,6 +514,16 @@ public class VcnGatewayConnection extends StateMachine { // is also called asynchronously when a NetworkAgent becomes unwanted // is also called asynchronously when a NetworkAgent becomes unwanted } } @Override protected void onQuitting() { // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. if (mTunnelIface != null) { mTunnelIface.close(); } mUnderlyingNetworkTracker.teardown(); } private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback { private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback { @Override @Override public void onSelectedUnderlyingNetworkChanged( public void onSelectedUnderlyingNetworkChanged( Loading @@ -530,26 +533,24 @@ public class VcnGatewayConnection extends StateMachine { if (underlying == null) { if (underlying == null) { sendMessageDelayed( sendMessageDelayed( EVENT_DISCONNECT_REQUESTED, EVENT_DISCONNECT_REQUESTED, TOKEN_ANY, TOKEN_ALL, new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST), new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST), TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS)); TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS)); return; } else if (getHandler() != null) { } // Cancel any existing disconnect due to loss of underlying network // Cancel any existing disconnect due to loss of underlying network // getHandler() can return null if the state machine has already quit. Since this is // getHandler() can return null if the state machine has already quit. Since this is // called // called from other classes, this condition must be verified. // from other classes, this condition must be verified. if (getHandler() != null) { getHandler() getHandler() .removeEqualMessages( .removeEqualMessages( EVENT_DISCONNECT_REQUESTED, EVENT_DISCONNECT_REQUESTED, new EventDisconnectRequestedInfo( new EventDisconnectRequestedInfo( DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); } } sendMessage( sendMessage( EVENT_UNDERLYING_NETWORK_CHANGED, EVENT_UNDERLYING_NETWORK_CHANGED, TOKEN_ANY, TOKEN_ALL, new EventUnderlyingNetworkChangedInfo(underlying)); new EventUnderlyingNetworkChangedInfo(underlying)); } } } } Loading Loading @@ -594,10 +595,101 @@ public class VcnGatewayConnection extends StateMachine { } } private abstract class BaseState extends State { private abstract class BaseState extends State { @Override public void enter() { try { enterState(); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); sendMessage( EVENT_DISCONNECT_REQUESTED, TOKEN_ALL, new EventDisconnectRequestedInfo( DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); } } protected void enterState() throws Exception {} protected void enterState() throws Exception {} /** * Top-level processMessage with safeguards to prevent crashing the System Server on non-eng * builds. */ @Override public boolean processMessage(Message msg) { try { processStateMsg(msg); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); sendMessage( EVENT_DISCONNECT_REQUESTED, TOKEN_ALL, new EventDisconnectRequestedInfo( DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); } return HANDLED; } protected abstract void processStateMsg(Message msg) throws Exception; protected abstract void processStateMsg(Message msg) throws Exception; protected void logUnhandledMessage(Message msg) { // Log as unexpected all known messages, and log all else as unknown. switch (msg.what) { case EVENT_UNDERLYING_NETWORK_CHANGED: // Fallthrough case EVENT_RETRY_TIMEOUT_EXPIRED: // Fallthrough case EVENT_SESSION_LOST: // Fallthrough case EVENT_SESSION_CLOSED: // Fallthrough case EVENT_TRANSFORM_CREATED: // Fallthrough case EVENT_SETUP_COMPLETED: // Fallthrough case EVENT_DISCONNECT_REQUESTED: // Fallthrough case EVENT_TEARDOWN_TIMEOUT_EXPIRED: logUnexpectedEvent(msg.what); break; default: logWtfUnknownEvent(msg.what); break; } } protected void teardownNetwork() { if (mNetworkAgent != null) { mNetworkAgent.sendNetworkInfo(buildNetworkInfo(false /* isConnected */)); mNetworkAgent = null; } } protected void teardownIke() { if (mIkeSession != null) { mIkeSession.close(); } } protected void handleDisconnectRequested(String msg) { Slog.v(TAG, "Tearing down. Cause: " + msg); teardownNetwork(); teardownIke(); if (mIkeSession == null) { // Already disconnected, go straight to DisconnectedState transitionTo(mDisconnectedState); } else { // Still need to wait for full closure transitionTo(mDisconnectingState); } } } protected void logUnexpectedEvent(int what) { Slog.d(TAG, String.format( "Unexpected event code %d in state %s", what, this.getClass().getSimpleName())); } protected void logWtfUnknownEvent(int what) { Slog.wtf(TAG, String.format( "Unknown event code %d in state %s", what, this.getClass().getSimpleName())); } } /** /** * State representing the a disconnected VCN tunnel. * State representing the a disconnected VCN tunnel. * * Loading @@ -608,7 +700,29 @@ public class VcnGatewayConnection extends StateMachine { protected void processStateMsg(Message msg) {} protected void processStateMsg(Message msg) {} } } private abstract class ActiveBaseState extends BaseState {} private abstract class ActiveBaseState extends BaseState { /** * Handles all incoming messages, discarding messages for previous networks. * * <p>States that handle mobility events may need to override this method to receive * messages for all underlying networks. */ @Override public boolean processMessage(Message msg) { final int token = msg.arg1; // Only process if a valid token is presented. if (isValidToken(token)) { return super.processMessage(msg); } Slog.v(TAG, "Message called with obsolete token: " + token + "; what: " + msg.what); return HANDLED; } protected boolean isValidToken(int token) { return (token == TOKEN_ALL || token == mCurrentToken); } } /** /** * Transitive state representing a VCN that is tearing down an IKE session. * Transitive state representing a VCN that is tearing down an IKE session. Loading