Add basic VcnMgmtSvc --> Vcn signals (startup, teardown, NetworkReq)
This change adds the relevant calls to ensure that the VcnMgmtSvc starts, updates and stops a Vcn instance when configs are set/removed Additionally, this change ensures that upon new network requests, the Vcn instance is notified. Bug: 163432852 Test: atest FrameworksVcnTests Change-Id: Ifec34fad8282a3d64b540d24f643f546463f4379
This commit is contained in:
@@ -43,6 +43,8 @@ import android.util.Slog;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||
import com.android.server.vcn.Vcn;
|
||||
import com.android.server.vcn.VcnContext;
|
||||
import com.android.server.vcn.util.PersistableBundleUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -122,11 +124,16 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
@NonNull private final Looper mLooper;
|
||||
@NonNull private final Handler mHandler;
|
||||
@NonNull private final VcnNetworkProvider mNetworkProvider;
|
||||
@NonNull private final VcnContext mVcnContext;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@NonNull
|
||||
private final Map<ParcelUuid, VcnConfig> mConfigs = new ArrayMap<>();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@NonNull
|
||||
private final Map<ParcelUuid, Vcn> mVcns = new ArrayMap<>();
|
||||
|
||||
@NonNull private final Object mLock = new Object();
|
||||
|
||||
@NonNull private final PersistableBundleUtils.LockingReadWriteHelper mConfigDiskRwHelper;
|
||||
@@ -141,6 +148,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
mNetworkProvider = new VcnNetworkProvider(mContext, mLooper);
|
||||
|
||||
mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE);
|
||||
mVcnContext = mDeps.newVcnContext(mContext, mLooper, mNetworkProvider);
|
||||
|
||||
// Run on handler to ensure I/O does not block system server startup
|
||||
mHandler.post(() -> {
|
||||
@@ -225,6 +233,22 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
newPersistableBundleLockingReadWriteHelper(@NonNull String path) {
|
||||
return new PersistableBundleUtils.LockingReadWriteHelper(path);
|
||||
}
|
||||
|
||||
/** Creates a new VcnContext */
|
||||
public VcnContext newVcnContext(
|
||||
@NonNull Context context,
|
||||
@NonNull Looper looper,
|
||||
@NonNull VcnNetworkProvider vcnNetworkProvider) {
|
||||
return new VcnContext(context, looper, vcnNetworkProvider);
|
||||
}
|
||||
|
||||
/** Creates a new Vcn instance using the provided configuration */
|
||||
public Vcn newVcn(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull ParcelUuid subscriptionGroup,
|
||||
@NonNull VcnConfig config) {
|
||||
return new Vcn(vcnContext, subscriptionGroup, config);
|
||||
}
|
||||
}
|
||||
|
||||
/** Notifies the VcnManagementService that external dependencies can be set up. */
|
||||
@@ -277,6 +301,17 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
"Carrier privilege required for subscription group to set VCN Config");
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void startOrUpdateVcnLocked(
|
||||
@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
|
||||
if (mVcns.containsKey(subscriptionGroup)) {
|
||||
mVcns.get(subscriptionGroup).updateConfig(config);
|
||||
} else {
|
||||
final Vcn newInstance = mDeps.newVcn(mVcnContext, subscriptionGroup, config);
|
||||
mVcns.put(subscriptionGroup, newInstance);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a VCN config for a given subscription group.
|
||||
*
|
||||
@@ -289,15 +324,14 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
|
||||
enforceCallingUserAndCarrierPrivilege(subscriptionGroup);
|
||||
|
||||
synchronized (mLock) {
|
||||
mConfigs.put(subscriptionGroup, config);
|
||||
Binder.withCleanCallingIdentity(() -> {
|
||||
synchronized (mLock) {
|
||||
mConfigs.put(subscriptionGroup, config);
|
||||
startOrUpdateVcnLocked(subscriptionGroup, config);
|
||||
|
||||
// Must be done synchronously to ensure that writes do not happen out-of-order.
|
||||
writeConfigsToDiskLocked();
|
||||
}
|
||||
|
||||
// TODO: Clear Binder calling identity
|
||||
// TODO: Trigger startup as necessary
|
||||
writeConfigsToDiskLocked();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -311,15 +345,17 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
|
||||
enforceCallingUserAndCarrierPrivilege(subscriptionGroup);
|
||||
|
||||
synchronized (mLock) {
|
||||
mConfigs.remove(subscriptionGroup);
|
||||
Binder.withCleanCallingIdentity(() -> {
|
||||
synchronized (mLock) {
|
||||
mConfigs.remove(subscriptionGroup);
|
||||
|
||||
// Must be done synchronously to ensure that writes do not happen out-of-order.
|
||||
writeConfigsToDiskLocked();
|
||||
}
|
||||
if (mVcns.containsKey(subscriptionGroup)) {
|
||||
mVcns.remove(subscriptionGroup).teardownAsynchronously();
|
||||
}
|
||||
|
||||
// TODO: Clear Binder calling identity
|
||||
// TODO: Trigger teardown as necessary
|
||||
writeConfigsToDiskLocked();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@@ -345,6 +381,14 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
/** Get current configuration list for testing purposes */
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
public Map<ParcelUuid, Vcn> getAllVcns() {
|
||||
synchronized (mLock) {
|
||||
return Collections.unmodifiableMap(mVcns);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Network provider for VCN networks.
|
||||
*
|
||||
@@ -357,7 +401,11 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
|
||||
@Override
|
||||
public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
|
||||
// TODO: Handle network requests - Ensure VCN started, and start appropriate tunnels.
|
||||
synchronized (mLock) {
|
||||
for (Vcn instance : mVcns.values()) {
|
||||
instance.onNetworkRequested(request, score, providerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ public class Vcn extends Handler {
|
||||
}
|
||||
|
||||
/** Asynchronously tears down this Vcn instance, along with all tunnels and Networks */
|
||||
public void teardown() {
|
||||
public void teardownAsynchronously() {
|
||||
// TODO: Proxy to handler, and teardown there.
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -42,6 +43,9 @@ import android.telephony.TelephonyManager;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.server.VcnManagementService.VcnNetworkProvider;
|
||||
import com.android.server.vcn.Vcn;
|
||||
import com.android.server.vcn.VcnContext;
|
||||
import com.android.server.vcn.util.PersistableBundleUtils;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -92,10 +96,12 @@ public class VcnManagementServiceTest {
|
||||
private final ConnectivityManager mConnMgr = mock(ConnectivityManager.class);
|
||||
private final TelephonyManager mTelMgr = mock(TelephonyManager.class);
|
||||
private final SubscriptionManager mSubMgr = mock(SubscriptionManager.class);
|
||||
private final VcnManagementService mVcnMgmtSvc;
|
||||
private final VcnContext mVcnContext = mock(VcnContext.class);
|
||||
private final PersistableBundleUtils.LockingReadWriteHelper mConfigReadWriteHelper =
|
||||
mock(PersistableBundleUtils.LockingReadWriteHelper.class);
|
||||
|
||||
private final VcnManagementService mVcnMgmtSvc;
|
||||
|
||||
public VcnManagementServiceTest() throws Exception {
|
||||
setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
|
||||
setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
|
||||
@@ -104,10 +110,22 @@ public class VcnManagementServiceTest {
|
||||
|
||||
doReturn(mTestLooper.getLooper()).when(mMockDeps).getLooper();
|
||||
doReturn(Process.FIRST_APPLICATION_UID).when(mMockDeps).getBinderCallingUid();
|
||||
doReturn(mVcnContext)
|
||||
.when(mMockDeps)
|
||||
.newVcnContext(
|
||||
eq(mMockContext),
|
||||
eq(mTestLooper.getLooper()),
|
||||
any(VcnNetworkProvider.class));
|
||||
doReturn(mConfigReadWriteHelper)
|
||||
.when(mMockDeps)
|
||||
.newPersistableBundleLockingReadWriteHelper(any());
|
||||
|
||||
// Setup VCN instance generation
|
||||
doAnswer((invocation) -> {
|
||||
// Mock-within a doAnswer is safe, because it doesn't actually run nested.
|
||||
return mock(Vcn.class);
|
||||
}).when(mMockDeps).newVcn(any(), any(), any());
|
||||
|
||||
final PersistableBundle bundle =
|
||||
PersistableBundleUtils.fromMap(
|
||||
TEST_VCN_CONFIG_MAP,
|
||||
@@ -255,4 +273,26 @@ public class VcnManagementServiceTest {
|
||||
assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
|
||||
verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTeardsDownVcns() throws Exception {
|
||||
// Use a different UUID to simulate a new VCN config.
|
||||
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG);
|
||||
final Map<ParcelUuid, Vcn> vcnInstances = mVcnMgmtSvc.getAllVcns();
|
||||
final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2);
|
||||
assertEquals(1, vcnInstances.size());
|
||||
assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2));
|
||||
verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
|
||||
|
||||
// Verify Vcn is started
|
||||
verify(mMockDeps).newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG));
|
||||
|
||||
// Verify Vcn is updated if it was previously started
|
||||
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG);
|
||||
verify(vcnInstance).updateConfig(TEST_VCN_CONFIG);
|
||||
|
||||
// Verify Vcn is stopped if it was already started
|
||||
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
|
||||
verify(vcnInstance).teardownAsynchronously();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user