diff options
| -rw-r--r-- | services/core/java/com/android/server/vcn/VcnGatewayConnection.java | 158 |
1 files changed, 136 insertions, 22 deletions
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 7024e67a8204..4e0c0c54923b 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -123,7 +123,7 @@ public class VcnGatewayConnection extends StateMachine { private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST = "Underlying Network lost"; 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 TEARDOWN_TIMEOUT_SECONDS = 5; @@ -139,7 +139,7 @@ public class VcnGatewayConnection extends StateMachine { * * <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. */ private static final int EVENT_UNDERLYING_NETWORK_CHANGED = 1; @@ -175,7 +175,7 @@ public class VcnGatewayConnection extends StateMachine { * <p>Upon receipt of this signal, the state machine will transition from the Retry-timeout * 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; @@ -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 * 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. */ private static final int EVENT_DISCONNECT_REQUESTED = 7; @@ -504,16 +504,9 @@ public class VcnGatewayConnection extends StateMachine { * <p>Once torn down, this VcnTunnel CANNOT be started again. */ public void teardownAsynchronously() { - mUnderlyingNetworkTracker.teardown(); - - // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. - if (mTunnelIface != null) { - mTunnelIface.close(); - } - sendMessage( EVENT_DISCONNECT_REQUESTED, - TOKEN_ANY, + TOKEN_ALL, new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN)); quit(); @@ -521,6 +514,16 @@ public class VcnGatewayConnection extends StateMachine { // 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 { @Override public void onSelectedUnderlyingNetworkChanged( @@ -530,26 +533,24 @@ public class VcnGatewayConnection extends StateMachine { if (underlying == null) { sendMessageDelayed( EVENT_DISCONNECT_REQUESTED, - TOKEN_ANY, + TOKEN_ALL, new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST), TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS)); - return; - } + } else if (getHandler() != null) { + // Cancel any existing disconnect due to loss of underlying network + // getHandler() can return null if the state machine has already quit. Since this is + // called from other classes, this condition must be verified. - // Cancel any existing disconnect due to loss of underlying network - // getHandler() can return null if the state machine has already quit. Since this is - // called - // from other classes, this condition must be verified. - if (getHandler() != null) { getHandler() .removeEqualMessages( EVENT_DISCONNECT_REQUESTED, new EventDisconnectRequestedInfo( DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); } + sendMessage( EVENT_UNDERLYING_NETWORK_CHANGED, - TOKEN_ANY, + TOKEN_ALL, new EventUnderlyingNetworkChangedInfo(underlying)); } } @@ -594,10 +595,101 @@ public class VcnGatewayConnection extends StateMachine { } 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 {} + /** + * 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 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. * @@ -608,7 +700,29 @@ public class VcnGatewayConnection extends StateMachine { 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. |