Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e6ac91c authored by Cody Kesting's avatar Cody Kesting Committed by Automerger Merge Worker
Browse files

Merge "Implement Policy Listener add/remove in VcnService." am: 59035bd8 am: 3661eba6

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1532144

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Id9399ea6e21930adfa0c44767b7714f7e35cf64a
parents 2baff218 3661eba6
Loading
Loading
Loading
Loading
+55 −6
Original line number Diff line number Diff line
@@ -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 */);
            }
        }
    }
}
+49 −0
Original line number Diff line number Diff line
@@ -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);
    }
}