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

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

Merge "Implement Disconnected state" am: 4f278834 am: b66cdc3e am: 6a762e05 am: 76b7d4c1

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

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I5456257533fb244c9ef9cc5acc54c4a301df9264
parents 423f266f 76b7d4c1
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -24,6 +24,9 @@ import android.net.NetworkCapabilities;
import android.os.Handler;
import android.os.ParcelUuid;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;

import java.util.Objects;

/**
@@ -72,7 +75,8 @@ public class UnderlyingNetworkTracker extends Handler {
        @NonNull public final LinkProperties linkProperties;
        public final boolean blocked;

        private UnderlyingNetworkRecord(
        @VisibleForTesting(visibility = Visibility.PRIVATE)
        UnderlyingNetworkRecord(
                @NonNull Network network,
                @NonNull NetworkCapabilities networkCapabilities,
                @NonNull LinkProperties linkProperties,
+80 −9
Original line number Diff line number Diff line
@@ -360,11 +360,25 @@ public class VcnGatewayConnection extends StateMachine {
     */
    private static final int EVENT_TEARDOWN_TIMEOUT_EXPIRED = 8;

    @NonNull private final DisconnectedState mDisconnectedState = new DisconnectedState();
    @NonNull private final DisconnectingState mDisconnectingState = new DisconnectingState();
    @NonNull private final ConnectingState mConnectingState = new ConnectingState();
    @NonNull private final ConnectedState mConnectedState = new ConnectedState();
    @NonNull private final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState();
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    @NonNull
    final DisconnectedState mDisconnectedState = new DisconnectedState();

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    @NonNull
    final DisconnectingState mDisconnectingState = new DisconnectingState();

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    @NonNull
    final ConnectingState mConnectingState = new ConnectingState();

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    @NonNull
    final ConnectedState mConnectedState = new ConnectedState();

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    @NonNull
    final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState();

    @NonNull private final VcnContext mVcnContext;
    @NonNull private final ParcelUuid mSubscriptionGroup;
