Define VcnStatusCallback#onGatewayConnectionError callback.
This CL updates VcnStatusCallback to have a onGatewayConnctionError() function. This function will be used to notify callers when Gateway Connection errors occur, such as authentication failures or the session unexpectedly dying. Bug: 163433613 Test: atest FrameworksVcnTests Change-Id: I9ea6e9e850eb9d8b0d374c5447895f1f04121696
This commit is contained in:
@@ -19,4 +19,9 @@ package android.net.vcn;
|
||||
/** @hide */
|
||||
interface IVcnStatusCallback {
|
||||
void onEnteredSafeMode();
|
||||
void onGatewayConnectionError(
|
||||
in int[] gatewayNetworkCapabilities,
|
||||
int errorCode,
|
||||
in String exceptionClass,
|
||||
in String exceptionMessage);
|
||||
}
|
||||
@@ -17,7 +17,9 @@ package android.net.vcn;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemService;
|
||||
import android.content.Context;
|
||||
@@ -32,6 +34,8 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -262,6 +266,42 @@ public class VcnManager {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
VCN_ERROR_CODE_INTERNAL_ERROR,
|
||||
VCN_ERROR_CODE_CONFIG_ERROR,
|
||||
VCN_ERROR_CODE_NETWORK_ERROR
|
||||
})
|
||||
public @interface VcnErrorCode {}
|
||||
|
||||
/**
|
||||
* Value indicating that an internal failure occurred in this Gateway Connection.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0;
|
||||
|
||||
/**
|
||||
* Value indicating that an error with this Gateway Connection's configuration occurred.
|
||||
*
|
||||
* <p>For example, this error code will be returned after authentication failures.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1;
|
||||
|
||||
/**
|
||||
* Value indicating that a Network error occurred with this Gateway Connection.
|
||||
*
|
||||
* <p>For example, this error code will be returned if an underlying {@link android.net.Network}
|
||||
* for this Gateway Connection is lost, or if an error occurs while resolving the connection
|
||||
* endpoint address.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int VCN_ERROR_CODE_NETWORK_ERROR = 2;
|
||||
|
||||
// TODO: make VcnStatusCallback @SystemApi
|
||||
/**
|
||||
* VcnStatusCallback is the interface for Carrier apps to receive updates for their VCNs.
|
||||
@@ -285,6 +325,24 @@ public class VcnManager {
|
||||
* via {@link #setVcnConfig(ParcelUuid, VcnConfig)}.
|
||||
*/
|
||||
public abstract void onEnteredSafeMode();
|
||||
|
||||
/**
|
||||
* Invoked when a VCN Gateway Connection corresponding to this callback's subscription
|
||||
* encounters an error.
|
||||
*
|
||||
* @param networkCapabilities an array of underlying NetworkCapabilities for the Gateway
|
||||
* Connection that encountered the error for identification purposes. These will be a
|
||||
* sorted list with no duplicates, matching one of the {@link
|
||||
* VcnGatewayConnectionConfig}s set in the {@link VcnConfig} for this subscription
|
||||
* group.
|
||||
* @param errorCode {@link VcnErrorCode} to indicate the error that occurred
|
||||
* @param detail Throwable to provide additional information about the error, or {@code
|
||||
* null} if none
|
||||
*/
|
||||
public abstract void onGatewayConnectionError(
|
||||
@NonNull int[] networkCapabilities,
|
||||
@VcnErrorCode int errorCode,
|
||||
@Nullable Throwable detail);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -385,11 +443,12 @@ public class VcnManager {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
private class VcnStatusCallbackBinder extends IVcnStatusCallback.Stub {
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
public static class VcnStatusCallbackBinder extends IVcnStatusCallback.Stub {
|
||||
@NonNull private final Executor mExecutor;
|
||||
@NonNull private final VcnStatusCallback mCallback;
|
||||
|
||||
private VcnStatusCallbackBinder(
|
||||
public VcnStatusCallbackBinder(
|
||||
@NonNull Executor executor, @NonNull VcnStatusCallback callback) {
|
||||
mExecutor = executor;
|
||||
mCallback = callback;
|
||||
@@ -400,5 +459,36 @@ public class VcnManager {
|
||||
Binder.withCleanCallingIdentity(
|
||||
() -> mExecutor.execute(() -> mCallback.onEnteredSafeMode()));
|
||||
}
|
||||
|
||||
// TODO(b/180521637): use ServiceSpecificException for safer Exception 'parceling'
|
||||
@Override
|
||||
public void onGatewayConnectionError(
|
||||
@NonNull int[] networkCapabilities,
|
||||
@VcnErrorCode int errorCode,
|
||||
@Nullable String exceptionClass,
|
||||
@Nullable String exceptionMessage) {
|
||||
final Throwable cause = createThrowableByClassName(exceptionClass, exceptionMessage);
|
||||
|
||||
Binder.withCleanCallingIdentity(
|
||||
() ->
|
||||
mExecutor.execute(
|
||||
() ->
|
||||
mCallback.onGatewayConnectionError(
|
||||
networkCapabilities, errorCode, cause)));
|
||||
}
|
||||
|
||||
private static Throwable createThrowableByClassName(
|
||||
@Nullable String className, @Nullable String message) {
|
||||
if (className == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
Class<?> c = Class.forName(className);
|
||||
return (Throwable) c.getConstructor(String.class).newInstance(message);
|
||||
} catch (ReflectiveOperationException | ClassCastException e) {
|
||||
return new RuntimeException(className + ": " + message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.notNull;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
@@ -33,6 +34,7 @@ import android.content.Context;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.vcn.VcnManager.VcnStatusCallback;
|
||||
import android.net.vcn.VcnManager.VcnStatusCallbackBinder;
|
||||
import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener;
|
||||
import android.os.ParcelUuid;
|
||||
|
||||
@@ -40,11 +42,15 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class VcnManagerTest {
|
||||
private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
|
||||
private static final int[] UNDERLYING_NETWORK_CAPABILITIES = {
|
||||
NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_INTERNET
|
||||
};
|
||||
private static final Executor INLINE_EXECUTOR = Runnable::run;
|
||||
|
||||
private IVcnManagementService mMockVcnManagementService;
|
||||
@@ -144,14 +150,8 @@ public class VcnManagerTest {
|
||||
public void testRegisterVcnStatusCallback() throws Exception {
|
||||
mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback);
|
||||
|
||||
ArgumentCaptor<IVcnStatusCallback> captor =
|
||||
ArgumentCaptor.forClass(IVcnStatusCallback.class);
|
||||
verify(mMockVcnManagementService)
|
||||
.registerVcnStatusCallback(eq(SUB_GROUP), captor.capture(), any());
|
||||
|
||||
IVcnStatusCallback callbackWrapper = captor.getValue();
|
||||
callbackWrapper.onEnteredSafeMode();
|
||||
verify(mMockStatusCallback).onEnteredSafeMode();
|
||||
.registerVcnStatusCallback(eq(SUB_GROUP), notNull(), any());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
@@ -195,4 +195,24 @@ public class VcnManagerTest {
|
||||
public void testUnregisterNullVcnStatusCallback() throws Exception {
|
||||
mVcnManager.unregisterVcnStatusCallback(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVcnStatusCallbackBinder() throws Exception {
|
||||
IVcnStatusCallback cbBinder =
|
||||
new VcnStatusCallbackBinder(INLINE_EXECUTOR, mMockStatusCallback);
|
||||
|
||||
cbBinder.onEnteredSafeMode();
|
||||
verify(mMockStatusCallback).onEnteredSafeMode();
|
||||
|
||||
cbBinder.onGatewayConnectionError(
|
||||
UNDERLYING_NETWORK_CAPABILITIES,
|
||||
VcnManager.VCN_ERROR_CODE_NETWORK_ERROR,
|
||||
"java.net.UnknownHostException",
|
||||
"exception_message");
|
||||
verify(mMockStatusCallback)
|
||||
.onGatewayConnectionError(
|
||||
eq(UNDERLYING_NETWORK_CAPABILITIES),
|
||||
eq(VcnManager.VCN_ERROR_CODE_NETWORK_ERROR),
|
||||
any(UnknownHostException.class));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user