Merge changes I5ce7fe05,I2d5dc5b9,Ibcc4bdc0

* changes:
  Add additional dump information for UnderlyingNetworkTracker
  Copy up/downstream bandwidth and TCP buffer sizes from underlying
  Prevent concurrent modification exceptions in VcnManagementService
This commit is contained in:
Benedict Wong
2021-05-26 19:13:42 +00:00
committed by Gerrit Code Review
7 changed files with 137 additions and 60 deletions

View File

@@ -148,6 +148,7 @@ import java.util.concurrent.TimeUnit;
// TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity // TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity
public class VcnManagementService extends IVcnManagementService.Stub { public class VcnManagementService extends IVcnManagementService.Stub {
@NonNull private static final String TAG = VcnManagementService.class.getSimpleName(); @NonNull private static final String TAG = VcnManagementService.class.getSimpleName();
private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5);
public static final boolean VDBG = false; // STOPSHIP: if true public static final boolean VDBG = false; // STOPSHIP: if true
@@ -999,48 +1000,38 @@ public class VcnManagementService extends IVcnManagementService.Stub {
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
mContext.enforceCallingOrSelfPermission(DUMP, TAG); mContext.enforceCallingOrSelfPermission(DUMP, TAG);
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "| ");
pw.println("VcnManagementService dump:"); // Post to handler thread to prevent ConcurrentModificationExceptions, and avoid lock-hell.
pw.increaseIndent(); mHandler.runWithScissors(() -> {
mNetworkProvider.dump(pw);
pw.println("mNetworkProvider:");
pw.increaseIndent();
mNetworkProvider.dump(pw);
pw.decreaseIndent();
pw.println();
pw.println("mTrackingNetworkCallback:");
pw.increaseIndent();
mTrackingNetworkCallback.dump(pw);
pw.decreaseIndent();
pw.println();
synchronized (mLock) {
pw.println("mLastSnapshot:");
pw.increaseIndent();
mLastSnapshot.dump(pw);
pw.decreaseIndent();
pw.println(); pw.println();
pw.println("mConfigs:"); mTrackingNetworkCallback.dump(pw);
pw.increaseIndent(); pw.println();
for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
pw.println(entry.getKey() + ": " + entry.getValue().getProvisioningPackageName()); synchronized (mLock) {
mLastSnapshot.dump(pw);
pw.println();
pw.println("mConfigs:");
pw.increaseIndent();
for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
pw.println(entry.getKey() + ": "
+ entry.getValue().getProvisioningPackageName());
}
pw.decreaseIndent();
pw.println();
pw.println("mVcns:");
pw.increaseIndent();
for (Vcn vcn : mVcns.values()) {
vcn.dump(pw);
}
pw.decreaseIndent();
pw.println();
} }
pw.decreaseIndent(); }, DUMP_TIMEOUT_MILLIS);
pw.println();
pw.println("mVcns:");
pw.increaseIndent();
for (Vcn vcn : mVcns.values()) {
vcn.dump(pw);
}
pw.decreaseIndent();
pw.println();
}
pw.decreaseIndent();
} }
// TODO(b/180452282): Make name more generic and implement directly with VcnManagementService // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService

View File

