Merge "[FUI04] Refactor VpnInfo"

This commit is contained in:
Junyu Lai
2021-01-29 13:54:53 +00:00
committed by Gerrit Code Review
14 changed files with 291 additions and 184 deletions

View File

@@ -31,7 +31,6 @@ import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.ProxyInfo;
import android.net.UidRange;
import android.net.VpnInfo;
import android.net.QosSocketInfo;
import android.os.Bundle;
import android.os.IBinder;

View File

@@ -23,7 +23,7 @@ import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.VpnInfo;
import android.net.UnderlyingNetworkInfo;
import android.net.netstats.provider.INetworkStatsProvider;
import android.net.netstats.provider.INetworkStatsProviderCallback;
import android.os.IBinder;
@@ -70,7 +70,7 @@ interface INetworkStatsService {
in Network[] defaultNetworks,
in NetworkState[] networkStates,
in String activeIface,
in VpnInfo[] vpnInfos);
in UnderlyingNetworkInfo[] underlyingNetworkInfos);
/** Force update of statistics. */
@UnsupportedAppUsage
void forceUpdate();

View File

@@ -16,4 +16,4 @@
package android.net;
parcelable VpnInfo;
parcelable UnderlyingNetworkInfo;

View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* A lightweight container used to carry information on the networks that underly a given
* virtual network.
*
* @hide
*/
public final class UnderlyingNetworkInfo implements Parcelable {
/** The owner of this network. */
public final int ownerUid;
/** The interface name of this network. */
@NonNull
public final String iface;
/** The names of the interfaces underlying this network. */
@NonNull
public final List<String> underlyingIfaces;
public UnderlyingNetworkInfo(int ownerUid, @NonNull String iface,
@NonNull List<String> underlyingIfaces) {
Objects.requireNonNull(iface);
Objects.requireNonNull(underlyingIfaces);
this.ownerUid = ownerUid;
this.iface = iface;
this.underlyingIfaces = underlyingIfaces;
}
private UnderlyingNetworkInfo(@NonNull Parcel in) {
this.ownerUid = in.readInt();
this.iface = in.readString();
this.underlyingIfaces = new ArrayList<>();
in.readList(this.underlyingIfaces, null /*classLoader*/);
}
@Override
public String toString() {
return "UnderlyingNetworkInfo{"
+ "ownerUid=" + ownerUid
+ ", iface='" + iface + '\''
+ ", underlyingIfaces='" + underlyingIfaces.toString() + '\''
+ '}';
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(ownerUid);
dest.writeString(iface);
dest.writeList(underlyingIfaces);
}
@NonNull
public static final Parcelable.Creator<UnderlyingNetworkInfo> CREATOR =
new Parcelable.Creator<UnderlyingNetworkInfo>() {
@NonNull
@Override
public UnderlyingNetworkInfo createFromParcel(@NonNull Parcel in) {
return new UnderlyingNetworkInfo(in);
}
@NonNull
@Override
public UnderlyingNetworkInfo[] newArray(int size) {
return new UnderlyingNetworkInfo[size];
}
};
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof UnderlyingNetworkInfo)) return false;
final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o;
return ownerUid == that.ownerUid
&& Objects.equals(iface, that.iface)
&& Objects.equals(underlyingIfaces, that.underlyingIfaces);
}
@Override
public int hashCode() {
return Objects.hash(ownerUid, iface, underlyingIfaces);
}
}

View File

