Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f8e1ebb6 authored by Benedict Wong's avatar Benedict Wong Committed by Automerger Merge Worker
Browse files

Merge "Add base states with exception catching and utility functions" am: 4d061143 am: c048e789

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1530783

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I36687edcbbe2cd6165e02b924372c0d666daacfb
parents 493aea74 c048e789
Loading
Loading
Loading
Loading
+136 −22
Original line number Diff line number Diff line
@@ -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.
            if (getHandler() != null) {
                // called from other classes, this condition must be verified.

                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.