diff --git a/core/api/current.txt b/core/api/current.txt index a9303a7fa1a86..66b103a226505 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -26748,7 +26748,22 @@ package android.net.vcn { public class VcnManager { method @RequiresPermission("carrier privileges") public void clearVcnConfig(@NonNull android.os.ParcelUuid) throws java.io.IOException; + method public void registerVcnStatusCallback(@NonNull android.os.ParcelUuid, @NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnStatusCallback); method @RequiresPermission("carrier privileges") public void setVcnConfig(@NonNull android.os.ParcelUuid, @NonNull android.net.vcn.VcnConfig) throws java.io.IOException; + method public void unregisterVcnStatusCallback(@NonNull android.net.vcn.VcnManager.VcnStatusCallback); + field public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1; // 0x1 + field public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0; // 0x0 + field public static final int VCN_ERROR_CODE_NETWORK_ERROR = 2; // 0x2 + field public static final int VCN_STATUS_CODE_ACTIVE = 2; // 0x2 + field public static final int VCN_STATUS_CODE_INACTIVE = 1; // 0x1 + field public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0; // 0x0 + field public static final int VCN_STATUS_CODE_SAFE_MODE = 3; // 0x3 + } + + public abstract static class VcnManager.VcnStatusCallback { + ctor public VcnManager.VcnStatusCallback(); + method public abstract void onGatewayConnectionError(@NonNull int[], int, @Nullable Throwable); + method public abstract void onVcnStatusChanged(int); } } diff --git a/core/java/android/net/vcn/IVcnStatusCallback.aidl b/core/java/android/net/vcn/IVcnStatusCallback.aidl index d91cef592d10c..236ae8bb11b2b 100644 --- a/core/java/android/net/vcn/IVcnStatusCallback.aidl +++ b/core/java/android/net/vcn/IVcnStatusCallback.aidl @@ -18,7 +18,6 @@ package android.net.vcn; /** @hide */ oneway interface IVcnStatusCallback { - void onEnteredSafeMode(); void onVcnStatusChanged(int statusCode); void onGatewayConnectionError( in int[] gatewayNetworkCapabilities, diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java index eb8c251fec784..8ebf757760c34 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -359,8 +359,6 @@ public class VcnManager { /** * Value indicating that the VCN for the subscription group is not configured, or that the * callback is not privileged for the subscription group. - * - * @hide */ public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0; @@ -369,8 +367,6 @@ public class VcnManager { * *
A VCN is inactive if a {@link VcnConfig} is present for the subscription group, but the * provisioning package is not privileged. - * - * @hide */ public static final int VCN_STATUS_CODE_INACTIVE = 1; @@ -380,8 +376,6 @@ public class VcnManager { *
A VCN is active if a {@link VcnConfig} is present for the subscription, the provisioning * package is privileged, and the VCN is not in Safe Mode. In other words, a VCN is considered * active while it is connecting, fully connected, and disconnecting. - * - * @hide */ public static final int VCN_STATUS_CODE_ACTIVE = 2; @@ -391,8 +385,6 @@ public class VcnManager { *
A VCN will be put into Safe Mode if any of the gateway connections were unable to * establish a connection within a system-determined timeout (while underlying networks were * available). - * - * @hide */ public static final int VCN_STATUS_CODE_SAFE_MODE = 3; @@ -407,8 +399,6 @@ public class VcnManager { /** * Value indicating that an internal failure occurred in this Gateway Connection. - * - * @hide */ public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0; @@ -416,8 +406,6 @@ public class VcnManager { * Value indicating that an error with this Gateway Connection's configuration occurred. * *
For example, this error code will be returned after authentication failures. - * - * @hide */ public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1; @@ -427,37 +415,18 @@ public class VcnManager { *
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. * *
VcnStatusCallbacks may be registered before {@link VcnConfig}s are provided for a * subscription group. - * - * @hide */ public abstract static class VcnStatusCallback { private VcnStatusCallbackBinder mCbBinder; - /** - * Invoked when the VCN for this Callback's subscription group enters safe mode. - * - *
A VCN will be put into safe mode if any of the gateway connections were unable to - * establish a connection within a system-determined timeout (while underlying networks were - * available). - * - *
A VCN-configuring app may opt to exit safe mode by (re)setting the VCN configuration - * via {@link #setVcnConfig(ParcelUuid, VcnConfig)}. - * - * @hide - */ - public void onEnteredSafeMode() {} - /** * Invoked when status of the VCN for this callback's subscription group changes. * @@ -467,15 +436,16 @@ public class VcnManager { public abstract void onVcnStatusChanged(@VcnStatusCode int statusCode); /** - * Invoked when a VCN Gateway Connection corresponding to this callback's subscription + * Invoked when a VCN Gateway Connection corresponding to this callback's subscription group * 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 + * @param networkCapabilities an array of NetworkCapabilities.NET_CAPABILITY_* capabilities + * for the Gateway Connection that encountered the error, for identification purposes. + * These will be a sorted list with no duplicates and will match {@link + * VcnGatewayConnectionConfig#getRequiredUnderlyingCapabilities()} for 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 errorCode the code to indicate the error that occurred * @param detail Throwable to provide additional information about the error, or {@code * null} if none */ @@ -496,6 +466,10 @@ public class VcnManager { *
A {@link VcnStatusCallback} will only be invoked if the registering package has carrier * privileges for the specified subscription at the time of invocation. * + *
A {@link VcnStatusCallback} is eligible to begin receiving callbacks once it is registered + * and there is a VCN active for its specified subscription group (this may happen after the + * callback is registered). + * *
{@link VcnStatusCallback#onVcnStatusChanged(int)} will be invoked on registration with the
* current status for the specified subscription group's VCN. If the registrant is not
* privileged for this subscription group, {@link #VCN_STATUS_CODE_NOT_CONFIGURED} will be
@@ -505,7 +479,6 @@ public class VcnManager {
* @param executor The {@link Executor} to be used for invoking callbacks
* @param callback The VcnStatusCallback to be registered
* @throws IllegalStateException if callback is currently registered with VcnManager
- * @hide
*/
public void registerVcnStatusCallback(
@NonNull ParcelUuid subscriptionGroup,
@@ -538,7 +511,6 @@ public class VcnManager {
* was registered with.
*
* @param callback The callback to be unregistered
- * @hide
*/
public void unregisterVcnStatusCallback(@NonNull VcnStatusCallback callback) {
requireNonNull(callback, "callback must not be null");
@@ -598,12 +570,6 @@ public class VcnManager {
mCallback = callback;
}
- @Override
- public void onEnteredSafeMode() {
- Binder.withCleanCallingIdentity(
- () -> mExecutor.execute(() -> mCallback.onEnteredSafeMode()));
- }
-
@Override
public void onVcnStatusChanged(@VcnStatusCode int statusCode) {
Binder.withCleanCallingIdentity(
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 8d5d3d939e4b5..ad2f52401e931 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -35,6 +35,7 @@ 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.VcnUnderlyingNetworkPolicy;
import android.net.wifi.WifiInfo;
@@ -724,6 +725,26 @@ public class VcnManagementService extends IVcnManagementService.Stub {
}
}
+ private boolean isCallbackPermissioned(
+ @NonNull VcnStatusCallbackInfo cbInfo, @NonNull ParcelUuid subgroup) {
+ if (!subgroup.equals(cbInfo.mSubGroup)) {
+ return false;
+ }
+
+ if (!mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subgroup, cbInfo.mPkgName)) {
+ return false;
+ }
+
+ if (!mLocationPermissionChecker.checkLocationPermission(
+ cbInfo.mPkgName,
+ "VcnStatusCallback" /* featureId */,
+ cbInfo.mUid,
+ null /* message */)) {
+ return false;
+ }
+ return true;
+ }
+
/** Registers the provided callback for receiving VCN status updates. */
@Override
public void registerVcnStatusCallback(
@@ -758,6 +779,27 @@ public class VcnManagementService extends IVcnManagementService.Stub {
}
mRegisteredStatusCallbacks.put(cbBinder, cbInfo);
+
+ // 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;
+ if (vcnConfig == null || !isCallbackPermissioned(cbInfo, subGroup)) {
+ vcnStatus = VcnManager.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;
+ } else {
+ // TODO(b/181789060): create Vcn.getStatus() and Log.WTF() for unknown status
+ vcnStatus = VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+ }
+
+ try {
+ cbInfo.mCallback.onVcnStatusChanged(vcnStatus);
+ } catch (RemoteException e) {
+ Slog.d(TAG, "VcnStatusCallback threw on VCN status change", e);
+ }
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -806,26 +848,6 @@ public class VcnManagementService extends IVcnManagementService.Stub {
mSubGroup = Objects.requireNonNull(subGroup, "Missing subGroup");
}
- private boolean isCallbackPermissioned(@NonNull VcnStatusCallbackInfo cbInfo) {
- if (!mSubGroup.equals(cbInfo.mSubGroup)) {
- return false;
- }
-
- if (!mLastSnapshot.packageHasPermissionsForSubscriptionGroup(
- mSubGroup, cbInfo.mPkgName)) {
- return false;
- }
-
- if (!mLocationPermissionChecker.checkLocationPermission(
- cbInfo.mPkgName,
- "VcnStatusCallback" /* featureId */,
- cbInfo.mUid,
- null /* message */)) {
- return false;
- }
- return true;
- }
-
@Override
public void onEnteredSafeMode() {
synchronized (mLock) {
@@ -838,7 +860,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
// Notify all registered StatusCallbacks for this subGroup
for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
- if (isCallbackPermissioned(cbInfo)) {
+ if (isCallbackPermissioned(cbInfo, mSubGroup)) {
Binder.withCleanCallingIdentity(
() ->
cbInfo.mCallback.onVcnStatusChanged(
@@ -862,7 +884,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
// Notify all registered StatusCallbacks for this subGroup
for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
- if (isCallbackPermissioned(cbInfo)) {
+ if (isCallbackPermissioned(cbInfo, mSubGroup)) {
Binder.withCleanCallingIdentity(
() ->
cbInfo.mCallback.onGatewayConnectionError(
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
index 66590c92579b2..7515971b8307a 100644
--- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -203,9 +203,6 @@ public class VcnManagerTest {
IVcnStatusCallback cbBinder =
new VcnStatusCallbackBinder(INLINE_EXECUTOR, mMockStatusCallback);
- cbBinder.onEnteredSafeMode();
- verify(mMockStatusCallback).onEnteredSafeMode();
-
cbBinder.onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE);
verify(mMockStatusCallback).onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE);
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 9b500a7271d72..73a6b88e29edd 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -100,6 +100,8 @@ import java.util.UUID;
public class VcnManagementServiceTest {
private static final String TEST_PACKAGE_NAME =
VcnManagementServiceTest.class.getPackage().getName();
+ private static final String TEST_CB_PACKAGE_NAME =
+ VcnManagementServiceTest.class.getPackage().getName() + ".callback";
private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0));
private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1));
private static final VcnConfig TEST_VCN_CONFIG;
@@ -288,6 +290,14 @@ public class VcnManagementServiceTest {
private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
Set