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

Commit a3fab46d authored by Benedict Wong's avatar Benedict Wong Committed by Gerrit Code Review
Browse files

Merge changes Ib439bde4,I5bc0fe94,I72abf1e2,Id1813bcb

* changes:
  Call setUnderlyingNetwork to complete VCN MOBIKE
  Rename isRunning to isQuitting, and flip all booleans
  Notify Vcn of VcnGatewayConnection quits
  Allow NETWORK_LOST disconnections to retry
parents 8c93a769 e145e066
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ public class UnderlyingNetworkTracker {
    @NonNull private final NetworkCallback mRouteSelectionCallback = new RouteSelectionCallback();

    @NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
    private boolean mIsRunning = true;
    private boolean mIsQuitting = false;

    @Nullable private UnderlyingNetworkRecord mCurrentRecord;
    @Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress;
@@ -151,7 +151,7 @@ public class UnderlyingNetworkTracker {
        mVcnContext.ensureRunningOnLooperThread();

        // Don't bother re-filing NetworkRequests if this Tracker has been torn down.
        if (!mIsRunning) {
        if (mIsQuitting) {
            return;
        }

@@ -205,7 +205,7 @@ public class UnderlyingNetworkTracker {
        }
        mCellBringupCallbacks.clear();

        mIsRunning = false;
        mIsQuitting = true;
    }

    /** Returns whether the currently selected Network matches the given network. */
+40 −4
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.vcn;

import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;

import static com.android.server.VcnManagementService.VDBG;

import android.annotation.NonNull;
@@ -84,6 +86,13 @@ public class Vcn extends Handler {
     */
    private static final int MSG_EVENT_SUBSCRIPTIONS_CHANGED = MSG_EVENT_BASE + 2;

    /**
     * A GatewayConnection owned by this VCN quit.
     *
     * @param obj VcnGatewayConnectionConfig
     */
    private static final int MSG_EVENT_GATEWAY_CONNECTION_QUIT = MSG_EVENT_BASE + 3;

    /** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */
    private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE;

@@ -208,6 +217,9 @@ public class Vcn extends Handler {
            case MSG_EVENT_SUBSCRIPTIONS_CHANGED:
                handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj);
                break;
            case MSG_EVENT_GATEWAY_CONNECTION_QUIT:
                handleGatewayConnectionQuit((VcnGatewayConnectionConfig) msg.obj);
                break;
            case MSG_CMD_TEARDOWN:
                handleTeardown();
                break;
@@ -263,7 +275,7 @@ public class Vcn extends Handler {

        // If preexisting VcnGatewayConnection(s) satisfy request, return
        for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) {
            if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
            if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
                if (VDBG) {
                    Slog.v(
                            getLogTag(),
@@ -278,7 +290,7 @@ public class Vcn extends Handler {
        // up
        for (VcnGatewayConnectionConfig gatewayConnectionConfig :
                mConfig.getGatewayConnectionConfigs()) {
            if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
            if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
                Slog.v(
                        getLogTag(),
                        "Bringing up new VcnGatewayConnection for request " + request.requestId);
@@ -289,12 +301,21 @@ public class Vcn extends Handler {
                                mSubscriptionGroup,
                                mLastSnapshot,
                                gatewayConnectionConfig,
                                new VcnGatewayStatusCallbackImpl());
                                new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig));
                mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection);
            }
        }
    }

    private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) {
        Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config);
        mVcnGatewayConnections.remove(config);

        // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied
        // start a new GatewayConnection)
        mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
    }

    private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) {
        mLastSnapshot = snapshot;

@@ -305,9 +326,10 @@ public class Vcn extends Handler {
        }
    }

    private boolean requestSatisfiedByGatewayConnectionConfig(
    private boolean isRequestSatisfiedByGatewayConnectionConfig(
            @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) {
        final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
        builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
        for (int cap : config.getAllExposedCapabilities()) {
            builder.addCapability(cap);
        }
@@ -339,9 +361,23 @@ public class Vcn extends Handler {
                @VcnErrorCode int errorCode,
                @Nullable String exceptionClass,
                @Nullable String exceptionMessage);

        /** Called by a VcnGatewayConnection to indicate that it has fully torn down. */
        void onQuit();
    }

    private class VcnGatewayStatusCallbackImpl implements VcnGatewayStatusCallback {
        public final VcnGatewayConnectionConfig mGatewayConnectionConfig;

        VcnGatewayStatusCallbackImpl(VcnGatewayConnectionConfig gatewayConnectionConfig) {
            mGatewayConnectionConfig = gatewayConnectionConfig;
        }

        @Override
        public void onQuit() {
            sendMessage(obtainMessage(MSG_EVENT_GATEWAY_CONNECTION_QUIT, mGatewayConnectionConfig));
        }

        @Override
        public void onEnteredSafeMode() {
            sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE));
+59 −44
Original line number Diff line number Diff line
@@ -168,6 +168,8 @@ public class VcnGatewayConnection extends StateMachine {
    private static final String DISCONNECT_REASON_INTERNAL_ERROR = "Uncaught exception: ";
    private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST =
            "Underlying Network lost";
    private static final String DISCONNECT_REASON_NETWORK_AGENT_UNWANTED =
            "NetworkAgent was unwanted";
    private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel";
    private static final int TOKEN_ALL = Integer.MIN_VALUE;

@@ -379,13 +381,16 @@ public class VcnGatewayConnection extends StateMachine {
        /** The reason why the disconnect was requested. */
        @NonNull public final String reason;

        EventDisconnectRequestedInfo(@NonNull String reason) {
        public final boolean shouldQuit;

        EventDisconnectRequestedInfo(@NonNull String reason, boolean shouldQuit) {
            this.reason = Objects.requireNonNull(reason);
            this.shouldQuit = shouldQuit;
        }

        @Override
        public int hashCode() {
            return Objects.hash(reason);
            return Objects.hash(reason, shouldQuit);
        }

        @Override
@@ -395,7 +400,7 @@ public class VcnGatewayConnection extends StateMachine {
            }

            final EventDisconnectRequestedInfo rhs = (EventDisconnectRequestedInfo) other;
            return reason.equals(rhs.reason);
            return reason.equals(rhs.reason) && shouldQuit == rhs.shouldQuit;
        }
    }

@@ -488,8 +493,14 @@ public class VcnGatewayConnection extends StateMachine {
     */
    @NonNull private final VcnWakeLock mWakeLock;

    /** Running state of this VcnGatewayConnection. */
    private boolean mIsRunning = true;
    /**
     * Whether the VcnGatewayConnection is in the process of irreversibly quitting.
     *
     * <p>This variable is false for the lifecycle of the VcnGatewayConnection, until a command to
     * teardown has been received. This may be flipped due to events such as the Network becoming
     * unwanted, the owning VCN entering safe mode, or an irrecoverable internal failure.
     */
    private boolean mIsQuitting = false;

    /**
     * The token used by the primary/current/active session.
@@ -622,10 +633,8 @@ public class VcnGatewayConnection extends StateMachine {
     * <p>Once torn down, this VcnTunnel CANNOT be started again.
     */
    public void teardownAsynchronously() {
        sendMessageAndAcquireWakeLock(
                EVENT_DISCONNECT_REQUESTED,
                TOKEN_ALL,
                new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN));
        sendDisconnectRequestedAndAcquireWakelock(
                DISCONNECT_REASON_TEARDOWN, true /* shouldQuit */);

        // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this
        // is also called asynchronously when a NetworkAgent becomes unwanted
@@ -646,6 +655,8 @@ public class VcnGatewayConnection extends StateMachine {
        cancelSafeModeAlarm();

        mUnderlyingNetworkTracker.teardown();

        mGatewayStatusCallback.onQuit();
    }

    /**
@@ -693,7 +704,7 @@ public class VcnGatewayConnection extends StateMachine {
    private void acquireWakeLock() {
        mVcnContext.ensureRunningOnLooperThread();

        if (mIsRunning) {
        if (!mIsQuitting) {
            mWakeLock.acquire();
        }
    }
@@ -892,7 +903,7 @@ public class VcnGatewayConnection extends StateMachine {
                        TOKEN_ALL,
                        0 /* arg2 */,
                        new EventDisconnectRequestedInfo(
                                DISCONNECT_REASON_UNDERLYING_NETWORK_LOST));
                                DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */));
        mDisconnectRequestAlarm =
                createScheduledAlarm(
                        DISCONNECT_REQUEST_ALARM,
@@ -909,7 +920,8 @@ public class VcnGatewayConnection extends StateMachine {
        // Cancel any existing disconnect due to previous loss of underlying network
        removeEqualMessages(
                EVENT_DISCONNECT_REQUESTED,
                new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST));
                new EventDisconnectRequestedInfo(
                        DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */));
    }

    private void setRetryTimeoutAlarm(long delay) {
@@ -1041,11 +1053,8 @@ public class VcnGatewayConnection extends StateMachine {
                enterState();
            } catch (Exception e) {
                Slog.wtf(TAG, "Uncaught exception", e);
                sendMessageAndAcquireWakeLock(
                        EVENT_DISCONNECT_REQUESTED,
                        TOKEN_ALL,
                        new EventDisconnectRequestedInfo(
                                DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
                sendDisconnectRequestedAndAcquireWakelock(
                        DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
            }
        }

@@ -1083,11 +1092,8 @@ public class VcnGatewayConnection extends StateMachine {
                processStateMsg(msg);
            } catch (Exception e) {
                Slog.wtf(TAG, "Uncaught exception", e);
                sendMessageAndAcquireWakeLock(
                        EVENT_DISCONNECT_REQUESTED,
                        TOKEN_ALL,
                        new EventDisconnectRequestedInfo(
                                DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
                sendDisconnectRequestedAndAcquireWakelock(
                        DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
            }

            // Attempt to release the WakeLock - only possible if the Handler queue is empty
@@ -1104,11 +1110,8 @@ public class VcnGatewayConnection extends StateMachine {
                exitState();
            } catch (Exception e) {
                Slog.wtf(TAG, "Uncaught exception", e);
                sendMessageAndAcquireWakeLock(
                        EVENT_DISCONNECT_REQUESTED,
                        TOKEN_ALL,
                        new EventDisconnectRequestedInfo(
                                DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
                sendDisconnectRequestedAndAcquireWakelock(
                        DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
            }
        }

@@ -1141,11 +1144,11 @@ public class VcnGatewayConnection extends StateMachine {
            }
        }

        protected void handleDisconnectRequested(String msg) {
        protected void handleDisconnectRequested(EventDisconnectRequestedInfo info) {
            // TODO(b/180526152): notify VcnStatusCallback for Network loss

            Slog.v(TAG, "Tearing down. Cause: " + msg);
            mIsRunning = false;
            Slog.v(TAG, "Tearing down. Cause: " + info.reason);
            mIsQuitting = info.shouldQuit;

            teardownNetwork();

@@ -1177,7 +1180,7 @@ public class VcnGatewayConnection extends StateMachine {
    private class DisconnectedState extends BaseState {
        @Override
        protected void enterState() {
            if (!mIsRunning) {
            if (mIsQuitting) {
                quitNow(); // Ignore all queued events; cleanup is complete.
            }

@@ -1200,9 +1203,11 @@ public class VcnGatewayConnection extends StateMachine {
                    }
                    break;
                case EVENT_DISCONNECT_REQUESTED:
                    mIsRunning = false;
                    if (((EventDisconnectRequestedInfo) msg.obj).shouldQuit) {
                        mIsQuitting = true;

                        quitNow();
                    }
                    break;
                default:
                    logUnhandledMessage(msg);
@@ -1284,10 +1289,11 @@ public class VcnGatewayConnection extends StateMachine {

                    break;
                case EVENT_DISCONNECT_REQUESTED:
                    EventDisconnectRequestedInfo info = ((EventDisconnectRequestedInfo) msg.obj);
                    mIsQuitting = info.shouldQuit;
                    teardownNetwork();

                    String reason = ((EventDisconnectRequestedInfo) msg.obj).reason;
                    if (reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) {
                    if (info.reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) {
                        // TODO(b/180526152): notify VcnStatusCallback for Network loss

                        // Will trigger EVENT_SESSION_CLOSED immediately.
@@ -1300,7 +1306,7 @@ public class VcnGatewayConnection extends StateMachine {
                case EVENT_SESSION_CLOSED:
                    mIkeSession = null;

                    if (mIsRunning && mUnderlying != null) {
                    if (!mIsQuitting && mUnderlying != null) {
                        transitionTo(mSkipRetryTimeout ? mConnectingState : mRetryTimeoutState);
                    } else {
                        teardownNetwork();
@@ -1391,7 +1397,7 @@ public class VcnGatewayConnection extends StateMachine {
                    transitionTo(mConnectedState);
                    break;
                case EVENT_DISCONNECT_REQUESTED:
                    handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
                    handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
                    break;
                case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
                    mGatewayStatusCallback.onEnteredSafeMode();
@@ -1438,6 +1444,7 @@ public class VcnGatewayConnection extends StateMachine {
                            mVcnContext.getVcnNetworkProvider()) {
                        @Override
                        public void unwanted() {
                            Slog.d(TAG, "NetworkAgent was unwanted");
                            teardownAsynchronously();
                        }

@@ -1471,7 +1478,7 @@ public class VcnGatewayConnection extends StateMachine {
                @NonNull IpSecTransform transform,
                int direction) {
            try {
                // TODO(b/180163196): Set underlying network of tunnel interface
                tunnelIface.setUnderlyingNetwork(underlyingNetwork);

                // Transforms do not need to be persisted; the IkeSession will keep them alive
                mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform);
@@ -1577,7 +1584,7 @@ public class VcnGatewayConnection extends StateMachine {
                    setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig);
                    break;
                case EVENT_DISCONNECT_REQUESTED:
                    handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
                    handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
                    break;
                case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
                    mGatewayStatusCallback.onEnteredSafeMode();
@@ -1682,7 +1689,7 @@ public class VcnGatewayConnection extends StateMachine {
                    transitionTo(mConnectingState);
                    break;
                case EVENT_DISCONNECT_REQUESTED:
                    handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
                    handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
                    break;
                case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
                    mGatewayStatusCallback.onEnteredSafeMode();
@@ -1905,13 +1912,13 @@ public class VcnGatewayConnection extends StateMachine {
    }

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    boolean isRunning() {
        return mIsRunning;
    boolean isQuitting() {
        return mIsQuitting;
    }

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    void setIsRunning(boolean isRunning) {
        mIsRunning = isRunning;
    void setIsQuitting(boolean isQuitting) {
        mIsQuitting = isQuitting;
    }

    @VisibleForTesting(visibility = Visibility.PRIVATE)
@@ -1924,6 +1931,14 @@ public class VcnGatewayConnection extends StateMachine {
        mIkeSession = session;
    }

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    void sendDisconnectRequestedAndAcquireWakelock(String reason, boolean shouldQuit) {
        sendMessageAndAcquireWakeLock(
                EVENT_DISCONNECT_REQUESTED,
                TOKEN_ALL,
                new EventDisconnectRequestedInfo(reason, shouldQuit));
    }

    private IkeSessionParams buildIkeParams() {
        // TODO: Implement this once IkeSessionParams is persisted
        return null;
+9 −3
Original line number Diff line number Diff line
@@ -67,9 +67,7 @@ public class VcnNetworkProvider extends NetworkProvider {
        mListeners.add(listener);

        // Send listener all cached requests
        for (NetworkRequestEntry entry : mRequests.values()) {
            notifyListenerForEvent(listener, entry);
        }
        resendAllRequests(listener);
    }

    /** Unregisters the specified listener from receiving future NetworkRequests. */
@@ -78,6 +76,14 @@ public class VcnNetworkProvider extends NetworkProvider {
        mListeners.remove(listener);
    }

    /** Sends all cached NetworkRequest(s) to the specified listener. */
    @VisibleForTesting(visibility = Visibility.PACKAGE)
    public void resendAllRequests(@NonNull NetworkRequestListener listener) {
        for (NetworkRequestEntry entry : mRequests.values()) {
            notifyListenerForEvent(listener, entry);
        }
    }

    private void notifyListenerForEvent(
            @NonNull NetworkRequestListener listener, @NonNull NetworkRequestEntry entry) {
        listener.onNetworkRequested(entry.mRequest, entry.mScore, entry.mProviderId);
+26 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;

@@ -143,11 +144,18 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
                .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
        mTestLooper.dispatchAll();

        verify(mIpSecSvc, times(2))
                .setNetworkForTunnelInterface(
                        eq(TEST_IPSEC_TUNNEL_RESOURCE_ID),
                        eq(TEST_UNDERLYING_NETWORK_RECORD_1.network),
                        any());

        for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
            verify(mIpSecSvc)
                    .applyTunnelModeTransform(
                            eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any());
        }

        assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
    }

@@ -290,4 +298,22 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
        verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback(
                new TemporaryFailureException("vcn test"), VCN_ERROR_CODE_INTERNAL_ERROR);
    }

    @Test
    public void testTeardown() throws Exception {
        mGatewayConnection.teardownAsynchronously();
        mTestLooper.dispatchAll();

        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
        assertTrue(mGatewayConnection.isQuitting());
    }

    @Test
    public void testNonTeardownDisconnectRequest() throws Exception {
        mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
        mTestLooper.dispatchAll();

        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
        assertFalse(mGatewayConnection.isQuitting());
    }
}
Loading