@@ -40,6 +40,7 @@ import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.Slog; import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.annotations.VisibleForTesting.Visibility;
@@ -106,6 +107,17 @@ public class UnderlyingNetworkTracker {
@VisibleForTesting(visibility = Visibility.PRIVATE) @VisibleForTesting(visibility = Visibility.PRIVATE)
static final int PRIORITY_ANY = Integer.MAX_VALUE; static final int PRIORITY_ANY = Integer.MAX_VALUE;
private static final SparseArray<String> PRIORITY_TO_STRING_MAP = new SparseArray<>();
static {
PRIORITY_TO_STRING_MAP.put(
PRIORITY_OPPORTUNISTIC_CELLULAR, "PRIORITY_OPPORTUNISTIC_CELLULAR");
PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_IN_USE, "PRIORITY_WIFI_IN_USE");
PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_PROSPECTIVE, "PRIORITY_WIFI_PROSPECTIVE");
PRIORITY_TO_STRING_MAP.put(PRIORITY_MACRO_CELLULAR, "PRIORITY_MACRO_CELLULAR");
PRIORITY_TO_STRING_MAP.put(PRIORITY_ANY, "PRIORITY_ANY");
}
@NonNull private final VcnContext mVcnContext; @NonNull private final VcnContext mVcnContext;
@NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final ParcelUuid mSubscriptionGroup;
@NonNull private final UnderlyingNetworkTrackerCallback mCb; @NonNull private final UnderlyingNetworkTrackerCallback mCb;
@@ -395,12 +407,12 @@ public class UnderlyingNetworkTracker {
} }
private void reevaluateNetworks() { private void reevaluateNetworks() {
TreeSet<UnderlyingNetworkRecord> sorted = if (mRouteSelectionCallback == null) {
new TreeSet<>( return; // UnderlyingNetworkTracker has quit.
UnderlyingNetworkRecord.getComparator( }
mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig));
sorted.addAll(mRouteSelectionCallback.getUnderlyingNetworks());
TreeSet<UnderlyingNetworkRecord> sorted =
mRouteSelectionCallback.getSortedUnderlyingNetworks();
UnderlyingNetworkRecord candidate = sorted.isEmpty() ? null : sorted.first(); UnderlyingNetworkRecord candidate = sorted.isEmpty() ? null : sorted.first();
if (Objects.equals(mCurrentRecord, candidate)) { if (Objects.equals(mCurrentRecord, candidate)) {
return; return;
@@ -446,17 +458,23 @@ public class UnderlyingNetworkTracker {
private final Map<Network, UnderlyingNetworkRecord.Builder> private final Map<Network, UnderlyingNetworkRecord.Builder>
mUnderlyingNetworkRecordBuilders = new ArrayMap<>(); mUnderlyingNetworkRecordBuilders = new ArrayMap<>();
private List<UnderlyingNetworkRecord> getUnderlyingNetworks() { private TreeSet<UnderlyingNetworkRecord> getSortedUnderlyingNetworks() {
final List<UnderlyingNetworkRecord> records = new ArrayList<>(); TreeSet<UnderlyingNetworkRecord> sorted =
new TreeSet<>(
UnderlyingNetworkRecord.getComparator(
mSubscriptionGroup,
mLastSnapshot,
mCurrentRecord,
mCarrierConfig));
for (UnderlyingNetworkRecord.Builder builder : for (UnderlyingNetworkRecord.Builder builder :
mUnderlyingNetworkRecordBuilders.values()) { mUnderlyingNetworkRecordBuilders.values()) {
if (builder.isValid()) { if (builder.isValid()) {
records.add(builder.build()); sorted.add(builder.build());
} }
} }
return records; return sorted;
} }
@Override @Override
@@ -660,10 +678,21 @@ public class UnderlyingNetworkTracker {
} }
/** Dumps the state of this record for logging and debugging purposes. */ /** Dumps the state of this record for logging and debugging purposes. */
public void dump(IndentingPrintWriter pw) { private void dump(
IndentingPrintWriter pw,
ParcelUuid subscriptionGroup,
TelephonySubscriptionSnapshot snapshot,
UnderlyingNetworkRecord currentlySelected,
PersistableBundle carrierConfig) {
pw.println("UnderlyingNetworkRecord:"); pw.println("UnderlyingNetworkRecord:");
pw.increaseIndent(); pw.increaseIndent();
final int priorityClass =
calculatePriorityClass(
subscriptionGroup, snapshot, currentlySelected, carrierConfig);
pw.println(
"Priority class: " + PRIORITY_TO_STRING_MAP.get(priorityClass) + " ("
+ priorityClass + ")");
pw.println("mNetwork: " + network); pw.println("mNetwork: " + network);
pw.println("mNetworkCapabilities: " + networkCapabilities); pw.println("mNetworkCapabilities: " + networkCapabilities);
pw.println("mLinkProperties: " + linkProperties); pw.println("mLinkProperties: " + linkProperties);
@@ -733,6 +762,30 @@ public class UnderlyingNetworkTracker {
} }
} }
/** Dumps the state of this record for logging and debugging purposes. */
public void dump(IndentingPrintWriter pw) {
pw.println("UnderlyingNetworkTracker:");
pw.increaseIndent();
pw.println("Carrier WiFi Entry Threshold: " + getWifiEntryRssiThreshold(mCarrierConfig));
pw.println("Carrier WiFi Exit Threshold: " + getWifiExitRssiThreshold(mCarrierConfig));
pw.println(
"Currently selected: " + (mCurrentRecord == null ? null : mCurrentRecord.network));
pw.println("Underlying networks:");
pw.increaseIndent();
if (mRouteSelectionCallback != null) {
for (UnderlyingNetworkRecord record :
mRouteSelectionCallback.getSortedUnderlyingNetworks()) {
record.dump(pw, mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig);
}
}
pw.decreaseIndent();
pw.println();
pw.decreaseIndent();
}
private class VcnActiveDataSubscriptionIdListener extends TelephonyCallback private class VcnActiveDataSubscriptionIdListener extends TelephonyCallback
implements ActiveDataSubscriptionIdListener { implements ActiveDataSubscriptionIdListener {
@Override @Override

View File

@@ -557,11 +557,14 @@ public class Vcn extends Handler {
pw.println("mCurrentStatus: " + mCurrentStatus); pw.println("mCurrentStatus: " + mCurrentStatus);
pw.println("mIsMobileDataEnabled: " + mIsMobileDataEnabled); pw.println("mIsMobileDataEnabled: " + mIsMobileDataEnabled);
pw.println();
pw.println("mVcnGatewayConnections:"); pw.println("mVcnGatewayConnections:");
pw.increaseIndent();
for (VcnGatewayConnection gw : mVcnGatewayConnections.values()) { for (VcnGatewayConnection gw : mVcnGatewayConnections.values()) {
gw.dump(pw); gw.dump(pw);
} }
pw.decreaseIndent();
pw.println(); pw.println();
pw.decreaseIndent(); pw.decreaseIndent();

View File

@@ -1969,6 +1969,9 @@ public class VcnGatewayConnection extends StateMachine {
} }
builder.setAdministratorUids(adminUids); builder.setAdministratorUids(adminUids);
builder.setLinkUpstreamBandwidthKbps(underlyingCaps.getLinkUpstreamBandwidthKbps());
builder.setLinkDownstreamBandwidthKbps(underlyingCaps.getLinkDownstreamBandwidthKbps());
// Set TransportInfo for SysUI use (never parcelled out of SystemServer). // Set TransportInfo for SysUI use (never parcelled out of SystemServer).
if (underlyingCaps.hasTransport(TRANSPORT_WIFI) if (underlyingCaps.hasTransport(TRANSPORT_WIFI)
&& underlyingCaps.getTransportInfo() instanceof WifiInfo) { && underlyingCaps.getTransportInfo() instanceof WifiInfo) {
@@ -1985,6 +1988,11 @@ public class VcnGatewayConnection extends StateMachine {
"Unknown transport type or missing TransportInfo/NetworkSpecifier for" "Unknown transport type or missing TransportInfo/NetworkSpecifier for"
+ " non-null underlying network"); + " non-null underlying network");
} }
} else {
Slog.wtf(
TAG,
"No underlying network while building network capabilities",
new IllegalStateException());
} }
return builder.build(); return builder.build();
@@ -2012,7 +2020,18 @@ public class VcnGatewayConnection extends StateMachine {
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/, lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/,
null /*iface*/, RouteInfo.RTN_UNICAST)); null /*iface*/, RouteInfo.RTN_UNICAST));
final int underlyingMtu = (underlying == null) ? 0 : underlying.linkProperties.getMtu(); int underlyingMtu = 0;
if (underlying != null) {
final LinkProperties underlyingLp = underlying.linkProperties;
lp.setTcpBufferSizes(underlyingLp.getTcpBufferSizes());
underlyingMtu = underlyingLp.getMtu();
} else {
Slog.wtf(
TAG,
"No underlying network while building link properties",
new IllegalStateException());
}
lp.setMtu( lp.setMtu(
MtuUtils.getMtu( MtuUtils.getMtu(
ikeTunnelParams.getTunnelModeChildSessionParams().getSaProposals(), ikeTunnelParams.getTunnelModeChildSessionParams().getSaProposals(),
@@ -2168,15 +2187,9 @@ public class VcnGatewayConnection extends StateMachine {
pw.println( pw.println(
"mNetworkAgent.getNetwork(): " "mNetworkAgent.getNetwork(): "
+ (mNetworkAgent == null ? null : mNetworkAgent.getNetwork())); + (mNetworkAgent == null ? null : mNetworkAgent.getNetwork()));
pw.println();
pw.println("mUnderlying:"); mUnderlyingNetworkTracker.dump(pw);
pw.increaseIndent();
if (mUnderlying != null) {
mUnderlying.dump(pw);
} else {
pw.println("null");
}
pw.decreaseIndent();
pw.println(); pw.println();
pw.decreaseIndent(); pw.decreaseIndent();

View File

@@ -200,6 +200,9 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
public void testMigration() throws Exception { public void testMigration() throws Exception {
triggerChildOpened(); triggerChildOpened();
mGatewayConnection
.getUnderlyingNetworkTrackerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
getChildSessionCallback() getChildSessionCallback()
.onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform()); .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
mTestLooper.dispatchAll(); mTestLooper.dispatchAll();
@@ -207,7 +210,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
verify(mIpSecSvc, times(2)) verify(mIpSecSvc, times(2))
.setNetworkForTunnelInterface( .setNetworkForTunnelInterface(
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_IPSEC_TUNNEL_RESOURCE_ID),
eq(TEST_UNDERLYING_NETWORK_RECORD_1.network), eq(TEST_UNDERLYING_NETWORK_RECORD_2.network),
any()); any());
for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) { for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
@@ -226,8 +229,10 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
MtuUtils.getMtu( MtuUtils.getMtu(
saProposals, saProposals,
mConfig.getMaxMtu(), mConfig.getMaxMtu(),
TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.getMtu()); TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.getMtu());
verify(mNetworkAgent).sendLinkProperties(argThat(lp -> expectedMtu == lp.getMtu())); verify(mNetworkAgent).sendLinkProperties(
argThat(lp -> expectedMtu == lp.getMtu()
&& TEST_TCP_BUFFER_SIZES_2.equals(lp.getTcpBufferSizes())));
} }
private void triggerChildOpened() { private void triggerChildOpened() {
@@ -297,6 +302,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
final LinkProperties lp = lpCaptor.getValue(); final LinkProperties lp = lpCaptor.getValue();
assertEquals(Collections.singletonList(TEST_INTERNAL_ADDR), lp.getLinkAddresses()); assertEquals(Collections.singletonList(TEST_INTERNAL_ADDR), lp.getLinkAddresses());
assertEquals(Collections.singletonList(TEST_DNS_ADDR), lp.getDnsServers()); assertEquals(Collections.singletonList(TEST_DNS_ADDR), lp.getDnsServers());
assertEquals(TEST_TCP_BUFFER_SIZES_1, lp.getTcpBufferSizes());
final NetworkCapabilities nc = ncCaptor.getValue(); final NetworkCapabilities nc = ncCaptor.getValue();
assertTrue(nc.hasTransport(TRANSPORT_CELLULAR)); assertTrue(nc.hasTransport(TRANSPORT_CELLULAR));

View File

@@ -74,6 +74,9 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class); private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class);
private static final Map<Integer, ParcelUuid> TEST_SUBID_TO_GROUP_MAP; private static final Map<Integer, ParcelUuid> TEST_SUBID_TO_GROUP_MAP;
private static final int TEST_UPSTREAM_BANDWIDTH = 1234;
private static final int TEST_DOWNSTREAM_BANDWIDTH = 2345;
static { static {
final Map<Integer, ParcelUuid> subIdToGroupMap = new HashMap<>(); final Map<Integer, ParcelUuid> subIdToGroupMap = new HashMap<>();
subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID); subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID);
@@ -106,6 +109,8 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
capBuilder.setNetworkSpecifier( capBuilder.setNetworkSpecifier(
new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_1)); new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_1));
} }
capBuilder.setLinkUpstreamBandwidthKbps(TEST_UPSTREAM_BANDWIDTH);
capBuilder.setLinkDownstreamBandwidthKbps(TEST_DOWNSTREAM_BANDWIDTH);
capBuilder.setAdministratorUids(new int[] {TEST_UID}); capBuilder.setAdministratorUids(new int[] {TEST_UID});
UnderlyingNetworkRecord record = new UnderlyingNetworkRecord( UnderlyingNetworkRecord record = new UnderlyingNetworkRecord(
mock(Network.class, CALLS_REAL_METHODS), mock(Network.class, CALLS_REAL_METHODS),
@@ -130,6 +135,8 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids()); assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids());
assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo); assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo);
assertEquals(TEST_UPSTREAM_BANDWIDTH, vcnCaps.getLinkUpstreamBandwidthKbps());
assertEquals(TEST_DOWNSTREAM_BANDWIDTH, vcnCaps.getLinkDownstreamBandwidthKbps());
final VcnTransportInfo info = (VcnTransportInfo) vcnCaps.getTransportInfo(); final VcnTransportInfo info = (VcnTransportInfo) vcnCaps.getTransportInfo();
if (transportType == TRANSPORT_WIFI) { if (transportType == TRANSPORT_WIFI) {

View File

@@ -99,6 +99,7 @@ public class VcnGatewayConnectionTestBase {
protected static final long ELAPSED_REAL_TIME = 123456789L; protected static final long ELAPSED_REAL_TIME = 123456789L;
protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE"; protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
protected static final String TEST_TCP_BUFFER_SIZES_1 = "1,2,3,4";
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 = protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
new UnderlyingNetworkRecord( new UnderlyingNetworkRecord(
mock(Network.class, CALLS_REAL_METHODS), mock(Network.class, CALLS_REAL_METHODS),
@@ -108,8 +109,10 @@ public class VcnGatewayConnectionTestBase {
static { static {
TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setMtu(1500); TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setMtu(1500);
TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES_1);
} }
protected static final String TEST_TCP_BUFFER_SIZES_2 = "2,3,4,5";
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 = protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
new UnderlyingNetworkRecord( new UnderlyingNetworkRecord(
mock(Network.class, CALLS_REAL_METHODS), mock(Network.class, CALLS_REAL_METHODS),
@@ -119,6 +122,7 @@ public class VcnGatewayConnectionTestBase {
static { static {
TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setMtu(1460); TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setMtu(1460);
TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES_2);
} }
protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT = protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT =