From 901dc86e4b8f43163ba425d244271595c1d0b664 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 17 Feb 2021 15:55:59 -0800 Subject: [PATCH 1/2] Define VcnNetworkPolicyListener for VCN transports. This CL defines VcnNetworkPolicyListener and VCN Network policy functions for VcnManager. Specifically, VcnNetworkPolicyListeners should be added and removed by Network factories as they bring up and teardown data Networks. VcnNetworkPolicyListeners are used by VcnManagementService to notify transports when they should re-query for their updated VcnNetworkPolicyResults - done via VcnManager#applyVcnNetworkPolicy. Policy results inform transports what the current NetworkCapabilities are based on their VCN policy, and also whether the transport should teardown and restart. Bug: 177020190 Test: atest FrameworksVcnTests Change-Id: Ide2c73025f4ffceabf7955f219a79be5a9bdc0d9 --- core/java/android/net/vcn/VcnManager.java | 163 ++++++++++++------ .../net/vcn/VcnNetworkPolicyResult.aidl | 20 +++ .../net/vcn/VcnNetworkPolicyResult.java | 109 ++++++++++++ .../net/vcn/VcnUnderlyingNetworkPolicy.java | 27 +-- .../vcn/VcnUnderlyingNetworkPolicyTest.java | 2 +- 5 files changed, 258 insertions(+), 63 deletions(-) create mode 100644 core/java/android/net/vcn/VcnNetworkPolicyResult.aidl create mode 100644 core/java/android/net/vcn/VcnNetworkPolicyResult.java diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java index aea0ea988f509..1c21844abf3d7 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -72,8 +72,7 @@ import java.util.concurrent.Executor; public class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); - private static final Map< - VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder> + private static final Map REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>(); @NonNull private final Context mContext; @@ -93,13 +92,13 @@ public class VcnManager { } /** - * Get all currently registered VcnUnderlyingNetworkPolicyListeners for testing purposes. + * Get all currently registered VcnNetworkPolicyListeners for testing purposes. * * @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) @NonNull - public static Map + public static Map getAllPolicyListeners() { return Collections.unmodifiableMap(REGISTERED_POLICY_LISTENERS); } @@ -161,22 +160,15 @@ public class VcnManager { } } - // TODO: make VcnUnderlyingNetworkPolicyListener @SystemApi + // TODO(b/180537630): remove all VcnUnderlyingNetworkPolicyListener refs once Telephony is using + // the new VcnNetworkPolicyListener API /** * VcnUnderlyingNetworkPolicyListener is the interface through which internal system components * can register to receive updates for VCN-underlying Network policies from the System Server. * * @hide */ - public interface VcnUnderlyingNetworkPolicyListener { - /** - * Notifies the implementation that the VCN's underlying Network policy has changed. - * - *

After receiving this callback, implementations MUST poll VcnManager for the updated - * VcnUnderlyingNetworkPolicy via VcnManager#getUnderlyingNetworkPolicy. - */ - void onPolicyChanged(); - } + public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyListener {} /** * Add a listener for VCN-underlying network policy updates. @@ -185,29 +177,14 @@ public class VcnManager { * Listener * @param listener the VcnUnderlyingNetworkPolicyListener to be added * @throws SecurityException if the caller does not have permission NETWORK_FACTORY - * @throws IllegalArgumentException if the specified VcnUnderlyingNetworkPolicyListener is - * already registered + * @throws IllegalStateException if the specified VcnUnderlyingNetworkPolicyListener is already + * registered * @hide */ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnUnderlyingNetworkPolicyListener( @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) { - requireNonNull(executor, "executor must not be null"); - requireNonNull(listener, "listener must not be null"); - - VcnUnderlyingNetworkPolicyListenerBinder binder = - new VcnUnderlyingNetworkPolicyListenerBinder(executor, listener); - if (REGISTERED_POLICY_LISTENERS.putIfAbsent(listener, binder) != null) { - throw new IllegalArgumentException( - "Attempting to add a listener that is already in use"); - } - - try { - mService.addVcnUnderlyingNetworkPolicyListener(binder); - } catch (RemoteException e) { - REGISTERED_POLICY_LISTENERS.remove(listener); - throw e.rethrowFromSystemServer(); - } + addVcnNetworkPolicyListener(executor, listener); } /** @@ -220,19 +197,7 @@ public class VcnManager { */ public void removeVcnUnderlyingNetworkPolicyListener( @NonNull VcnUnderlyingNetworkPolicyListener listener) { - requireNonNull(listener, "listener must not be null"); - - VcnUnderlyingNetworkPolicyListenerBinder binder = - REGISTERED_POLICY_LISTENERS.remove(listener); - if (binder == null) { - return; - } - - try { - mService.removeVcnUnderlyingNetworkPolicyListener(binder); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + removeVcnNetworkPolicyListener(listener); } /** @@ -266,6 +231,107 @@ public class VcnManager { } } + // TODO: make VcnNetworkPolicyListener @SystemApi + /** + * VcnNetworkPolicyListener is the interface through which internal system components can + * register to receive updates for VCN-underlying Network policies from the System Server. + * + * @hide + */ + public interface VcnNetworkPolicyListener { + /** + * Notifies the implementation that the VCN's underlying Network policy has changed. + * + *