@@ -1,86 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Arrays;
/**
* A lightweight container used to carry information of the ongoing VPN.
* Internal use only.
*
* @hide
*/
public class VpnInfo implements Parcelable {
public final int ownerUid;
@Nullable
public final String vpnIface;
@Nullable
public final String[] underlyingIfaces;
public VpnInfo(int ownerUid, @Nullable String vpnIface, @Nullable String[] underlyingIfaces) {
this.ownerUid = ownerUid;
this.vpnIface = vpnIface;
this.underlyingIfaces = underlyingIfaces;
}
private VpnInfo(@NonNull Parcel in) {
this.ownerUid = in.readInt();
this.vpnIface = in.readString();
this.underlyingIfaces = in.createStringArray();
}
@Override
public String toString() {
return "VpnInfo{"
+ "ownerUid=" + ownerUid
+ ", vpnIface='" + vpnIface + '\''
+ ", underlyingIfaces='" + Arrays.toString(underlyingIfaces) + '\''
+ '}';
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(ownerUid);
dest.writeString(vpnIface);
dest.writeStringArray(underlyingIfaces);
}
@NonNull
public static final Parcelable.Creator<VpnInfo> CREATOR = new Parcelable.Creator<VpnInfo>() {
@NonNull
@Override
public VpnInfo createFromParcel(@NonNull Parcel in) {
return new VpnInfo(in);
}
@NonNull
@Override
public VpnInfo[] newArray(int size) {
return new VpnInfo[size];
}
};
}

View File

