diff options
4 files changed, 64 insertions, 49 deletions
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index 434e9241c742..4fd9373ad1df 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -40,7 +40,6 @@ import android.net.vcn.IVcnManagementService; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; -import android.net.vcn.VcnManager; import android.net.vcn.VcnManager.VcnErrorCode; import android.net.vcn.VcnManager.VcnStatusCode; import android.net.vcn.VcnUnderlyingNetworkPolicy; @@ -532,11 +531,12 @@ public class VcnManagementService extends IVcnManagementService.Stub { if (mVcns.containsKey(subscriptionGroup)) { final Vcn vcn = mVcns.get(subscriptionGroup); - final boolean isActive = vcn.isActive(); + 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 (!isActive) { + if (status == VCN_STATUS_CODE_SAFE_MODE) { // TODO(b/181789060): invoke asynchronously after Vcn notifies through VcnCallback notifyAllPermissionedStatusCallbacksLocked( subscriptionGroup, VCN_STATUS_CODE_ACTIVE); @@ -769,7 +769,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { synchronized (mLock) { final Vcn vcn = mVcns.get(subGrp); if (vcn != null) { - if (vcn.isActive()) { + if (vcn.getStatus() == VCN_STATUS_CODE_ACTIVE) { isVcnManagedNetwork = true; } @@ -880,20 +880,23 @@ public class VcnManagementService extends IVcnManagementService.Stub { // now that callback is registered, send it the VCN's current status final VcnConfig vcnConfig = mConfigs.get(subGroup); final Vcn vcn = mVcns.get(subGroup); - final int vcnStatus; + final int vcnStatus = + vcn == null ? VCN_STATUS_CODE_NOT_CONFIGURED : vcn.getStatus(); + final int resultStatus; if (vcnConfig == null || !isCallbackPermissioned(cbInfo, subGroup)) { - vcnStatus = VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; + resultStatus = VCN_STATUS_CODE_NOT_CONFIGURED; } else if (vcn == null) { - vcnStatus = VcnManager.VCN_STATUS_CODE_INACTIVE; - } else if (vcn.isActive()) { - vcnStatus = VcnManager.VCN_STATUS_CODE_ACTIVE; + resultStatus = VCN_STATUS_CODE_INACTIVE; + } else if (vcnStatus == VCN_STATUS_CODE_ACTIVE + || vcnStatus == VCN_STATUS_CODE_SAFE_MODE) { + resultStatus = vcnStatus; } else { - // TODO(b/181789060): create Vcn.getStatus() and Log.WTF() for unknown status - vcnStatus = VcnManager.VCN_STATUS_CODE_SAFE_MODE; + Slog.wtf(TAG, "Unknown VCN status: " + vcnStatus); + resultStatus = VCN_STATUS_CODE_NOT_CONFIGURED; } try { - cbInfo.mCallback.onVcnStatusChanged(vcnStatus); + cbInfo.mCallback.onVcnStatusChanged(resultStatus); } catch (RemoteException e) { Slog.d(TAG, "VcnStatusCallback threw on VCN status change", e); } diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java index c0130da7ddbc..54689358802f 100644 --- a/services/core/java/com/android/server/vcn/Vcn.java +++ b/services/core/java/com/android/server/vcn/Vcn.java @@ -17,6 +17,9 @@ package com.android.server.vcn; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; +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; import static com.android.server.VcnManagementService.VDBG; @@ -44,7 +47,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; /** * Represents an single instance of a VCN. @@ -137,17 +139,14 @@ public class Vcn extends Handler { @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; /** - * Whether this Vcn instance is active and running. + * The current status of this Vcn instance * - * <p>The value will be {@code true} while running. It will be {@code false} if the VCN has been - * shut down or has entered safe mode. - * - * <p>This AtomicBoolean is required in order to ensure consistency and correctness across - * multiple threads. Unlike the rest of the Vcn, this is queried synchronously on Binder threads - * from VcnManagementService, and therefore cannot rely on guarantees of running on the VCN - * Looper. + * <p>The value will be {@link VCN_STATUS_CODE_ACTIVE} while all VcnGatewayConnections are in + * good standing, {@link VCN_STATUS_CODE_SAFE_MODE} if any VcnGatewayConnections are in safe + * mode, and {@link VCN_STATUS_CODE_INACTIVE} once a teardown has been commanded. */ - private final AtomicBoolean mIsActive = new AtomicBoolean(true); + // Accessed from different threads, but always under lock in VcnManagementService + private volatile int mCurrentStatus = VCN_STATUS_CODE_ACTIVE; public Vcn( @NonNull VcnContext vcnContext, @@ -199,9 +198,15 @@ public class Vcn extends Handler { sendMessageAtFrontOfQueue(obtainMessage(MSG_CMD_TEARDOWN)); } - /** Synchronously checks whether this Vcn is active. */ - public boolean isActive() { - return mIsActive.get(); + /** Synchronously retrieves the current status code. */ + public int getStatus() { + return mCurrentStatus; + } + + /** Sets the status of this VCN */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public void setStatus(int status) { + mCurrentStatus = status; } /** Get current Gateways for testing purposes */ @@ -217,12 +222,6 @@ public class Vcn extends Handler { return Collections.unmodifiableMap(new HashMap<>(mVcnGatewayConnections)); } - /** Set whether this Vcn is active for testing purposes */ - @VisibleForTesting(visibility = Visibility.PRIVATE) - public void setIsActive(boolean isActive) { - mIsActive.set(isActive); - } - private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener { @Override public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { @@ -264,7 +263,8 @@ public class Vcn extends Handler { mConfig = config; - if (mIsActive.getAndSet(true)) { + // 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 for (final Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry : @@ -288,11 +288,15 @@ 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 { + } 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() { @@ -302,18 +306,20 @@ public class Vcn extends Handler { gatewayConnection.teardownAsynchronously(); } - mIsActive.set(false); + mCurrentStatus = VCN_STATUS_CODE_INACTIVE; } private void handleEnterSafeMode() { + // TODO(b/183174340): Remove this once opportunistic-safe-mode is supported handleTeardown(); + mCurrentStatus = VCN_STATUS_CODE_SAFE_MODE; mVcnCallback.onEnteredSafeMode(); } private void handleNetworkRequested( @NonNull NetworkRequest request, int score, int providerId) { - if (!isActive()) { + if (mCurrentStatus != VCN_STATUS_CODE_ACTIVE) { Slog.v(getLogTag(), "Received NetworkRequest while inactive. Ignore for now"); return; } @@ -370,8 +376,8 @@ 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 active - if (isActive()) { + // start a new GatewayConnection), but only if the Vcn is still alive + if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) { mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); } } @@ -379,7 +385,7 @@ public class Vcn extends Handler { private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) { mLastSnapshot = snapshot; - if (isActive()) { + if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) { for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) { gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot); } diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index c88b0c154712..4ad7136aabb2 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -19,6 +19,8 @@ package com.android.server; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; @@ -695,7 +697,9 @@ public class VcnManagementServiceTest { hasCarrierPrivileges); final Vcn vcn = startAndGetVcnInstance(subGrp); - doReturn(isVcnActive).when(vcn).isActive(); + doReturn(isVcnActive ? VCN_STATUS_CODE_ACTIVE : VCN_STATUS_CODE_SAFE_MODE) + .when(vcn) + .getStatus(); doReturn(true) .when(mLocationPermissionChecker) diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java index 530d8348bfff..540be38ed798 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java @@ -19,10 +19,12 @@ package com.android.server.vcn; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; +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; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; @@ -142,7 +144,7 @@ public class VcnTest { mTestLooper.dispatchAll(); } - private void verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(boolean isActive) { + private void verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(int status) { final NetworkRequestListener requestListener = verifyAndGetRequestListener(); startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]); @@ -152,25 +154,25 @@ public class VcnTest { final TelephonySubscriptionSnapshot updatedSnapshot = mock(TelephonySubscriptionSnapshot.class); - mVcn.setIsActive(isActive); + mVcn.setStatus(status); mVcn.updateSubscriptionSnapshot(updatedSnapshot); mTestLooper.dispatchAll(); for (final VcnGatewayConnection gateway : gatewayConnections) { - verify(gateway, isActive ? times(1) : never()) + verify(gateway, status == VCN_STATUS_CODE_ACTIVE ? times(1) : never()) .updateSubscriptionSnapshot(eq(updatedSnapshot)); } } @Test public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() { - verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(true /* isActive */); + verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_ACTIVE); } @Test - public void testSubscriptionSnapshotUpdatesVcnGatewayConnectionsWhileInactive() { - verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(false /* isActive */); + public void testSubscriptionSnapshotUpdatesVcnGatewayConnectionsInSafeMode() { + verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_SAFE_MODE); } private void triggerVcnRequestListeners(NetworkRequestListener requestListener) { @@ -201,7 +203,7 @@ public class VcnTest { private void verifySafeMode( NetworkRequestListener requestListener, Set<VcnGatewayConnection> expectedGatewaysTornDown) { - assertFalse(mVcn.isActive()); + assertEquals(VCN_STATUS_CODE_SAFE_MODE, mVcn.getStatus()); for (final VcnGatewayConnection gatewayConnection : expectedGatewaysTornDown) { verify(gatewayConnection).teardownAsynchronously(); } @@ -319,7 +321,7 @@ public class VcnTest { // Registered on start, then re-registered with new configs verify(mVcnNetworkProvider, times(2)).registerListener(eq(requestListener)); - assertTrue(mVcn.isActive()); + assertEquals(VCN_STATUS_CODE_ACTIVE, mVcn.getStatus()); for (final int[] caps : TEST_CAPS) { // Expect each gateway connection created only on initial startup verify(mDeps) @@ -334,7 +336,7 @@ public class VcnTest { @Test public void testIgnoreNetworkRequestWhileInactive() { - mVcn.setIsActive(false /* isActive */); + mVcn.setStatus(VCN_STATUS_CODE_INACTIVE); final NetworkRequestListener requestListener = verifyAndGetRequestListener(); triggerVcnRequestListeners(requestListener); |