@@ -455,7 +469,8 @@ public class VcnGatewayConnection extends StateMachine {
        this(vcnContext, subscriptionGroup, connectionConfig, new Dependencies());
    }

    private VcnGatewayConnection(
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    VcnGatewayConnection(
            @NonNull VcnContext vcnContext,
            @NonNull ParcelUuid subscriptionGroup,
            @NonNull VcnGatewayConnectionConfig connectionConfig,
@@ -508,7 +523,6 @@ public class VcnGatewayConnection extends StateMachine {
                EVENT_DISCONNECT_REQUESTED,
                TOKEN_ALL,
                new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN));
        quit();

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

        protected void handleDisconnectRequested(String msg) {
            Slog.v(TAG, "Tearing down. Cause: " + msg);
            mIsRunning = false;

            teardownNetwork();
            teardownIke();

@@ -697,7 +713,37 @@ public class VcnGatewayConnection extends StateMachine {
     */
    private class DisconnectedState extends BaseState {
        @Override
        protected void processStateMsg(Message msg) {}
        protected void enterState() {
            if (!mIsRunning) {
                quitNow(); // Ignore all queued events; cleanup is complete.
            }

            if (mIkeSession != null || mNetworkAgent != null) {
                Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState");
            }
        }

        @Override
        protected void processStateMsg(Message msg) {
            switch (msg.what) {
                case EVENT_UNDERLYING_NETWORK_CHANGED:
                    // First network found; start tunnel
                    mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;

                    if (mUnderlying != null) {
                        transitionTo(mConnectingState);
                    }
                    break;
                case EVENT_DISCONNECT_REQUESTED:
                    mIsRunning = false;

                    quitNow();
                    break;
                default:
                    logUnhandledMessage(msg);
                    break;
            }
        }
    }

    private abstract class ActiveBaseState extends BaseState {
@@ -893,7 +939,32 @@ public class VcnGatewayConnection extends StateMachine {
        }
    }

    /** External dependencies used by VcnGatewayConnection, for injection in tests. */
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    UnderlyingNetworkTrackerCallback getUnderlyingNetworkTrackerCallback() {
        return mUnderlyingNetworkTrackerCallback;
    }

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    UnderlyingNetworkRecord getUnderlyingNetwork() {
        return mUnderlying;
    }

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    void setUnderlyingNetwork(@Nullable UnderlyingNetworkRecord record) {
        mUnderlying = record;
    }

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

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

    /** External dependencies used by VcnGatewayConnection, for injection in tests */
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    public static class Dependencies {
        /** Builds a new UnderlyingNetworkTracker. */
+10 −9
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server;

import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
import static com.android.server.vcn.VcnTestUtils.setupSystemService;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@@ -138,11 +139,16 @@ public class VcnManagementServiceTest {
    private final IBinder mMockIBinder = mock(IBinder.class);

    public VcnManagementServiceTest() throws Exception {
        setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
        setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
        setupSystemService(
                mSubMgr, Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class);
        setupSystemService(mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class);
                mMockContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
        setupSystemService(
                mMockContext, mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
        setupSystemService(
                mMockContext,
                mSubMgr,
                Context.TELEPHONY_SUBSCRIPTION_SERVICE,
                SubscriptionManager.class);
        setupSystemService(mMockContext, mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class);

        doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName();

@@ -186,11 +192,6 @@ public class VcnManagementServiceTest {
        mTestLooper.dispatchAll();
    }

    private void setupSystemService(Object service, String name, Class<?> serviceClass) {
        doReturn(name).when(mMockContext).getSystemServiceName(serviceClass);
        doReturn(service).when(mMockContext).getSystemService(name);
    }

    private void setupMockedCarrierPrivilege(boolean isPrivileged) {
        doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
                .when(mSubMgr)
+84 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.vcn;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;

import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

/** Tests for VcnGatewayConnection.DisconnectedState */
@RunWith(AndroidJUnit4.class)
@SmallTest
public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnectionTestBase {
    @Before
    public void setUp() throws Exception {
        super.setUp();

        mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectedState);
        mTestLooper.dispatchAll();
    }

    @Test
    public void testEnterWhileNotRunningTriggersQuit() throws Exception {
        final VcnGatewayConnection vgc =
                new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps);

        vgc.setIsRunning(false);
        vgc.transitionTo(vgc.mDisconnectedState);
        mTestLooper.dispatchAll();

        assertNull(vgc.getCurrentState());
    }

    @Test
    public void testNetworkChangesTriggerStateTransitions() throws Exception {
        mGatewayConnection
                .getUnderlyingNetworkTrackerCallback()
                .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
        mTestLooper.dispatchAll();

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

    @Test
    public void testNullNetworkDoesNotTriggerStateTransition() throws Exception {
        mGatewayConnection
                .getUnderlyingNetworkTrackerCallback()
                .onSelectedUnderlyingNetworkChanged(null);
        mTestLooper.dispatchAll();

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

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

        assertNull(mGatewayConnection.getCurrentState());
        verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any());
    }
}
+105 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.vcn;

import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;

import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;

import android.annotation.NonNull;
import android.content.Context;
import android.net.IpSecManager;
import android.net.IpSecTunnelInterfaceResponse;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnGatewayConnectionConfigTest;
import android.os.ParcelUuid;
import android.os.test.TestLooper;

import com.android.server.IpSecService;

import org.junit.Before;

import java.util.UUID;

public class VcnGatewayConnectionTestBase {
    protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
    protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 1;
    protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
    protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
            new UnderlyingNetworkRecord(
                    new Network(0),
                    new NetworkCapabilities(),
                    new LinkProperties(),
                    false /* blocked */);
    protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
            new UnderlyingNetworkRecord(
                    new Network(1),
                    new NetworkCapabilities(),
                    new LinkProperties(),
                    false /* blocked */);

    @NonNull protected final Context mContext;
    @NonNull protected final TestLooper mTestLooper;
    @NonNull protected final VcnNetworkProvider mVcnNetworkProvider;
    @NonNull protected final VcnContext mVcnContext;
    @NonNull protected final VcnGatewayConnectionConfig mConfig;
    @NonNull protected final VcnGatewayConnection.Dependencies mDeps;
    @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker;

    @NonNull protected final IpSecService mIpSecSvc;

    protected VcnGatewayConnection mGatewayConnection;

    public VcnGatewayConnectionTestBase() {
        mContext = mock(Context.class);
        mTestLooper = new TestLooper();
        mVcnNetworkProvider = mock(VcnNetworkProvider.class);
        mVcnContext = mock(VcnContext.class);
        mConfig = VcnGatewayConnectionConfigTest.buildTestConfig();
        mDeps = mock(VcnGatewayConnection.Dependencies.class);
        mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class);

        mIpSecSvc = mock(IpSecService.class);
        setupIpSecManager(mContext, mIpSecSvc);

        doReturn(mContext).when(mVcnContext).getContext();
        doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
        doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();

        doReturn(mUnderlyingNetworkTracker)
                .when(mDeps)
                .newUnderlyingNetworkTracker(any(), any(), any());
    }

    @Before
    public void setUp() throws Exception {
        IpSecTunnelInterfaceResponse resp =
                new IpSecTunnelInterfaceResponse(
                        IpSecManager.Status.OK,
                        TEST_IPSEC_TUNNEL_RESOURCE_ID,
                        TEST_IPSEC_TUNNEL_IFACE);
        doReturn(resp).when(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any());

        mGatewayConnection = new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps);
    }
}
Loading