@@ -132,8 +132,8 @@ import android.net.SocketKeepalive;
import android.net.TetheringManager;
import android.net.UidRange;
import android.net.UidRangeParcel;
import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
import android.net.VpnInfo;
import android.net.VpnManager;
import android.net.VpnService;
import android.net.metrics.INetdEventListener;
@@ -4854,28 +4854,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
*
* <p>Must be called on the handler thread.
*/
private VpnInfo[] getAllVpnInfo() {
private UnderlyingNetworkInfo[] getAllVpnInfo() {
ensureRunningOnConnectivityServiceThread();
synchronized (mVpns) {
if (mLockdownEnabled) {
return new VpnInfo[0];
return new UnderlyingNetworkInfo[0];
}
}
List<VpnInfo> infoList = new ArrayList<>();
List<UnderlyingNetworkInfo> infoList = new ArrayList<>();
for (NetworkAgentInfo nai : mNetworkAgentInfos) {
VpnInfo info = createVpnInfo(nai);
UnderlyingNetworkInfo info = createVpnInfo(nai);
if (info != null) {
infoList.add(info);
}
}
return infoList.toArray(new VpnInfo[infoList.size()]);
return infoList.toArray(new UnderlyingNetworkInfo[infoList.size()]);
}
/**
* @return VPN information for accounting, or null if we can't retrieve all required
* information, e.g underlying ifaces.
*/
private VpnInfo createVpnInfo(NetworkAgentInfo nai) {
private UnderlyingNetworkInfo createVpnInfo(NetworkAgentInfo nai) {
if (!nai.isVPN()) return null;
Network[] underlyingNetworks = nai.declaredUnderlyingNetworks;
@@ -4907,11 +4907,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Must be non-null or NetworkStatsService will crash.
// Cannot happen in production code because Vpn only registers the NetworkAgent after the
// tun or ipsec interface is created.
// TODO: Remove this check.
if (nai.linkProperties.getInterfaceName() == null) return null;
return new VpnInfo(nai.networkCapabilities.getOwnerUid(),
nai.linkProperties.getInterfaceName(),
interfaces.toArray(new String[0]));
return new UnderlyingNetworkInfo(nai.networkCapabilities.getOwnerUid(),
nai.linkProperties.getInterfaceName(), interfaces);
}
/**
@@ -8001,10 +8001,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
activeIface = activeLinkProperties.getInterfaceName();
}
final VpnInfo[] vpnInfos = getAllVpnInfo();
final UnderlyingNetworkInfo[] underlyingNetworkInfos = getAllVpnInfo();
try {
mStatsService.forceUpdateIfaces(
getDefaultNetworks(), getAllNetworkState(), activeIface, vpnInfos);
mStatsService.forceUpdateIfaces(getDefaultNetworks(), getAllNetworkState(), activeIface,
underlyingNetworkInfos);
} catch (Exception ignored) {
}
}
@@ -8264,6 +8264,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
return getVpnIfOwner(mDeps.getCallingUid());
}
// TODO: stop calling into Vpn.java and get this information from data in this class.
@GuardedBy("mVpns")
private Vpn getVpnIfOwner(int uid) {
final int user = UserHandle.getUserId(uid);
@@ -8272,7 +8273,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (vpn == null) {
return null;
} else {
final VpnInfo info = vpn.getVpnInfo();
final UnderlyingNetworkInfo info = vpn.getUnderlyingNetworkInfo();
return (info == null || info.ownerUid != uid) ? null : vpn;
}
}

View File

@@ -70,7 +70,7 @@ import android.net.NetworkRequest;
import android.net.RouteInfo;
import android.net.UidRange;
import android.net.UidRangeParcel;
import android.net.VpnInfo;
import android.net.UnderlyingNetworkInfo;
import android.net.VpnManager;
import android.net.VpnService;
import android.net.ipsec.ike.ChildSessionCallback;
@@ -1819,12 +1819,12 @@ public class Vpn {
* This method should not be called if underlying interfaces field is needed, because it doesn't
* have enough data to fill VpnInfo.underlyingIfaces field.
*/
public synchronized VpnInfo getVpnInfo() {
public synchronized UnderlyingNetworkInfo getUnderlyingNetworkInfo() {
if (!isRunningLocked()) {
return null;
}
return new VpnInfo(mOwnerUID, mInterface, null);
return new UnderlyingNetworkInfo(mOwnerUID, mInterface, new ArrayList<>());
}
public synchronized boolean appliesToUid(int uid) {

View File

@@ -27,7 +27,7 @@ import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
import android.annotation.Nullable;
import android.net.INetd;
import android.net.NetworkStats;
import android.net.VpnInfo;
import android.net.UnderlyingNetworkInfo;
import android.net.util.NetdService;
import android.os.RemoteException;
import android.os.StrictMode;
@@ -81,7 +81,7 @@ public class NetworkStatsFactory {
private final Object mPersistentDataLock = new Object();
/** Set containing info about active VPNs and their underlying networks. */
private volatile VpnInfo[] mVpnInfos = new VpnInfo[0];
private volatile UnderlyingNetworkInfo[] mUnderlyingNetworkInfos = new UnderlyingNetworkInfo[0];
// A persistent snapshot of cumulative stats since device start
@GuardedBy("mPersistentDataLock")
@@ -116,8 +116,8 @@ public class NetworkStatsFactory {
*
* @param vpnArray The snapshot of the currently-running VPNs.
*/
public void updateVpnInfos(VpnInfo[] vpnArray) {
mVpnInfos = vpnArray.clone();
public void updateUnderlyingNetworkInfos(UnderlyingNetworkInfo[] vpnArray) {
mUnderlyingNetworkInfos = vpnArray.clone();
}
/**
@@ -319,7 +319,7 @@ public class NetworkStatsFactory {
// code that will acquire other locks within the system server. See b/134244752.
synchronized (mPersistentDataLock) {
// Take a reference. If this gets swapped out, we still have the old reference.
final VpnInfo[] vpnArray = mVpnInfos;
final UnderlyingNetworkInfo[] vpnArray = mUnderlyingNetworkInfos;
// Take a defensive copy. mPersistSnapshot is mutated in some cases below
final NetworkStats prev = mPersistSnapshot.clone();
@@ -369,8 +369,8 @@ public class NetworkStatsFactory {
}
@GuardedBy("mPersistentDataLock")
private NetworkStats adjustForTunAnd464Xlat(
NetworkStats uidDetailStats, NetworkStats previousStats, VpnInfo[] vpnArray) {
private NetworkStats adjustForTunAnd464Xlat(NetworkStats uidDetailStats,
NetworkStats previousStats, UnderlyingNetworkInfo[] vpnArray) {
// Calculate delta from last snapshot
final NetworkStats delta = uidDetailStats.subtract(previousStats);
@@ -381,8 +381,9 @@ public class NetworkStatsFactory {
delta.apply464xlatAdjustments(mStackedIfaces);
// Migrate data usage over a VPN to the TUN network.
for (VpnInfo info : vpnArray) {
delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces);
for (UnderlyingNetworkInfo info : vpnArray) {
delta.migrateTun(info.ownerUid, info.iface,
info.underlyingIfaces.toArray(new String[0]));
// Filter out debug entries as that may lead to over counting.
delta.filterDebugEntries();
}

View File

@@ -104,8 +104,8 @@ import android.net.NetworkStats.NonMonotonicObserver;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TrafficStats;
import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
import android.net.VpnInfo;
import android.net.netstats.provider.INetworkStatsProvider;
import android.net.netstats.provider.INetworkStatsProviderCallback;
import android.net.netstats.provider.NetworkStatsProvider;
@@ -973,7 +973,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
Network[] defaultNetworks,
NetworkState[] networkStates,
String activeIface,
VpnInfo[] vpnInfos) {
UnderlyingNetworkInfo[] underlyingNetworkInfos) {
checkNetworkStackPermission(mContext);
final long token = Binder.clearCallingIdentity();
@@ -986,7 +986,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// Update the VPN underlying interfaces only after the poll is made and tun data has been
// migrated. Otherwise the migration would use the new interfaces instead of the ones that
// were current when the polled data was transferred.
mStatsFactory.updateVpnInfos(vpnInfos);
mStatsFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
}
@Override

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net
import android.os.Build
import androidx.test.filters.SmallTest
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.assertParcelSane
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.test.assertEquals
private const val TEST_OWNER_UID = 123
private const val TEST_IFACE = "test_tun0"
private val TEST_IFACE_LIST = listOf("wlan0", "rmnet_data0", "eth0")
@SmallTest
@RunWith(DevSdkIgnoreRunner::class)
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
class UnderlyingNetworkInfoTest {
@Test
fun testParcelUnparcel() {
val testInfo = UnderlyingNetworkInfo(TEST_OWNER_UID, TEST_IFACE, TEST_IFACE_LIST)
assertEquals(TEST_OWNER_UID, testInfo.ownerUid)
assertEquals(TEST_IFACE, testInfo.iface)
assertEquals(TEST_IFACE_LIST, testInfo.underlyingIfaces)
assertParcelSane(testInfo, 3)
val emptyInfo = UnderlyingNetworkInfo(0, String(), listOf())
assertEquals(0, emptyInfo.ownerUid)
assertEquals(String(), emptyInfo.iface)
assertEquals(listOf(), emptyInfo.underlyingIfaces)
assertParcelSane(emptyInfo, 3)
}
}

View File

@@ -201,8 +201,8 @@ import android.net.RouteInfoParcel;
import android.net.SocketKeepalive;
import android.net.UidRange;
import android.net.UidRangeParcel;
import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
import android.net.VpnInfo;
import android.net.VpnManager;
import android.net.metrics.IpConnectivityLog;
import android.net.shared.NetworkMonitorUtils;
@@ -1076,7 +1076,7 @@ public class ConnectivityServiceTest {
private boolean mAgentRegistered = false;
private int mVpnType = VpnManager.TYPE_VPN_SERVICE;
private VpnInfo mVpnInfo;
private UnderlyingNetworkInfo mUnderlyingNetworkInfo;
// These ConditionVariables allow tests to wait for LegacyVpnRunner to be stopped/started.
// TODO: this scheme is ad-hoc and error-prone because it does not fail if, for example, the
@@ -1250,14 +1250,15 @@ public class ConnectivityServiceTest {
}
@Override
public synchronized VpnInfo getVpnInfo() {
if (mVpnInfo != null) return mVpnInfo;
public synchronized UnderlyingNetworkInfo getUnderlyingNetworkInfo() {
if (mUnderlyingNetworkInfo != null) return mUnderlyingNetworkInfo;
return super.getVpnInfo();
return super.getUnderlyingNetworkInfo();
}
private synchronized void setVpnInfo(VpnInfo vpnInfo) {
mVpnInfo = vpnInfo;
private synchronized void setUnderlyingNetworkInfo(
UnderlyingNetworkInfo underlyingNetworkInfo) {
mUnderlyingNetworkInfo = underlyingNetworkInfo;
}
}
@@ -5199,20 +5200,22 @@ public class ConnectivityServiceTest {
private void expectForceUpdateIfaces(Network[] networks, String defaultIface,
Integer vpnUid, String vpnIfname, String[] underlyingIfaces) throws Exception {
ArgumentCaptor<Network[]> networksCaptor = ArgumentCaptor.forClass(Network[].class);
ArgumentCaptor<VpnInfo[]> vpnInfosCaptor = ArgumentCaptor.forClass(VpnInfo[].class);
ArgumentCaptor<UnderlyingNetworkInfo[]> vpnInfosCaptor = ArgumentCaptor.forClass(
UnderlyingNetworkInfo[].class);
verify(mStatsService, atLeastOnce()).forceUpdateIfaces(networksCaptor.capture(),
any(NetworkState[].class), eq(defaultIface), vpnInfosCaptor.capture());
assertSameElementsNoDuplicates(networksCaptor.getValue(), networks);
VpnInfo[] infos = vpnInfosCaptor.getValue();
UnderlyingNetworkInfo[] infos = vpnInfosCaptor.getValue();
if (vpnUid != null) {
assertEquals("Should have exactly one VPN:", 1, infos.length);
VpnInfo info = infos[0];
UnderlyingNetworkInfo info = infos[0];
assertEquals("Unexpected VPN owner:", (int) vpnUid, info.ownerUid);
assertEquals("Unexpected VPN interface:", vpnIfname, info.vpnIface);
assertSameElementsNoDuplicates(underlyingIfaces, info.underlyingIfaces);
assertEquals("Unexpected VPN interface:", vpnIfname, info.iface);
assertSameElementsNoDuplicates(underlyingIfaces,
info.underlyingIfaces.toArray(new String[0]));
} else {
assertEquals(0, infos.length);
return;
@@ -5273,7 +5276,7 @@ public class ConnectivityServiceTest {
waitForIdle();
verify(mStatsService, never())
.forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
eq(new VpnInfo[0]));
eq(new UnderlyingNetworkInfo[0]));
reset(mStatsService);
// Roaming change should update ifaces
@@ -5356,8 +5359,8 @@ public class ConnectivityServiceTest {
// network for the VPN...
verify(mStatsService, never()).forceUpdateIfaces(any(Network[].class),
any(NetworkState[].class), any() /* anyString() doesn't match null */,
argThat(infos -> infos[0].underlyingIfaces.length == 1
&& WIFI_IFNAME.equals(infos[0].underlyingIfaces[0])));
argThat(infos -> infos[0].underlyingIfaces.size() == 1
&& WIFI_IFNAME.equals(infos[0].underlyingIfaces.get(0))));
verifyNoMoreInteractions(mStatsService);
reset(mStatsService);
@@ -5370,8 +5373,8 @@ public class ConnectivityServiceTest {
waitForIdle();
verify(mStatsService).forceUpdateIfaces(any(Network[].class),
any(NetworkState[].class), any() /* anyString() doesn't match null */,
argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.length == 1
&& WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces[0])));
argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.size() == 1
&& WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces.get(0))));
mEthernetNetworkAgent.disconnect();
waitForIdle();
reset(mStatsService);
@@ -8351,8 +8354,9 @@ public class ConnectivityServiceTest {
assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
mMockVpn.setVpnType(vpnType);
final VpnInfo vpnInfo = new VpnInfo(vpnOwnerUid, null, null);
mMockVpn.setVpnInfo(vpnInfo);
final UnderlyingNetworkInfo underlyingNetworkInfo =
new UnderlyingNetworkInfo(vpnOwnerUid, VPN_IFNAME, new ArrayList<String>());
mMockVpn.setUnderlyingNetworkInfo(underlyingNetworkInfo);
}
private void setupConnectionOwnerUidAsVpnApp(int vpnOwnerUid, @VpnManager.VpnType int vpnType)

View File

@@ -33,7 +33,9 @@ import static android.net.NetworkStats.TAG_NONE;
import static org.junit.Assert.assertEquals;
import android.net.NetworkStats;
import android.net.VpnInfo;
import android.net.UnderlyingNetworkInfo;
import java.util.Arrays;
/** Superclass with utilities for NetworkStats(Service|Factory)Test */
abstract class NetworkStatsBaseTest {
@@ -107,11 +109,11 @@ abstract class NetworkStatsBaseTest {
assertEquals("unexpected operations", operations, entry.operations);
}
static VpnInfo createVpnInfo(String[] underlyingIfaces) {
static UnderlyingNetworkInfo createVpnInfo(String[] underlyingIfaces) {
return createVpnInfo(TUN_IFACE, underlyingIfaces);
}
static VpnInfo createVpnInfo(String vpnIface, String[] underlyingIfaces) {
return new VpnInfo(UID_VPN, vpnIface, underlyingIfaces);
static UnderlyingNetworkInfo createVpnInfo(String vpnIface, String[] underlyingIfaces) {
return new UnderlyingNetworkInfo(UID_VPN, vpnIface, Arrays.asList(underlyingIfaces));
}
}

View File

@@ -36,7 +36,7 @@ import static org.junit.Assert.fail;
import android.content.res.Resources;
import android.net.NetworkStats;
import android.net.TrafficStats;
import android.net.VpnInfo;
import android.net.UnderlyingNetworkInfo;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -79,7 +79,7 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
// related to networkStatsFactory is compiled to a minimal native library and loaded here.
System.loadLibrary("networkstatsfactorytestjni");
mFactory = new NetworkStatsFactory(mTestProc, false);
mFactory.updateVpnInfos(new VpnInfo[0]);
mFactory.updateUnderlyingNetworkInfos(new UnderlyingNetworkInfo[0]);
}
@After
@@ -105,8 +105,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
@Test
public void testVpnRewriteTrafficThroughItself() throws Exception {
VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
mFactory.updateVpnInfos(vpnInfos);
UnderlyingNetworkInfo[] underlyingNetworkInfos =
new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -134,8 +135,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
@Test
public void testVpnWithClat() throws Exception {
VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {CLAT_PREFIX + TEST_IFACE})};
mFactory.updateVpnInfos(vpnInfos);
final UnderlyingNetworkInfo[] underlyingNetworkInfos = new UnderlyingNetworkInfo[] {
createVpnInfo(new String[] {CLAT_PREFIX + TEST_IFACE})};
mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
mFactory.noteStackedIface(CLAT_PREFIX + TEST_IFACE, TEST_IFACE);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
@@ -167,8 +169,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
@Test
public void testVpnWithOneUnderlyingIface() throws Exception {
VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
mFactory.updateVpnInfos(vpnInfos);
final UnderlyingNetworkInfo[] underlyingNetworkInfos =
new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -191,8 +194,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
@Test
public void testVpnWithOneUnderlyingIfaceAndOwnTraffic() throws Exception {
// WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
mFactory.updateVpnInfos(vpnInfos);
final UnderlyingNetworkInfo[] underlyingNetworkInfos =
new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -219,8 +223,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
@Test
public void testVpnWithOneUnderlyingIface_withCompression() throws Exception {
// WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
mFactory.updateVpnInfos(vpnInfos);
final UnderlyingNetworkInfo[] underlyingNetworkInfos =
new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -242,8 +247,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
// WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
// Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
// Additionally, VPN is duplicating traffic across both WiFi and Cell.
VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
mFactory.updateVpnInfos(vpnInfos);
final UnderlyingNetworkInfo[] underlyingNetworkInfos =
new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -267,10 +273,10 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
public void testConcurrentVpns() throws Exception {
// Assume two VPNs are connected on two different network interfaces. VPN1 is using
// TEST_IFACE and VPN2 is using TEST_IFACE2.
final VpnInfo[] vpnInfos = new VpnInfo[] {
final UnderlyingNetworkInfo[] underlyingNetworkInfos = new UnderlyingNetworkInfo[] {
createVpnInfo(TUN_IFACE, new String[] {TEST_IFACE}),
createVpnInfo(TUN_IFACE2, new String[] {TEST_IFACE2})};
mFactory.updateVpnInfos(vpnInfos);
mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -308,8 +314,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
// WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
// Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
// Additionally, VPN is arbitrarily splitting traffic across WiFi and Cell.
VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
mFactory.updateVpnInfos(vpnInfos);
final UnderlyingNetworkInfo[] underlyingNetworkInfos =
new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -335,8 +342,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
// WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
// Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
// Additionally, VPN is arbitrarily splitting compressed traffic across WiFi and Cell.
VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
mFactory.updateVpnInfos(vpnInfos);
final UnderlyingNetworkInfo[] underlyingNetworkInfos =
new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface:
// 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
@@ -357,8 +365,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
public void testVpnWithIncorrectUnderlyingIface() throws Exception {
// WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2),
// but has declared only WiFi (TEST_IFACE) in its underlying network set.
VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
mFactory.updateVpnInfos(vpnInfos);
final UnderlyingNetworkInfo[] underlyingNetworkInfos =
new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):

View File

@@ -86,7 +86,7 @@ import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.VpnInfo;
import android.net.UnderlyingNetworkInfo;
import android.net.netstats.provider.INetworkStatsProviderCallback;
import android.os.ConditionVariable;
import android.os.Handler;
@@ -286,7 +286,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -328,7 +329,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -401,7 +403,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// modify some number on wifi, and trigger poll event
incrementCurrentTime(2 * HOUR_IN_MILLIS);
@@ -441,7 +444,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// create some traffic on first network
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -475,7 +479,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
.insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
forcePollAndWaitForIdle();
@@ -514,7 +519,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -581,7 +587,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
new VpnInfo[0]);
new UnderlyingNetworkInfo[0]);
// Create some traffic.
incrementCurrentTime(MINUTE_IN_MILLIS);
@@ -655,7 +661,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// create some traffic for two apps
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -713,7 +720,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
NetworkStats.Entry entry1 = new NetworkStats.Entry(
TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L);
@@ -756,7 +764,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
NetworkStats.Entry uidStats = new NetworkStats.Entry(
TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
@@ -810,7 +819,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// create some initial traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -867,7 +877,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// create some initial traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -906,7 +917,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// Create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -943,7 +955,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// create some tethering traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -999,7 +1012,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -1104,7 +1118,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
mService.registerNetworkStatsProvider("TEST", provider);
assertNotNull(cb);
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// Verifies that one requestStatsUpdate will be called during iface update.
provider.expectOnRequestStatsUpdate(0 /* unused */);
@@ -1155,7 +1170,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
NetworkState[] states =
new NetworkState[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// Register custom provider and retrieve callback.
final TestableNetworkStatsProviderBinder provider =
@@ -1204,7 +1220,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
// 3G network comes online.
setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
new VpnInfo[0]);
new UnderlyingNetworkInfo[0]);
// Create some traffic.
incrementCurrentTime(MINUTE_IN_MILLIS);
@@ -1274,7 +1290,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
NetworkState[] states = new NetworkState[]{
buildWifiState(true /*isMetered*/, TEST_IFACE2), buildMobile3gState(IMSI_1)};
expectNetworkStatsUidDetail(buildEmptyStats());
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// Create some traffic on mobile network.
incrementCurrentTime(HOUR_IN_MILLIS);