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

Commit cca000ac authored by Yan Yan's avatar Yan Yan Committed by Automerger Merge Worker
Browse files

Merge changes Ifc8ad902,I6d1b8d0e am: 8d659bb1 am: bdaf1de8

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

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: If7bedd741266a08bf2eef515f1fb72a9aebc74e3
parents db3dd2d5 bdaf1de8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6150,6 +6150,7 @@ package android.net {
    method public void close();
    method @NonNull public String getInterfaceName();
    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void setUnderlyingNetwork(@NonNull android.net.Network) throws java.io.IOException;
  }
  public static class IpSecTransform.Builder {
+3 −0
Original line number Diff line number Diff line
@@ -58,6 +58,9 @@ interface IIpSecService
            in LinkAddress localAddr,
            in String callingPackage);

    void setNetworkForTunnelInterface(
            int tunnelResourceId, in Network underlyingNetwork, in String callingPackage);

    void deleteTunnelInterface(int resourceId, in String callingPackage);

    IpSecTransformResponse createTransform(
+36 −0
Original line number Diff line number Diff line
@@ -782,6 +782,42 @@ public final class IpSecManager {
            }
        }

        /**
         * Update the underlying network for this IpSecTunnelInterface.
         *
         * <p>This new underlying network will be used for all transforms applied AFTER this call is
         * complete. Before new {@link IpSecTransform}(s) with matching addresses are applied to
         * this tunnel interface, traffic will still use the old SA, and be routed on the old
         * underlying network.
         *
         * <p>To migrate IPsec tunnel mode traffic, a caller should:
         *
         * <ol>
         *   <li>Update the IpSecTunnelInterface’s underlying network.
         *   <li>Apply {@link IpSecTransform}(s) with matching addresses to this
         *       IpSecTunnelInterface.
         * </ol>
         *
         * @param underlyingNetwork the new {@link Network} that will carry traffic for this tunnel.
         *     This network MUST never be the network exposing this IpSecTunnelInterface, otherwise
         *     this method will throw an {@link IllegalArgumentException}.
         */
        // TODO: b/169171001 Update the documentation when transform migration is supported.
        // The purpose of making updating network and applying transforms separate is to leave open
        // the possibility to support lossless migration procedures. To do that, Android platform
        // will need to support multiple inbound tunnel mode transforms, just like it can support
        // multiple transport mode transforms.
        @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
        @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
        public void setUnderlyingNetwork(@NonNull Network underlyingNetwork) throws IOException {
            try {
                mService.setNetworkForTunnelInterface(
                        mResourceId, underlyingNetwork, mOpPackageName);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

        private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service,
                @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress,
                @NonNull Network underlyingNetwork)
+50 −4
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.IIpSecService;
import android.net.INetd;
import android.net.InetAddresses;
@@ -41,6 +42,7 @@ import android.net.IpSecTransformResponse;
import android.net.IpSecTunnelInterfaceResponse;
import android.net.IpSecUdpEncapResponse;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.TrafficStats;
import android.net.util.NetdService;
@@ -797,9 +799,15 @@ public class IpSecService extends IIpSecService.Stub {
        }
    }

    private final class TunnelInterfaceRecord extends OwnedResourceRecord {
    /**
     * Tracks an tunnel interface, and manages cleanup paths.
     *
     * <p>This class is not thread-safe, and expects that that users of this class will ensure
     * synchronization and thread safety by holding the IpSecService.this instance lock
     */
    @VisibleForTesting
    final class TunnelInterfaceRecord extends OwnedResourceRecord {
        private final String mInterfaceName;
        private final Network mUnderlyingNetwork;

        // outer addresses
        private final String mLocalAddress;
@@ -810,6 +818,8 @@ public class IpSecService extends IIpSecService.Stub {

        private final int mIfId;

        private Network mUnderlyingNetwork;

        TunnelInterfaceRecord(
                int resourceId,
                String interfaceName,
@@ -870,14 +880,22 @@ public class IpSecService extends IIpSecService.Stub {
            releaseNetId(mOkey);
        }

        public String getInterfaceName() {
            return mInterfaceName;
        @GuardedBy("IpSecService.this")
        public void setUnderlyingNetwork(Network underlyingNetwork) {
            // When #applyTunnelModeTransform is called, this new underlying network will be used to
            // update the output mark of the input transform.
            mUnderlyingNetwork = underlyingNetwork;
        }

        @GuardedBy("IpSecService.this")
        public Network getUnderlyingNetwork() {
            return mUnderlyingNetwork;
        }

        public String getInterfaceName() {
            return mInterfaceName;
        }

        /** Returns the local, outer address for the tunnelInterface */
        public String getLocalAddress() {
            return mLocalAddress;
@@ -1429,6 +1447,34 @@ public class IpSecService extends IIpSecService.Stub {
        }
    }

    /** Set TunnelInterface to use a specific underlying network. */
    @Override
    public synchronized void setNetworkForTunnelInterface(
            int tunnelResourceId, Network underlyingNetwork, String callingPackage) {
        enforceTunnelFeatureAndPermissions(callingPackage);
        Objects.requireNonNull(underlyingNetwork, "No underlying network was specified");

        final UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());

        // Get tunnelInterface record; if no such interface is found, will throw
        // IllegalArgumentException. userRecord.mTunnelInterfaceRecords is never null
        final TunnelInterfaceRecord tunnelInterfaceInfo =
                userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);

        final ConnectivityManager connectivityManager =
                mContext.getSystemService(ConnectivityManager.class);
        final LinkProperties lp = connectivityManager.getLinkProperties(underlyingNetwork);
        if (tunnelInterfaceInfo.getInterfaceName().equals(lp.getInterfaceName())) {
            throw new IllegalArgumentException(
                    "Underlying network cannot be the network being exposed by this tunnel");
        }

        // It is meaningless to check if the network exists or is valid because the network might
        // disconnect at any time after it passes the check.

        tunnelInterfaceInfo.setUnderlyingNetwork(underlyingNetwork);
    }

    /**
     * Delete a TunnelInterface that has been been allocated by and registered with the system
     * server
+117 −35
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.InetAddresses;
import android.net.IpSecAlgorithm;
@@ -44,6 +45,7 @@ import android.net.IpSecTransformResponse;
import android.net.IpSecTunnelInterfaceResponse;
import android.net.IpSecUdpEncapResponse;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.os.Binder;
import android.os.INetworkManagementService;
@@ -53,6 +55,8 @@ import android.test.mock.MockContext;

import androidx.test.filters.SmallTest;

import com.android.server.IpSecService.TunnelInterfaceRecord;

import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -109,6 +113,7 @@ public class IpSecServiceParameterizedTest {
    };

    AppOpsManager mMockAppOps = mock(AppOpsManager.class);
    ConnectivityManager mMockConnectivityMgr = mock(ConnectivityManager.class);

    MockContext mMockContext = new MockContext() {
        @Override
@@ -116,11 +121,21 @@ public class IpSecServiceParameterizedTest {
            switch(name) {
                case Context.APP_OPS_SERVICE:
                    return mMockAppOps;
                case Context.CONNECTIVITY_SERVICE:
                    return mMockConnectivityMgr;
                default:
                    return null;
            }
        }

        @Override
        public String getSystemServiceName(Class<?> serviceClass) {
            if (ConnectivityManager.class == serviceClass) {
                return Context.CONNECTIVITY_SERVICE;
            }
            return null;
        }

        @Override
        public PackageManager getPackageManager() {
            return mMockPkgMgr;
@@ -151,6 +166,10 @@ public class IpSecServiceParameterizedTest {
            new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
    private static final int REMOTE_ENCAP_PORT = 4500;

    private static final String BLESSED_PACKAGE = "blessedPackage";
    private static final String SYSTEM_PACKAGE = "systemPackage";
    private static final String BAD_PACKAGE = "badPackage";

    public IpSecServiceParameterizedTest(
            String sourceAddr, String destAddr, String localInnerAddr, int family) {
        mSourceAddr = sourceAddr;
@@ -174,14 +193,14 @@ public class IpSecServiceParameterizedTest {
        when(mMockPkgMgr.hasSystemFeature(anyString())).thenReturn(true);

        // A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED.
        when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("blessedPackage")))
        when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(BLESSED_PACKAGE)))
                .thenReturn(AppOpsManager.MODE_ALLOWED);
        // A system package will not be granted the app op, so this should fall back to
        // a permissions check, which should pass.
        when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("systemPackage")))
        when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(SYSTEM_PACKAGE)))
                .thenReturn(AppOpsManager.MODE_DEFAULT);
        // A mismatch between the package name and the UID will return MODE_IGNORED.
        when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("badPackage")))
        when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(BAD_PACKAGE)))
                .thenReturn(AppOpsManager.MODE_IGNORED);
    }

@@ -338,7 +357,7 @@ public class IpSecServiceParameterizedTest {
        addAuthAndCryptToIpSecConfig(ipSecConfig);

        IpSecTransformResponse createTransformResp =
                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
        assertEquals(IpSecManager.Status.OK, createTransformResp.status);

        verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
@@ -352,7 +371,7 @@ public class IpSecServiceParameterizedTest {
        ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);

        IpSecTransformResponse createTransformResp =
                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
        assertEquals(IpSecManager.Status.OK, createTransformResp.status);

        verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
@@ -370,14 +389,14 @@ public class IpSecServiceParameterizedTest {

        if (mFamily == AF_INET) {
            IpSecTransformResponse createTransformResp =
                    mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                    mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
            assertEquals(IpSecManager.Status.OK, createTransformResp.status);

            verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
        } else {
            try {
                IpSecTransformResponse createTransformResp =
                        mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                        mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
                fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
            } catch (IllegalArgumentException expected) {
            }
@@ -396,14 +415,14 @@ public class IpSecServiceParameterizedTest {

        if (mFamily == AF_INET) {
            IpSecTransformResponse createTransformResp =
                    mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                    mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
            assertEquals(IpSecManager.Status.OK, createTransformResp.status);

            verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
        } else {
            try {
                IpSecTransformResponse createTransformResp =
                        mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                        mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
                fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
            } catch (IllegalArgumentException expected) {
            }
@@ -417,12 +436,12 @@ public class IpSecServiceParameterizedTest {
        addAuthAndCryptToIpSecConfig(ipSecConfig);

        IpSecTransformResponse createTransformResp =
                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
        assertEquals(IpSecManager.Status.OK, createTransformResp.status);

        // Attempting to create transform a second time with the same SPIs should throw an error...
        try {
                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
            mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
                fail("IpSecService should have thrown an error for reuse of SPI");
        } catch (IllegalStateException expected) {
        }
@@ -430,7 +449,7 @@ public class IpSecServiceParameterizedTest {
        // ... even if the transform is deleted
        mIpSecService.deleteTransform(createTransformResp.resourceId);
        try {
                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
            mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
                fail("IpSecService should have thrown an error for reuse of SPI");
        } catch (IllegalStateException expected) {
        }
@@ -443,7 +462,7 @@ public class IpSecServiceParameterizedTest {
        addAuthAndCryptToIpSecConfig(ipSecConfig);

        IpSecTransformResponse createTransformResp =
                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
        assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
        mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
@@ -467,7 +486,7 @@ public class IpSecServiceParameterizedTest {
        addAuthAndCryptToIpSecConfig(ipSecConfig);

        IpSecTransformResponse createTransformResp =
                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
        mIpSecService.deleteTransform(createTransformResp.resourceId);

        verify(mMockNetd, times(1))
@@ -515,7 +534,7 @@ public class IpSecServiceParameterizedTest {
        addAuthAndCryptToIpSecConfig(ipSecConfig);

        IpSecTransformResponse createTransformResp =
                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);

        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
        IpSecService.RefcountedResource refcountedRecord =
@@ -562,7 +581,7 @@ public class IpSecServiceParameterizedTest {
        addAuthAndCryptToIpSecConfig(ipSecConfig);

        IpSecTransformResponse createTransformResp =
                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);

        if (closeSpiBeforeApply) {
            mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
@@ -592,7 +611,7 @@ public class IpSecServiceParameterizedTest {
        addAuthAndCryptToIpSecConfig(ipSecConfig);

        IpSecTransformResponse createTransformResp =
                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);

        // Close SPI record
        mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
@@ -638,7 +657,7 @@ public class IpSecServiceParameterizedTest {
    @Test
    public void testCreateTunnelInterface() throws Exception {
        IpSecTunnelInterfaceResponse createTunnelResp =
                createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);

        // Check that we have stored the tracking object, and retrieve it
        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
@@ -661,11 +680,11 @@ public class IpSecServiceParameterizedTest {
    @Test
    public void testDeleteTunnelInterface() throws Exception {
        IpSecTunnelInterfaceResponse createTunnelResp =
                createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);

        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);

        mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, "blessedPackage");
        mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, BLESSED_PACKAGE);

        // Verify quota and RefcountedResource objects cleaned up
        assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
@@ -678,10 +697,73 @@ public class IpSecServiceParameterizedTest {
        }
    }

    private Network createFakeUnderlyingNetwork(String interfaceName) {
        final Network fakeNetwork = new Network(1000);
        final LinkProperties fakeLp = new LinkProperties();
        fakeLp.setInterfaceName(interfaceName);
        when(mMockConnectivityMgr.getLinkProperties(eq(fakeNetwork))).thenReturn(fakeLp);
        return fakeNetwork;
    }

    @Test
    public void testSetNetworkForTunnelInterface() throws Exception {
        final IpSecTunnelInterfaceResponse createTunnelResp =
                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
        final Network newFakeNetwork = createFakeUnderlyingNetwork("newFakeNetworkInterface");
        final int tunnelIfaceResourceId = createTunnelResp.resourceId;
        mIpSecService.setNetworkForTunnelInterface(
                tunnelIfaceResourceId, newFakeNetwork, BLESSED_PACKAGE);

        final IpSecService.UserRecord userRecord =
                mIpSecService.mUserResourceTracker.getUserRecord(mUid);
        assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);

        final TunnelInterfaceRecord tunnelInterfaceInfo =
                userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelIfaceResourceId);
        assertEquals(newFakeNetwork, tunnelInterfaceInfo.getUnderlyingNetwork());
    }

    @Test
    public void testSetNetworkForTunnelInterfaceFailsForInvalidResourceId() throws Exception {
        final IpSecTunnelInterfaceResponse createTunnelResp =
                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
        final Network newFakeNetwork = new Network(1000);

        try {
            mIpSecService.setNetworkForTunnelInterface(
                    IpSecManager.INVALID_RESOURCE_ID, newFakeNetwork, BLESSED_PACKAGE);
            fail("Expected an IllegalArgumentException for invalid resource ID.");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testSetNetworkForTunnelInterfaceFailsWhenSettingTunnelNetwork() throws Exception {
        final IpSecTunnelInterfaceResponse createTunnelResp =
                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
        final int tunnelIfaceResourceId = createTunnelResp.resourceId;
        final IpSecService.UserRecord userRecord =
                mIpSecService.mUserResourceTracker.getUserRecord(mUid);
        final TunnelInterfaceRecord tunnelInterfaceInfo =
                userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelIfaceResourceId);

        final Network newFakeNetwork =
                createFakeUnderlyingNetwork(tunnelInterfaceInfo.getInterfaceName());

        try {
            mIpSecService.setNetworkForTunnelInterface(
                    tunnelIfaceResourceId, newFakeNetwork, BLESSED_PACKAGE);
            fail(
                    "Expected an IllegalArgumentException because the underlying network is the"
                            + " network being exposed by this tunnel.");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testTunnelInterfaceBinderDeath() throws Exception {
        IpSecTunnelInterfaceResponse createTunnelResp =
                createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);

        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
        IpSecService.RefcountedResource refcountedRecord =
@@ -718,9 +800,9 @@ public class IpSecServiceParameterizedTest {
        addAuthAndCryptToIpSecConfig(ipSecConfig);

        IpSecTransformResponse createTransformResp =
                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
        IpSecTunnelInterfaceResponse createTunnelResp =
                createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);

        if (closeSpiBeforeApply) {
            mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
@@ -728,8 +810,8 @@ public class IpSecServiceParameterizedTest {

        int transformResourceId = createTransformResp.resourceId;
        int tunnelResourceId = createTunnelResp.resourceId;
        mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
                transformResourceId, "blessedPackage");
        mIpSecService.applyTunnelModeTransform(
                tunnelResourceId, IpSecManager.DIRECTION_OUT, transformResourceId, BLESSED_PACKAGE);

        for (int selAddrFamily : ADDRESS_FAMILIES) {
            verify(mMockNetd)
@@ -758,17 +840,17 @@ public class IpSecServiceParameterizedTest {
        addAuthAndCryptToIpSecConfig(ipSecConfig);

        IpSecTransformResponse createTransformResp =
                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
        IpSecTunnelInterfaceResponse createTunnelResp =
                createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);

        // Close SPI record
        mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());

        int transformResourceId = createTransformResp.resourceId;
        int tunnelResourceId = createTunnelResp.resourceId;
        mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
                transformResourceId, "blessedPackage");
        mIpSecService.applyTunnelModeTransform(
                tunnelResourceId, IpSecManager.DIRECTION_OUT, transformResourceId, BLESSED_PACKAGE);

        for (int selAddrFamily : ADDRESS_FAMILIES) {
            verify(mMockNetd)
@@ -790,7 +872,7 @@ public class IpSecServiceParameterizedTest {

    @Test
    public void testAddRemoveAddressFromTunnelInterface() throws Exception {
        for (String pkgName : new String[]{"blessedPackage", "systemPackage"}) {
        for (String pkgName : new String[] {BLESSED_PACKAGE, SYSTEM_PACKAGE}) {
            IpSecTunnelInterfaceResponse createTunnelResp =
                    createAndValidateTunnel(mSourceAddr, mDestinationAddr, pkgName);
            mIpSecService.addAddressToTunnelInterface(
@@ -816,7 +898,7 @@ public class IpSecServiceParameterizedTest {
    public void testAddTunnelFailsForBadPackageName() throws Exception {
        try {
            IpSecTunnelInterfaceResponse createTunnelResp =
                    createAndValidateTunnel(mSourceAddr, mDestinationAddr, "badPackage");
                    createAndValidateTunnel(mSourceAddr, mDestinationAddr, BAD_PACKAGE);
            fail("Expected a SecurityException for badPackage.");
        } catch (SecurityException expected) {
        }
@@ -830,7 +912,7 @@ public class IpSecServiceParameterizedTest {
        try {
            String addr = Inet4Address.getLoopbackAddress().getHostAddress();
            mIpSecService.createTunnelInterface(
                    addr, addr, new Network(0), new Binder(), "blessedPackage");
                    addr, addr, new Network(0), new Binder(), BLESSED_PACKAGE);
            fail("Expected UnsupportedOperationException for disabled feature");
        } catch (UnsupportedOperationException expected) {
        }