Merge "Implement Policy Listener add/remove in VcnService."

This commit is contained in:
Cody Kesting
2021-01-22 17:20:12 +00:00
committed by Gerrit Code Review
2 changed files with 104 additions and 6 deletions

View File

@@ -31,16 +31,19 @@ import android.net.vcn.VcnConfig;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.UserHandle;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -155,6 +158,11 @@ public class VcnManagementService extends IVcnManagementService.Stub {
@NonNull private final PersistableBundleUtils.LockingReadWriteHelper mConfigDiskRwHelper;
@GuardedBy("mLock")
@NonNull
private final Map<IBinder, PolicyListenerBinderDeath> mRegisteredPolicyListeners =
new ArrayMap<>();
@VisibleForTesting(visibility = Visibility.PRIVATE)
VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) {
mContext = requireNonNull(context, "Missing context");
@@ -497,19 +505,60 @@ public class VcnManagementService extends IVcnManagementService.Stub {
}
}
/** Binder death recipient used to remove a registered policy listener. */
private class PolicyListenerBinderDeath implements Binder.DeathRecipient {
@NonNull private final IVcnUnderlyingNetworkPolicyListener mListener;
PolicyListenerBinderDeath(@NonNull IVcnUnderlyingNetworkPolicyListener listener) {
mListener = listener;
}
@Override
public void binderDied() {
Log.e(TAG, "app died without removing VcnUnderlyingNetworkPolicyListener");
removeVcnUnderlyingNetworkPolicyListener(mListener);
}
}
/** Adds the provided listener for receiving VcnUnderlyingNetworkPolicy updates. */
@GuardedBy("mLock")
@Override
public void addVcnUnderlyingNetworkPolicyListener(
IVcnUnderlyingNetworkPolicyListener listener) {
// TODO(b/175739863): implement policy listener registration
throw new UnsupportedOperationException("Not yet implemented");
@NonNull IVcnUnderlyingNetworkPolicyListener listener) {
requireNonNull(listener, "listener was null");
mContext.enforceCallingPermission(
android.Manifest.permission.NETWORK_FACTORY,
"Must have permission NETWORK_FACTORY to register a policy listener");
PolicyListenerBinderDeath listenerBinderDeath = new PolicyListenerBinderDeath(listener);
synchronized (mLock) {
mRegisteredPolicyListeners.put(listener.asBinder(), listenerBinderDeath);
try {
listener.asBinder().linkToDeath(listenerBinderDeath, 0 /* flags */);
} catch (RemoteException e) {
// Remote binder already died - cleanup registered Listener
listenerBinderDeath.binderDied();
}
}
}
/** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */
@GuardedBy("mLock")
@Override
public void removeVcnUnderlyingNetworkPolicyListener(
IVcnUnderlyingNetworkPolicyListener listener) {
// TODO(b/175739863): implement policy listener unregistration
throw new UnsupportedOperationException("Not yet implemented");
@NonNull IVcnUnderlyingNetworkPolicyListener listener) {
requireNonNull(listener, "listener was null");
synchronized (mLock) {
PolicyListenerBinderDeath listenerBinderDeath =
mRegisteredPolicyListeners.remove(listener.asBinder());
if (listenerBinderDeath != null) {
listener.asBinder().unlinkToDeath(listenerBinderDeath, 0 /* flags */);
}
}
}
}

View File

@@ -23,10 +23,15 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -35,8 +40,10 @@ import static org.mockito.Mockito.verify;
import android.app.AppOpsManager;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
import android.net.vcn.VcnConfigTest;
import android.os.IBinder;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.os.Process;
@@ -126,6 +133,10 @@ public class VcnManagementServiceTest {
private final VcnManagementService mVcnMgmtSvc;
private final IVcnUnderlyingNetworkPolicyListener mMockPolicyListener =
mock(IVcnUnderlyingNetworkPolicyListener.class);
private final IBinder mMockIBinder = mock(IBinder.class);
public VcnManagementServiceTest() throws Exception {
setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
@@ -169,6 +180,8 @@ public class VcnManagementServiceTest {
setupMockedCarrierPrivilege(true);
mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps);
doReturn(mMockIBinder).when(mMockPolicyListener).asBinder();
// Make sure the profiles are loaded.
mTestLooper.dispatchAll();
}
@@ -438,4 +451,40 @@ public class VcnManagementServiceTest {
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
verify(vcnInstance).teardownAsynchronously();
}
@Test
public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception {
doNothing()
.when(mMockContext)
.enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
verify(mMockIBinder).linkToDeath(any(), anyInt());
}
@Test(expected = SecurityException.class)
public void testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
doThrow(new SecurityException())
.when(mMockContext)
.enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
}
@Test
public void testRemoveVcnUnderlyingNetworkPolicyListener() {
// verify listener added
doNothing()
.when(mMockContext)
.enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
}
@Test
public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() {
mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
}
}