After receiving this callback, implementations should get the current {@link + * VcnNetworkPolicyResult} via {@link #applyVcnNetworkPolicy(NetworkCapabilities, + * LinkProperties)}. + */ + void onPolicyChanged(); + } + + /** + * Add a listener for VCN-underlying Network policy updates. + * + * @param executor the Executor that will be used for invoking all calls to the specified + * Listener + * @param listener the VcnNetworkPolicyListener to be added + * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws IllegalStateException if the specified VcnNetworkPolicyListener is already registered + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void addVcnNetworkPolicyListener( + @NonNull Executor executor, @NonNull VcnNetworkPolicyListener listener) { + requireNonNull(executor, "executor must not be null"); + requireNonNull(listener, "listener must not be null"); + + VcnUnderlyingNetworkPolicyListenerBinder binder = + new VcnUnderlyingNetworkPolicyListenerBinder(executor, listener); + if (REGISTERED_POLICY_LISTENERS.putIfAbsent(listener, binder) != null) { + throw new IllegalStateException("listener is already registered with VcnManager"); + } + + try { + mService.addVcnUnderlyingNetworkPolicyListener(binder); + } catch (RemoteException e) { + REGISTERED_POLICY_LISTENERS.remove(listener); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Remove the specified VcnNetworkPolicyListener from VcnManager. + * + *

If the specified listener is not currently registered, this is a no-op. + * + * @param listener the VcnNetworkPolicyListener that will be removed + * @hide + */ + public void removeVcnNetworkPolicyListener(@NonNull VcnNetworkPolicyListener listener) { + requireNonNull(listener, "listener must not be null"); + + VcnUnderlyingNetworkPolicyListenerBinder binder = + REGISTERED_POLICY_LISTENERS.remove(listener); + if (binder == null) { + return; + } + + try { + mService.removeVcnUnderlyingNetworkPolicyListener(binder); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Applies the network policy for a {@link android.net.Network} with the given parameters. + * + *

Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy + * may have changed via {@link VcnNetworkPolicyListener#onPolicyChanged()}, a Network Provider + * MUST poll for the updated Network policy based on that Network's capabilities and properties. + * + * @param networkCapabilities the NetworkCapabilities to be used in determining the Network + * policy result for this Network. + * @param linkProperties the LinkProperties to be used in determining the Network policy result + * for this Network. + * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @return the {@link VcnNetworkPolicyResult} to be used for this Network. + * @hide + */ + @NonNull + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public VcnNetworkPolicyResult applyVcnNetworkPolicy( + @NonNull NetworkCapabilities networkCapabilities, + @NonNull LinkProperties linkProperties) { + requireNonNull(networkCapabilities, "networkCapabilities must not be null"); + requireNonNull(linkProperties, "linkProperties must not be null"); + + final VcnUnderlyingNetworkPolicy policy = + getUnderlyingNetworkPolicy(networkCapabilities, linkProperties); + return new VcnNetworkPolicyResult( + policy.isTeardownRequested(), policy.getMergedNetworkCapabilities()); + } + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({ @@ -415,18 +481,17 @@ public class VcnManager { } /** - * Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System - * Server. + * Binder wrapper for added VcnNetworkPolicyListeners to receive signals from System Server. * * @hide */ private static class VcnUnderlyingNetworkPolicyListenerBinder extends IVcnUnderlyingNetworkPolicyListener.Stub { @NonNull private final Executor mExecutor; - @NonNull private final VcnUnderlyingNetworkPolicyListener mListener; + @NonNull private final VcnNetworkPolicyListener mListener; private VcnUnderlyingNetworkPolicyListenerBinder( - Executor executor, VcnUnderlyingNetworkPolicyListener listener) { + Executor executor, VcnNetworkPolicyListener listener) { mExecutor = executor; mListener = listener; } diff --git a/core/java/android/net/vcn/VcnNetworkPolicyResult.aidl b/core/java/android/net/vcn/VcnNetworkPolicyResult.aidl new file mode 100644 index 0000000000000..3f13abe869daa --- /dev/null +++ b/core/java/android/net/vcn/VcnNetworkPolicyResult.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2021 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 android.net.vcn; + +/** @hide */ +parcelable VcnNetworkPolicyResult; diff --git a/core/java/android/net/vcn/VcnNetworkPolicyResult.java b/core/java/android/net/vcn/VcnNetworkPolicyResult.java new file mode 100644 index 0000000000000..8d011421cdeb5 --- /dev/null +++ b/core/java/android/net/vcn/VcnNetworkPolicyResult.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2021 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 android.net.vcn; + +import android.annotation.NonNull; +import android.net.NetworkCapabilities; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * VcnNetworkPolicyResult represents the Network policy result for a Network transport applying its + * VCN policy via {@link VcnManager#applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}. + * + *

Transports that are bringing up networks capable of acting as a VCN's underlying network + * should query for policy state upon any capability changes (e.g. changing of TRUSTED bit), and + * when prompted by VcnManagementService via VcnNetworkPolicyListener. + * + * @hide + */ +public final class VcnNetworkPolicyResult implements Parcelable { + private final boolean mIsTearDownRequested; + private final NetworkCapabilities mNetworkCapabilities; + + /** + * Constructs a VcnNetworkPolicyResult with the specified parameters. + * + * @hide + */ + public VcnNetworkPolicyResult( + boolean isTearDownRequested, @NonNull NetworkCapabilities networkCapabilities) { + Objects.requireNonNull(networkCapabilities, "networkCapabilities must be non-null"); + + mIsTearDownRequested = isTearDownRequested; + mNetworkCapabilities = networkCapabilities; + } + + /** + * Returns whether this Carrier VCN policy policy result requires that the underlying Network + * should be torn down. + */ + public boolean isTeardownRequested() { + return mIsTearDownRequested; + } + + /** + * Returns the NetworkCapabilities with Carrier VCN policy bits applied to the provided + * capabilities. + */ + @NonNull + public NetworkCapabilities getNetworkCapabilities() { + return mNetworkCapabilities; + } + + @Override + public int hashCode() { + return Objects.hash(mIsTearDownRequested, mNetworkCapabilities); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof VcnNetworkPolicyResult)) return false; + final VcnNetworkPolicyResult that = (VcnNetworkPolicyResult) o; + + return mIsTearDownRequested == that.mIsTearDownRequested + && mNetworkCapabilities.equals(that.mNetworkCapabilities); + } + + /** {@inheritDoc} */ + @Override + public int describeContents() { + return 0; + } + + /** {@inheritDoc} */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeBoolean(mIsTearDownRequested); + dest.writeParcelable(mNetworkCapabilities, flags); + } + + /** Implement the Parcelable interface */ + public static final @NonNull Creator CREATOR = + new Creator() { + public VcnNetworkPolicyResult createFromParcel(Parcel in) { + return new VcnNetworkPolicyResult(in.readBoolean(), in.readParcelable(null)); + } + + public VcnNetworkPolicyResult[] newArray(int size) { + return new VcnNetworkPolicyResult[size]; + } + }; +} diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java index dd7c86d87ff2e..b47d5642419e5 100644 --- a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java +++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java @@ -33,8 +33,7 @@ import java.util.Objects; * @hide */ public final class VcnUnderlyingNetworkPolicy implements Parcelable { - private final boolean mIsTearDownRequested; - private final NetworkCapabilities mMergedNetworkCapabilities; + private final VcnNetworkPolicyResult mVcnNetworkPolicyResult; /** * Constructs a VcnUnderlyingNetworkPolicy with the specified parameters. @@ -46,8 +45,13 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { Objects.requireNonNull( mergedNetworkCapabilities, "mergedNetworkCapabilities must be nonnull"); - mIsTearDownRequested = isTearDownRequested; - mMergedNetworkCapabilities = mergedNetworkCapabilities; + mVcnNetworkPolicyResult = + new VcnNetworkPolicyResult(isTearDownRequested, mergedNetworkCapabilities); + } + + private VcnUnderlyingNetworkPolicy(@NonNull VcnNetworkPolicyResult vcnNetworkPolicyResult) { + this.mVcnNetworkPolicyResult = + Objects.requireNonNull(vcnNetworkPolicyResult, "vcnNetworkPolicyResult"); } /** @@ -55,7 +59,7 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { * be torn down. */ public boolean isTeardownRequested() { - return mIsTearDownRequested; + return mVcnNetworkPolicyResult.isTeardownRequested(); } /** @@ -64,12 +68,12 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { */ @NonNull public NetworkCapabilities getMergedNetworkCapabilities() { - return mMergedNetworkCapabilities; + return mVcnNetworkPolicyResult.getNetworkCapabilities(); } @Override public int hashCode() { - return Objects.hash(mIsTearDownRequested, mMergedNetworkCapabilities); + return Objects.hash(mVcnNetworkPolicyResult); } @Override @@ -78,8 +82,7 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { if (!(o instanceof VcnUnderlyingNetworkPolicy)) return false; final VcnUnderlyingNetworkPolicy that = (VcnUnderlyingNetworkPolicy) o; - return mIsTearDownRequested == that.mIsTearDownRequested - && mMergedNetworkCapabilities.equals(that.mMergedNetworkCapabilities); + return mVcnNetworkPolicyResult.equals(that.mVcnNetworkPolicyResult); } /** {@inheritDoc} */ @@ -91,16 +94,14 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { /** {@inheritDoc} */ @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeBoolean(mIsTearDownRequested); - dest.writeParcelable(mMergedNetworkCapabilities, flags); + dest.writeParcelable(mVcnNetworkPolicyResult, flags); } /** Implement the Parcelable interface */ public static final @NonNull Creator CREATOR = new Creator() { public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) { - return new VcnUnderlyingNetworkPolicy( - in.readBoolean(), in.readParcelable(null)); + return new VcnUnderlyingNetworkPolicy(in.readParcelable(null)); } public VcnUnderlyingNetworkPolicy[] newArray(int size) { diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java index 3ba0a1f53a9f0..a674425efea32 100644 --- a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java +++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java @@ -46,6 +46,6 @@ public class VcnUnderlyingNetworkPolicyTest { @Test public void testParcelUnparcel() { - assertParcelSane(SAMPLE_NETWORK_POLICY, 2); + assertParcelSane(SAMPLE_NETWORK_POLICY, 1); } } From a4c27eea1a8e023d013917c076c5540098d7d49a Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 17 Feb 2021 18:49:23 -0800 Subject: [PATCH 2/2] Change Exception class references to use Class.getName(). This CL updates references to fully qualified Exception names (such as "java.lang.RuntimeException") to get the Exception name through the Exception's Class Object (e.g. RuntimeException.class.getName()). Bug: 163433613 Test: atest FrameworksVcntests Change-Id: I1ceccedda0a513a8c41caaef752d9f0005eceac0 --- .../java/com/android/server/vcn/VcnGatewayConnection.java | 6 +++--- tests/vcn/java/android/net/vcn/VcnManagerTest.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 9ee072ee7ce53..06748a3aa2d13 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -969,7 +969,7 @@ public class VcnGatewayConnection extends StateMachine { mGatewayStatusCallback.onGatewayConnectionError( mConnectionConfig.getRequiredUnderlyingCapabilities(), VCN_ERROR_CODE_INTERNAL_ERROR, - "java.lang.RuntimeException", + RuntimeException.class.getName(), "Received " + exception.getClass().getSimpleName() + " with message: " @@ -991,11 +991,11 @@ public class VcnGatewayConnection extends StateMachine { } else if (exception instanceof IkeInternalException && exception.getCause() instanceof IOException) { errorCode = VCN_ERROR_CODE_NETWORK_ERROR; - exceptionClass = "java.io.IOException"; + exceptionClass = IOException.class.getName(); exceptionMessage = exception.getCause().getMessage(); } else { errorCode = VCN_ERROR_CODE_INTERNAL_ERROR; - exceptionClass = "java.lang.RuntimeException"; + exceptionClass = RuntimeException.class.getName(); exceptionMessage = "Received " + exception.getClass().getSimpleName() diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java index 708767605508b..ce8a898de2ed3 100644 --- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java +++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java @@ -207,7 +207,7 @@ public class VcnManagerTest { cbBinder.onGatewayConnectionError( UNDERLYING_NETWORK_CAPABILITIES, VcnManager.VCN_ERROR_CODE_NETWORK_ERROR, - "java.net.UnknownHostException", + UnknownHostException.class.getName(), "exception_message"); verify(mMockStatusCallback) .onGatewayConnectionError(