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

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

Merge changes Icf32cb46,I43434c80,I59dc46dc,I7df3f14b,I50f2c0e9

* changes:
  Don't process dup unwanted() when unregistering NetworkAgent
  Add/remove internal addresses from IpSecTunnelInterface
  Populate legacy type in VCN NetworkAgentConfig
  Add TRANSPORT_CELLULAR to VCN filter
  Allow soft-start and opportunistic safe mode
parents caa46170 0906d6bc
Loading
Loading
Loading
Loading
+7 −13
Original line number Diff line number Diff line
@@ -542,16 +542,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {

        if (mVcns.containsKey(subscriptionGroup)) {
            final Vcn vcn = mVcns.get(subscriptionGroup);
            final int status = vcn.getStatus();
            vcn.updateConfig(config);

            // TODO(b/183174340): Remove this once opportunistic-safe-mode is supported
            // Only notify VcnStatusCallbacks if this VCN was previously in Safe Mode
            if (status == VCN_STATUS_CODE_SAFE_MODE) {
                // TODO(b/181789060): invoke asynchronously after Vcn notifies through VcnCallback
                notifyAllPermissionedStatusCallbacksLocked(
                        subscriptionGroup, VCN_STATUS_CODE_ACTIVE);
            }
        } else {
            startVcnLocked(subscriptionGroup, config);
        }
@@ -941,8 +932,8 @@ public class VcnManagementService extends IVcnManagementService.Stub {
    // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService
    /** Callback for Vcn signals sent up to VcnManagementService. */
    public interface VcnCallback {
        /** Called by a Vcn to signal that it has entered safe mode. */
        void onEnteredSafeMode();
        /** Called by a Vcn to signal that its safe mode status has changed. */
        void onSafeModeStatusChanged(boolean isInSafeMode);

        /** Called by a Vcn to signal that an error occurred. */
        void onGatewayConnectionError(
@@ -1004,15 +995,18 @@ public class VcnManagementService extends IVcnManagementService.Stub {
        }

        @Override
        public void onEnteredSafeMode() {
        public void onSafeModeStatusChanged(boolean isInSafeMode) {
            synchronized (mLock) {
                // Ignore if this subscription group doesn't exist anymore
                if (!mVcns.containsKey(mSubGroup)) {
                    return;
                }

                final int status =
                        isInSafeMode ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE;

                notifyAllPolicyListenersLocked();
                notifyAllPermissionedStatusCallbacksLocked(mSubGroup, VCN_STATUS_CODE_SAFE_MODE);
                notifyAllPermissionedStatusCallbacksLocked(mSubGroup, status);
            }
        }

+65 −63
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.vcn;

import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
@@ -96,16 +97,20 @@ public class Vcn extends Handler {
     */
    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;

    /**
     * Causes this VCN to immediately enter safe mode.
     * Triggers reevaluation of safe mode conditions.
     *
     * <p>Upon entering safe mode, the VCN will only provide gateway connections opportunistically,
     * leaving the underlying networks marked as NOT_VCN_MANAGED.
     *
     * <p>Upon entering safe mode, the VCN will unregister its RequestListener, tear down all of its
     * VcnGatewayConnections, and notify VcnManagementService that it is in safe mode.
     * <p>Any VcnGatewayConnection in safe mode will result in the entire Vcn instance being put
     * into safe mode. Upon receiving this message, the Vcn MUST query all VcnGatewayConnections to
     * determine if any are in safe mode.
     */
    private static final int MSG_CMD_ENTER_SAFE_MODE = MSG_CMD_BASE + 1;
    private static final int MSG_EVENT_SAFE_MODE_STATE_CHANGED = MSG_EVENT_BASE + 4;

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

    @NonNull private final VcnContext mVcnContext;
    @NonNull private final ParcelUuid mSubscriptionGroup;
@@ -233,6 +238,11 @@ public class Vcn extends Handler {

    @Override
    public void handleMessage(@NonNull Message msg) {
        if (mCurrentStatus != VCN_STATUS_CODE_ACTIVE
                && mCurrentStatus != VCN_STATUS_CODE_SAFE_MODE) {
            return;
        }

        switch (msg.what) {
            case MSG_EVENT_CONFIG_UPDATED:
                handleConfigUpdated((VcnConfig) msg.obj);
@@ -246,12 +256,12 @@ public class Vcn extends Handler {
            case MSG_EVENT_GATEWAY_CONNECTION_QUIT:
                handleGatewayConnectionQuit((VcnGatewayConnectionConfig) msg.obj);
                break;
            case MSG_EVENT_SAFE_MODE_STATE_CHANGED:
                handleSafeModeStatusChanged();
                break;
            case MSG_CMD_TEARDOWN:
                handleTeardown();
                break;
            case MSG_CMD_ENTER_SAFE_MODE:
                handleEnterSafeMode();
                break;
            default:
                Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what);
        }
@@ -263,10 +273,8 @@ public class Vcn extends Handler {

        mConfig = config;

        // TODO(b/183174340): Remove this once opportunistic safe mode is supported.
        if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) {
            // VCN is already active - teardown any GatewayConnections whose configs have been
            // removed and get all current requests
        // Teardown any GatewayConnections whose configs have been removed and get all current
        // requests
        for (final Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry :
                mVcnGatewayConnections.entrySet()) {
            final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey();
@@ -277,8 +285,7 @@ public class Vcn extends Handler {
            if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) {
                if (gatewayConnection == null) {
                    Slog.wtf(
                                getLogTag(),
                                "Found gatewayConnectionConfig without GatewayConnection");
                            getLogTag(), "Found gatewayConnectionConfig without GatewayConnection");
                } else {
                    gatewayConnection.teardownAsynchronously();
                }
@@ -288,15 +295,6 @@ public class Vcn extends Handler {
        // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be
        // satisfied start a new GatewayConnection)
        mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
        } else if (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE) {
            // If this VCN was not previously active, it is exiting Safe Mode. Re-register the
            // request listener to get NetworkRequests again (and all cached requests).
            mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener);
        } else {
            // Ignored; VCN was not active; config updates ignored.
            return;
        }
        mCurrentStatus = VCN_STATUS_CODE_ACTIVE;
    }

    private void handleTeardown() {
@@ -309,21 +307,27 @@ public class Vcn extends Handler {
        mCurrentStatus = VCN_STATUS_CODE_INACTIVE;
    }

    private void handleEnterSafeMode() {
        // TODO(b/183174340): Remove this once opportunistic-safe-mode is supported
        handleTeardown();
    private void handleSafeModeStatusChanged() {
        boolean hasSafeModeGatewayConnection = false;

        mCurrentStatus = VCN_STATUS_CODE_SAFE_MODE;
        mVcnCallback.onEnteredSafeMode();
        // If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode
        for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
            if (gatewayConnection.isInSafeMode()) {
                hasSafeModeGatewayConnection = true;
                break;
            }
        }

    private void handleNetworkRequested(
            @NonNull NetworkRequest request, int score, int providerId) {
        if (mCurrentStatus != VCN_STATUS_CODE_ACTIVE) {
            Slog.v(getLogTag(), "Received NetworkRequest while inactive. Ignore for now");
            return;
        final int oldStatus = mCurrentStatus;
        mCurrentStatus =
                hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE;
        if (oldStatus != mCurrentStatus) {
            mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection);
        }
    }

    private void handleNetworkRequested(
            @NonNull NetworkRequest request, int score, int providerId) {
        if (score > getNetworkScore()) {
            if (VDBG) {
                Slog.v(
@@ -376,25 +380,23 @@ public class Vcn extends Handler {
        mVcnGatewayConnections.remove(config);

        // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied
        // start a new GatewayConnection), but only if the Vcn is still alive
        if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) {
        // start a new GatewayConnection). VCN is always alive here, courtesy of the liveness check
        // in handleMessage()
        mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
    }
    }

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

        if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) {
        for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
            gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot);
        }
    }
    }

    private boolean isRequestSatisfiedByGatewayConnectionConfig(
            @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) {
        final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
        builder.addTransportType(TRANSPORT_CELLULAR);
        builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
        for (int cap : config.getAllExposedCapabilities()) {
            builder.addCapability(cap);
@@ -418,8 +420,8 @@ public class Vcn extends Handler {
    /** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */
    @VisibleForTesting(visibility = Visibility.PACKAGE)
    public interface VcnGatewayStatusCallback {
        /** Called by a VcnGatewayConnection to indicate that it has entered safe mode. */
        void onEnteredSafeMode();
        /** Called by a VcnGatewayConnection to indicate that it's safe mode status has changed. */
        void onSafeModeStatusChanged();

        /** Callback by a VcnGatewayConnection to indicate that an error occurred. */
        void onGatewayConnectionError(
@@ -445,8 +447,8 @@ public class Vcn extends Handler {
        }

        @Override
        public void onEnteredSafeMode() {
            sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE));
        public void onSafeModeStatusChanged() {
            sendMessage(obtainMessage(MSG_EVENT_SAFE_MODE_STATE_CHANGED));
        }

        @Override
+110 −38
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import static com.android.server.VcnManagementService.VDBG;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.IpSecManager;
@@ -44,6 +45,7 @@ import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkProvider;
import android.net.RouteInfo;
import android.net.TelephonyNetworkSpecifier;
import android.net.Uri;
@@ -92,6 +94,7 @@ import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * A single VCN Gateway Connection, providing a single public-facing VCN network.
@@ -503,6 +506,15 @@ public class VcnGatewayConnection extends StateMachine {
     */
    private boolean mIsQuitting = false;

    /**
     * Whether the VcnGatewayConnection is in safe mode.
     *
     * <p>Upon hitting the safe mode timeout, this will be set to {@code true}. In safe mode, this
     * VcnGatewayConnection will continue attempting to connect, and if a successful connection is
     * made, safe mode will be exited.
     */
    private boolean mIsInSafeMode = false;

    /**
     * The token used by the primary/current/active session.
     *
@@ -562,8 +574,7 @@ public class VcnGatewayConnection extends StateMachine {
     * <p>Set in Connected state, always @NonNull in Connected, Migrating states, @Nullable
     * otherwise.
     */
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    NetworkAgent mNetworkAgent;
    private NetworkAgent mNetworkAgent;

    @Nullable private WakeupMessage mTeardownTimeoutAlarm;
    @Nullable private WakeupMessage mDisconnectRequestAlarm;
@@ -628,6 +639,14 @@ public class VcnGatewayConnection extends StateMachine {
        start();
    }

    /** Queries whether this VcnGatewayConnection is in safe mode. */
    public boolean isInSafeMode() {
        // Accessing internal state; must only be done on looper thread.
        mVcnContext.ensureRunningOnLooperThread();

        return mIsInSafeMode;
    }

    /**
     * Asynchronously tears down this GatewayConnection, and any resources used.
     *
@@ -1162,6 +1181,15 @@ public class VcnGatewayConnection extends StateMachine {
            }
        }

        protected void handleSafeModeTimeoutExceeded() {
            mSafeModeTimeoutAlarm = null;

            // Connectivity for this GatewayConnection is broken; tear down the Network.
            teardownNetwork();
            mIsInSafeMode = true;
            mGatewayStatusCallback.onSafeModeStatusChanged();
        }

        protected void logUnexpectedEvent(int what) {
            Slog.d(TAG, String.format(
                    "Unexpected event code %d in state %s", what, this.getClass().getSimpleName()));
@@ -1315,8 +1343,7 @@ public class VcnGatewayConnection extends StateMachine {
                    }
                    break;
                case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
                    mGatewayStatusCallback.onEnteredSafeMode();
                    mSafeModeTimeoutAlarm = null;
                    handleSafeModeTimeoutExceeded();
                    break;
                default:
                    logUnhandledMessage(msg);
@@ -1401,8 +1428,7 @@ public class VcnGatewayConnection extends StateMachine {
                    handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
                    break;
                case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
                    mGatewayStatusCallback.onEnteredSafeMode();
                    mSafeModeTimeoutAlarm = null;
                    handleSafeModeTimeoutExceeded();
                    break;
                default:
                    logUnhandledMessage(msg);
@@ -1432,30 +1458,35 @@ public class VcnGatewayConnection extends StateMachine {
                    buildNetworkCapabilities(mConnectionConfig, mUnderlying);
            final LinkProperties lp =
                    buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig);
            final NetworkAgentConfig nac =
                    new NetworkAgentConfig.Builder()
                            .setLegacyType(ConnectivityManager.TYPE_MOBILE)
                            .build();

            final NetworkAgent agent =
                    new NetworkAgent(
                            mVcnContext.getContext(),
                            mVcnContext.getLooper(),
                    mDeps.newNetworkAgent(
                            mVcnContext,
                            TAG,
                            caps,
                            lp,
                            Vcn.getNetworkScore(),
                            new NetworkAgentConfig.Builder().build(),
                            mVcnContext.getVcnNetworkProvider()) {
                        @Override
                        public void onNetworkUnwanted() {
                            nac,
                            mVcnContext.getVcnNetworkProvider(),
                            () -> {
                                Slog.d(TAG, "NetworkAgent was unwanted");
                                // If network agent has already been torn down, skip sending the
                                // disconnect. Unwanted() is always called, even when networkAgents
                                // are unregistered in teardownNetwork(), so prevent duplicate
                                // notifications.
                                if (mNetworkAgent != null) {
                                    teardownAsynchronously();
                                }

                        @Override
                        public void onValidationStatus(int status, @Nullable Uri redirectUri) {
                            } /* networkUnwantedCallback */,
                            (status) -> {
                                if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
                                    clearFailedAttemptCounterAndSafeModeAlarm();
                                }
                        }
                    };
                            } /* validationStatusCallback */);

            agent.register();
            agent.markConnected();
@@ -1469,6 +1500,11 @@ public class VcnGatewayConnection extends StateMachine {
            // Validated connection, clear failed attempt counter
            mFailedAttempts = 0;
            cancelSafeModeAlarm();

            if (mIsInSafeMode) {
                mIsInSafeMode = false;
                mGatewayStatusCallback.onSafeModeStatusChanged();
            }
        }

        protected void applyTransform(
@@ -1488,13 +1524,6 @@ public class VcnGatewayConnection extends StateMachine {
            }
        }

        protected void setupInterface(
                int token,
                @NonNull IpSecTunnelInterface tunnelIface,
                @NonNull VcnChildSessionConfiguration childConfig) {
            setupInterface(token, tunnelIface, childConfig, null);
        }

        protected void setupInterface(
                int token,
                @NonNull IpSecTunnelInterface tunnelIface,
@@ -1579,16 +1608,17 @@ public class VcnGatewayConnection extends StateMachine {
                            transformCreatedInfo.direction);
                    break;
                case EVENT_SETUP_COMPLETED:
                    final VcnChildSessionConfiguration oldChildConfig = mChildConfig;
                    mChildConfig = ((EventSetupCompletedInfo) msg.obj).childSessionConfig;

                    setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig);
                    setupInterfaceAndNetworkAgent(
                            mCurrentToken, mTunnelIface, mChildConfig, oldChildConfig);
                    break;
                case EVENT_DISCONNECT_REQUESTED:
                    handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
                    break;
                case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
                    mGatewayStatusCallback.onEnteredSafeMode();
                    mSafeModeTimeoutAlarm = null;
                    handleSafeModeTimeoutExceeded();
                    break;
                default:
                    logUnhandledMessage(msg);
@@ -1626,8 +1656,9 @@ public class VcnGatewayConnection extends StateMachine {
        protected void setupInterfaceAndNetworkAgent(
                int token,
                @NonNull IpSecTunnelInterface tunnelIface,
                @NonNull VcnChildSessionConfiguration childConfig) {
            setupInterface(token, tunnelIface, childConfig);
                @NonNull VcnChildSessionConfiguration childConfig,
                @NonNull VcnChildSessionConfiguration oldChildConfig) {
            setupInterface(token, tunnelIface, childConfig, oldChildConfig);

            if (mNetworkAgent == null) {
                mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig);
@@ -1692,8 +1723,7 @@ public class VcnGatewayConnection extends StateMachine {
                    handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
                    break;
                case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
                    mGatewayStatusCallback.onEnteredSafeMode();
                    mSafeModeTimeoutAlarm = null;
                    handleSafeModeTimeoutExceeded();
                    break;
                default:
                    logUnhandledMessage(msg);
@@ -1934,6 +1964,16 @@ public class VcnGatewayConnection extends StateMachine {
        mIkeSession = session;
    }

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    NetworkAgent getNetworkAgent() {
        return mNetworkAgent;
    }

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    void setNetworkAgent(@Nullable NetworkAgent networkAgent) {
        mNetworkAgent = networkAgent;
    }

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    void sendDisconnectRequestedAndAcquireWakelock(String reason, boolean shouldQuit) {
        sendMessageAndAcquireWakeLock(
@@ -2018,6 +2058,38 @@ public class VcnGatewayConnection extends StateMachine {
            return new WakeupMessage(vcnContext.getContext(), handler, tag, runnable);
        }

        /** Builds a new NetworkAgent. */
        public NetworkAgent newNetworkAgent(
                @NonNull VcnContext vcnContext,
                @NonNull String tag,
                @NonNull NetworkCapabilities caps,
                @NonNull LinkProperties lp,
                @NonNull int score,
                @NonNull NetworkAgentConfig nac,
                @NonNull NetworkProvider provider,
                @NonNull Runnable networkUnwantedCallback,
                @NonNull Consumer<Integer> validationStatusCallback) {
            return new NetworkAgent(
                    vcnContext.getContext(),
                    vcnContext.getLooper(),
                    tag,
                    caps,
                    lp,
                    score,
                    nac,
                    provider) {
                @Override
                public void onNetworkUnwanted() {
                    networkUnwantedCallback.run();
                }

                @Override
                public void onValidationStatus(int status, @Nullable Uri redirectUri) {
                    validationStatusCallback.accept(status);
                }
            };
        }

        /** Gets the elapsed real time since boot, in millis. */
        public long getElapsedRealTime() {
            return SystemClock.elapsedRealtime();
+28 −24

File changed.

Preview size limit exceeded, changes collapsed.

+126 −16

File changed.

Preview size limit exceeded, changes collapsed.

Loading