Loading api/test-current.txt +7 −0 Original line number Diff line number Diff line Loading @@ -253,6 +253,13 @@ package android.net { field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0 } public class TrafficStats { method public static long getLoopbackRxBytes(); method public static long getLoopbackRxPackets(); method public static long getLoopbackTxBytes(); method public static long getLoopbackTxPackets(); } } package android.os { Loading core/java/android/net/TrafficStats.java +27 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.net; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.DownloadManager; import android.app.backup.BackupManager; import android.app.usage.NetworkStatsManager; Loading Loading @@ -154,6 +155,8 @@ public class TrafficStats { private static Object sProfilingLock = new Object(); private static final String LOOPBACK_IFACE = "lo"; /** * Set active tag to use when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. Loading Loading @@ -542,6 +545,30 @@ public class TrafficStats { return nativeGetIfaceStat(iface, TYPE_RX_BYTES); } /** {@hide} */ @TestApi public static long getLoopbackTxPackets() { return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_TX_PACKETS); } /** {@hide} */ @TestApi public static long getLoopbackRxPackets() { return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_RX_PACKETS); } /** {@hide} */ @TestApi public static long getLoopbackTxBytes() { return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_TX_BYTES); } /** {@hide} */ @TestApi public static long getLoopbackRxBytes() { return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_RX_BYTES); } /** * Return number of packets transmitted since device boot. Counts packets * across all network interfaces, and always increases monotonically since Loading services/core/java/com/android/server/IpSecService.java +40 −1 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.net.IpSecTransform; import android.net.IpSecTransformResponse; import android.net.IpSecUdpEncapResponse; import android.net.NetworkUtils; import android.net.TrafficStats; import android.net.util.NetdService; import android.os.Binder; import android.os.IBinder; Loading Loading @@ -120,6 +121,7 @@ public class IpSecService extends IIpSecService.Stub { } private final IpSecServiceConfiguration mSrvConfig; final UidFdTagger mUidFdTagger; /** * Interface for user-reference and kernel-resource cleanup. Loading Loading @@ -762,8 +764,23 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting public IpSecService(Context context, IpSecServiceConfiguration config) { this(context, config, (fd, uid) -> { try{ TrafficStats.setThreadStatsUid(uid); TrafficStats.tagFileDescriptor(fd); } finally { TrafficStats.clearThreadStatsUid(); } }); } /** @hide */ @VisibleForTesting public IpSecService( Context context, IpSecServiceConfiguration config, UidFdTagger uidFdTagger) { mContext = context; mSrvConfig = config; mUidFdTagger = uidFdTagger; } public void systemReady() { Loading Loading @@ -924,6 +941,26 @@ public class IpSecService extends IIpSecService.Stub { throw new IOException("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port"); } /** * Functional interface to do traffic tagging of given sockets to UIDs. * * <p>Specifically used by openUdpEncapsulationSocket to ensure data usage on the UDP encap * sockets are billed to the UID that the UDP encap socket was created on behalf of. * * <p>Separate class so that the socket tagging logic can be mocked; TrafficStats uses static * methods that cannot be easily mocked/tested. */ @VisibleForTesting public interface UidFdTagger { /** * Sets socket tag to assign all traffic to the provided UID. * * <p>Since the socket is created on behalf of an unprivileged application, all traffic * should be accounted to the UID of the unprivileged application. */ public void tag(FileDescriptor fd, int uid) throws IOException; } /** * Open a socket via the system server and bind it to the specified port (random if port=0). * This will return a PFD to the user that represent a bound UDP socket. The system server will Loading @@ -939,7 +976,8 @@ public class IpSecService extends IIpSecService.Stub { } checkNotNull(binder, "Null Binder passed to openUdpEncapsulationSocket"); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); int callingUid = Binder.getCallingUid(); UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); int resourceId = mNextResourceId.getAndIncrement(); FileDescriptor sockFd = null; try { Loading @@ -948,6 +986,7 @@ public class IpSecService extends IIpSecService.Stub { } sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); mUidFdTagger.tag(sockFd, callingUid); if (port != 0) { Log.v(TAG, "Binding to port " + port); Loading tests/net/java/com/android/server/IpSecServiceTest.java +64 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; Loading @@ -40,10 +41,14 @@ import android.net.IpSecTransform; import android.net.IpSecUdpEncapResponse; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.os.Process; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.system.ErrnoException; import android.system.Os; import android.system.StructStat; import dalvik.system.SocketTagger; import java.io.FileDescriptor; import java.net.InetAddress; Loading @@ -56,6 +61,7 @@ import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; /** Unit tests for {@link IpSecService}. */ @SmallTest Loading Loading @@ -411,4 +417,62 @@ public class IpSecServiceTest { mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId); } } @Test public void testUidFdtagger() throws Exception { SocketTagger actualSocketTagger = SocketTagger.get(); try { FileDescriptor sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // Has to be done after socket creation because BlockGuardOS calls tag on new sockets SocketTagger mockSocketTagger = mock(SocketTagger.class); SocketTagger.set(mockSocketTagger); mIpSecService.mUidFdTagger.tag(sockFd, Process.LAST_APPLICATION_UID); verify(mockSocketTagger).tag(eq(sockFd)); } finally { SocketTagger.set(actualSocketTagger); } } /** * Checks if two file descriptors point to the same file. * * <p>According to stat.h documentation, the correct way to check for equivalent or duplicated * file descriptors is to check their inode and device. These two entries uniquely identify any * file. */ private boolean fileDescriptorsEqual(FileDescriptor fd1, FileDescriptor fd2) { try { StructStat fd1Stat = Os.fstat(fd1); StructStat fd2Stat = Os.fstat(fd2); return fd1Stat.st_ino == fd2Stat.st_ino && fd1Stat.st_dev == fd2Stat.st_dev; } catch (ErrnoException e) { return false; } } @Test public void testOpenUdpEncapSocketTagsSocket() throws Exception { IpSecService.UidFdTagger mockTagger = mock(IpSecService.UidFdTagger.class); IpSecService testIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig, mockTagger); IpSecUdpEncapResponse udpEncapResp = testIpSecService.openUdpEncapsulationSocket(0, new Binder()); assertNotNull(udpEncapResp); assertEquals(IpSecManager.Status.OK, udpEncapResp.status); FileDescriptor sockFd = udpEncapResp.fileDescriptor.getFileDescriptor(); ArgumentMatcher<FileDescriptor> fdMatcher = (argFd) -> { return fileDescriptorsEqual(sockFd, argFd); }; verify(mockTagger).tag(argThat(fdMatcher), eq(Os.getuid())); testIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId); udpEncapResp.fileDescriptor.close(); } } Loading
api/test-current.txt +7 −0 Original line number Diff line number Diff line Loading @@ -253,6 +253,13 @@ package android.net { field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0 } public class TrafficStats { method public static long getLoopbackRxBytes(); method public static long getLoopbackRxPackets(); method public static long getLoopbackTxBytes(); method public static long getLoopbackTxPackets(); } } package android.os { Loading
core/java/android/net/TrafficStats.java +27 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.net; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.DownloadManager; import android.app.backup.BackupManager; import android.app.usage.NetworkStatsManager; Loading Loading @@ -154,6 +155,8 @@ public class TrafficStats { private static Object sProfilingLock = new Object(); private static final String LOOPBACK_IFACE = "lo"; /** * Set active tag to use when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. Loading Loading @@ -542,6 +545,30 @@ public class TrafficStats { return nativeGetIfaceStat(iface, TYPE_RX_BYTES); } /** {@hide} */ @TestApi public static long getLoopbackTxPackets() { return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_TX_PACKETS); } /** {@hide} */ @TestApi public static long getLoopbackRxPackets() { return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_RX_PACKETS); } /** {@hide} */ @TestApi public static long getLoopbackTxBytes() { return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_TX_BYTES); } /** {@hide} */ @TestApi public static long getLoopbackRxBytes() { return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_RX_BYTES); } /** * Return number of packets transmitted since device boot. Counts packets * across all network interfaces, and always increases monotonically since Loading
services/core/java/com/android/server/IpSecService.java +40 −1 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.net.IpSecTransform; import android.net.IpSecTransformResponse; import android.net.IpSecUdpEncapResponse; import android.net.NetworkUtils; import android.net.TrafficStats; import android.net.util.NetdService; import android.os.Binder; import android.os.IBinder; Loading Loading @@ -120,6 +121,7 @@ public class IpSecService extends IIpSecService.Stub { } private final IpSecServiceConfiguration mSrvConfig; final UidFdTagger mUidFdTagger; /** * Interface for user-reference and kernel-resource cleanup. Loading Loading @@ -762,8 +764,23 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting public IpSecService(Context context, IpSecServiceConfiguration config) { this(context, config, (fd, uid) -> { try{ TrafficStats.setThreadStatsUid(uid); TrafficStats.tagFileDescriptor(fd); } finally { TrafficStats.clearThreadStatsUid(); } }); } /** @hide */ @VisibleForTesting public IpSecService( Context context, IpSecServiceConfiguration config, UidFdTagger uidFdTagger) { mContext = context; mSrvConfig = config; mUidFdTagger = uidFdTagger; } public void systemReady() { Loading Loading @@ -924,6 +941,26 @@ public class IpSecService extends IIpSecService.Stub { throw new IOException("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port"); } /** * Functional interface to do traffic tagging of given sockets to UIDs. * * <p>Specifically used by openUdpEncapsulationSocket to ensure data usage on the UDP encap * sockets are billed to the UID that the UDP encap socket was created on behalf of. * * <p>Separate class so that the socket tagging logic can be mocked; TrafficStats uses static * methods that cannot be easily mocked/tested. */ @VisibleForTesting public interface UidFdTagger { /** * Sets socket tag to assign all traffic to the provided UID. * * <p>Since the socket is created on behalf of an unprivileged application, all traffic * should be accounted to the UID of the unprivileged application. */ public void tag(FileDescriptor fd, int uid) throws IOException; } /** * Open a socket via the system server and bind it to the specified port (random if port=0). * This will return a PFD to the user that represent a bound UDP socket. The system server will Loading @@ -939,7 +976,8 @@ public class IpSecService extends IIpSecService.Stub { } checkNotNull(binder, "Null Binder passed to openUdpEncapsulationSocket"); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); int callingUid = Binder.getCallingUid(); UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); int resourceId = mNextResourceId.getAndIncrement(); FileDescriptor sockFd = null; try { Loading @@ -948,6 +986,7 @@ public class IpSecService extends IIpSecService.Stub { } sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); mUidFdTagger.tag(sockFd, callingUid); if (port != 0) { Log.v(TAG, "Binding to port " + port); Loading
tests/net/java/com/android/server/IpSecServiceTest.java +64 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; Loading @@ -40,10 +41,14 @@ import android.net.IpSecTransform; import android.net.IpSecUdpEncapResponse; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.os.Process; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.system.ErrnoException; import android.system.Os; import android.system.StructStat; import dalvik.system.SocketTagger; import java.io.FileDescriptor; import java.net.InetAddress; Loading @@ -56,6 +61,7 @@ import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; /** Unit tests for {@link IpSecService}. */ @SmallTest Loading Loading @@ -411,4 +417,62 @@ public class IpSecServiceTest { mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId); } } @Test public void testUidFdtagger() throws Exception { SocketTagger actualSocketTagger = SocketTagger.get(); try { FileDescriptor sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // Has to be done after socket creation because BlockGuardOS calls tag on new sockets SocketTagger mockSocketTagger = mock(SocketTagger.class); SocketTagger.set(mockSocketTagger); mIpSecService.mUidFdTagger.tag(sockFd, Process.LAST_APPLICATION_UID); verify(mockSocketTagger).tag(eq(sockFd)); } finally { SocketTagger.set(actualSocketTagger); } } /** * Checks if two file descriptors point to the same file. * * <p>According to stat.h documentation, the correct way to check for equivalent or duplicated * file descriptors is to check their inode and device. These two entries uniquely identify any * file. */ private boolean fileDescriptorsEqual(FileDescriptor fd1, FileDescriptor fd2) { try { StructStat fd1Stat = Os.fstat(fd1); StructStat fd2Stat = Os.fstat(fd2); return fd1Stat.st_ino == fd2Stat.st_ino && fd1Stat.st_dev == fd2Stat.st_dev; } catch (ErrnoException e) { return false; } } @Test public void testOpenUdpEncapSocketTagsSocket() throws Exception { IpSecService.UidFdTagger mockTagger = mock(IpSecService.UidFdTagger.class); IpSecService testIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig, mockTagger); IpSecUdpEncapResponse udpEncapResp = testIpSecService.openUdpEncapsulationSocket(0, new Binder()); assertNotNull(udpEncapResp); assertEquals(IpSecManager.Status.OK, udpEncapResp.status); FileDescriptor sockFd = udpEncapResp.fileDescriptor.getFileDescriptor(); ArgumentMatcher<FileDescriptor> fdMatcher = (argFd) -> { return fileDescriptorsEqual(sockFd, argFd); }; verify(mockTagger).tag(argThat(fdMatcher), eq(Os.getuid())); testIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId); udpEncapResp.fileDescriptor.close(); } }