Merge "Address nit from aosp/1301317"
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ad07e7c..6b71360 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -48,6 +48,7 @@
import android.os.Message;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -4735,4 +4736,28 @@
Log.d(TAG, "StackLog:" + sb.toString());
}
}
+
+ /**
+ * Simulates a Data Stall for the specified Network.
+ *
+ * <p>The caller must be the owner of the specified Network.
+ *
+ * @param detectionMethod The detection method used to identify the Data Stall.
+ * @param timestampMillis The timestamp at which the stall 'occurred', in milliseconds.
+ * @param network The Network for which a Data Stall is being simluated.
+ * @param extras The PersistableBundle of extras included in the Data Stall notification.
+ * @throws SecurityException if the caller is not the owner of the given network.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_TEST_NETWORKS,
+ android.Manifest.permission.NETWORK_STACK})
+ public void simulateDataStall(int detectionMethod, long timestampMillis,
+ @NonNull Network network, @NonNull PersistableBundle extras) {
+ try {
+ mService.simulateDataStall(detectionMethod, timestampMillis, network, extras);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index b0f79bc..d7f178c 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -18,6 +18,7 @@
import android.app.PendingIntent;
import android.net.ConnectionInfo;
+import android.net.ConnectivityDiagnosticsManager;
import android.net.IConnectivityDiagnosticsCallback;
import android.net.LinkProperties;
import android.net.Network;
@@ -33,6 +34,7 @@
import android.os.IBinder;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import android.os.ResultReceiver;
import com.android.internal.net.LegacyVpnInfo;
@@ -228,4 +230,7 @@
void unregisterConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback);
IBinder startOrGetTestNetworkService();
+
+ void simulateDataStall(int detectionMethod, long timestampMillis, in Network network,
+ in PersistableBundle extras);
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 74eced7..57d5d03 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -677,16 +677,27 @@
* restrictions.
* @hide
*/
- public void restrictCapabilitesForTestNetwork() {
+ public void restrictCapabilitesForTestNetwork(int creatorUid) {
final long originalCapabilities = mNetworkCapabilities;
final NetworkSpecifier originalSpecifier = mNetworkSpecifier;
final int originalSignalStrength = mSignalStrength;
+ final int originalOwnerUid = getOwnerUid();
+ final int[] originalAdministratorUids = getAdministratorUids();
clearAll();
// Reset the transports to only contain TRANSPORT_TEST.
mTransportTypes = (1 << TRANSPORT_TEST);
mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES;
mNetworkSpecifier = originalSpecifier;
mSignalStrength = originalSignalStrength;
+
+ // Only retain the owner and administrator UIDs if they match the app registering the remote
+ // caller that registered the network.
+ if (originalOwnerUid == creatorUid) {
+ setOwnerUid(creatorUid);
+ }
+ if (ArrayUtils.contains(originalAdministratorUids, creatorUid)) {
+ setAdministratorUids(new int[] {creatorUid});
+ }
}
/**
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 08aab2a..635f184 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2732,7 +2732,7 @@
// the Messenger, but if this ever changes, not making a defensive copy
// here will give attack vectors to clients using this code path.
networkCapabilities = new NetworkCapabilities(networkCapabilities);
- networkCapabilities.restrictCapabilitesForTestNetwork();
+ networkCapabilities.restrictCapabilitesForTestNetwork(nai.creatorUid);
}
updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
break;
@@ -3079,10 +3079,6 @@
@Override
public void notifyDataStallSuspected(DataStallReportParcelable p) {
- final Message msg = mConnectivityDiagnosticsHandler.obtainMessage(
- ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED,
- p.detectionMethod, mNetId, p.timestampMillis);
-
final PersistableBundle extras = new PersistableBundle();
switch (p.detectionMethod) {
case DETECTION_METHOD_DNS_EVENTS:
@@ -3097,12 +3093,9 @@
log("Unknown data stall detection method, ignoring: " + p.detectionMethod);
return;
}
- msg.setData(new Bundle(extras));
- // NetworkStateTrackerHandler currently doesn't take any actions based on data
- // stalls so send the message directly to ConnectivityDiagnosticsHandler and avoid
- // the cost of going through two handlers.
- mConnectivityDiagnosticsHandler.sendMessage(msg);
+ proxyDataStallToConnectivityDiagnosticsHandler(
+ p.detectionMethod, mNetId, p.timestampMillis, extras);
}
@Override
@@ -3116,6 +3109,19 @@
}
}
+ private void proxyDataStallToConnectivityDiagnosticsHandler(int detectionMethod, int netId,
+ long timestampMillis, @NonNull PersistableBundle extras) {
+ final Message msg = mConnectivityDiagnosticsHandler.obtainMessage(
+ ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED,
+ detectionMethod, netId, timestampMillis);
+ msg.setData(new Bundle(extras));
+
+ // NetworkStateTrackerHandler currently doesn't take any actions based on data
+ // stalls so send the message directly to ConnectivityDiagnosticsHandler and avoid
+ // the cost of going through two handlers.
+ mConnectivityDiagnosticsHandler.sendMessage(msg);
+ }
+
private boolean networkRequiresPrivateDnsValidation(NetworkAgentInfo nai) {
return isPrivateDnsValidationRequired(nai.networkCapabilities);
}
@@ -5855,7 +5861,7 @@
// the call to mixInCapabilities below anyway, but sanitizing here means the NAI never
// sees capabilities that may be malicious, which might prevent mistakes in the future.
networkCapabilities = new NetworkCapabilities(networkCapabilities);
- networkCapabilities.restrictCapabilitesForTestNetwork();
+ networkCapabilities.restrictCapabilitesForTestNetwork(Binder.getCallingUid());
} else {
enforceNetworkFactoryPermission();
}
@@ -5868,7 +5874,7 @@
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
- this, mNetd, mDnsResolver, mNMS, providerId);
+ this, mNetd, mDnsResolver, mNMS, providerId, Binder.getCallingUid());
// Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
@@ -5969,7 +5975,8 @@
// Start or stop DNS64 detection and 464xlat according to network state.
networkAgent.clatd.update();
notifyIfacesChangedForNetworkStats();
- networkAgent.networkMonitor().notifyLinkPropertiesChanged(newLp);
+ networkAgent.networkMonitor().notifyLinkPropertiesChanged(
+ new LinkProperties(newLp, true /* parcelSensitiveFields */));
if (networkAgent.everConnected) {
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
}
@@ -7157,7 +7164,9 @@
networkAgent.networkMonitor().setAcceptPartialConnectivity();
}
networkAgent.networkMonitor().notifyNetworkConnected(
- networkAgent.linkProperties, networkAgent.networkCapabilities);
+ new LinkProperties(networkAgent.linkProperties,
+ true /* parcelSensitiveFields */),
+ networkAgent.networkCapabilities);
scheduleUnvalidatedPrompt(networkAgent);
// Whether a particular NetworkRequest listen should cause signal strength thresholds to
@@ -8155,4 +8164,24 @@
0,
callback));
}
+
+ @Override
+ public void simulateDataStall(int detectionMethod, long timestampMillis,
+ @NonNull Network network, @NonNull PersistableBundle extras) {
+ enforceAnyPermissionOf(android.Manifest.permission.MANAGE_TEST_NETWORKS,
+ android.Manifest.permission.NETWORK_STACK);
+ final NetworkCapabilities nc = getNetworkCapabilitiesInternal(network);
+ if (!nc.hasTransport(TRANSPORT_TEST)) {
+ throw new SecurityException("Data Stall simluation is only possible for test networks");
+ }
+
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+ if (nai == null || nai.creatorUid != Binder.getCallingUid()) {
+ throw new SecurityException("Data Stall simulation is only possible for network "
+ + "creators");
+ }
+
+ proxyDataStallToConnectivityDiagnosticsHandler(
+ detectionMethod, network.netId, timestampMillis, extras);
+ }
}
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index 0ea7346..d6bd5a1 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -317,39 +317,34 @@
"Cannot create network for non ipsec, non-testtun interface");
}
- // Setup needs to be done with NETWORK_STACK privileges.
- int callingUid = Binder.getCallingUid();
- Binder.withCleanCallingIdentity(
- () -> {
- try {
- mNMS.setInterfaceUp(iface);
+ try {
+ // This requires NETWORK_STACK privileges.
+ Binder.withCleanCallingIdentity(() -> mNMS.setInterfaceUp(iface));
- // Synchronize all accesses to mTestNetworkTracker to prevent the case
- // where:
- // 1. TestNetworkAgent successfully binds to death of binder
- // 2. Before it is added to the mTestNetworkTracker, binder dies,
- // binderDied() is called (on a different thread)
- // 3. This thread is pre-empted, put() is called after remove()
- synchronized (mTestNetworkTracker) {
- TestNetworkAgent agent =
- registerTestNetworkAgent(
- mHandler.getLooper(),
- mContext,
- iface,
- lp,
- isMetered,
- callingUid,
- administratorUids,
- binder);
+ // Synchronize all accesses to mTestNetworkTracker to prevent the case where:
+ // 1. TestNetworkAgent successfully binds to death of binder
+ // 2. Before it is added to the mTestNetworkTracker, binder dies, binderDied() is called
+ // (on a different thread)
+ // 3. This thread is pre-empted, put() is called after remove()
+ synchronized (mTestNetworkTracker) {
+ TestNetworkAgent agent =
+ registerTestNetworkAgent(
+ mHandler.getLooper(),
+ mContext,
+ iface,
+ lp,
+ isMetered,
+ Binder.getCallingUid(),
+ administratorUids,
+ binder);
- mTestNetworkTracker.put(agent.getNetwork().netId, agent);
- }
- } catch (SocketException e) {
- throw new UncheckedIOException(e);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- });
+ mTestNetworkTracker.put(agent.getNetwork().netId, agent);
+ }
+ } catch (SocketException e) {
+ throw new UncheckedIOException(e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/** Teardown a test network */
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 2d1f553..a9f62d9 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -168,6 +168,9 @@
// Obtained by ConnectivityService and merged into NetworkAgent-provided information.
public CaptivePortalData captivePortalData;
+ // The UID of the remote entity that created this Network.
+ public final int creatorUid;
+
// Networks are lingered when they become unneeded as a result of their NetworkRequests being
// satisfied by a higher-scoring network. so as to allow communication to wrap up before the
// network is taken down. This usually only happens to the default network. Lingering ends with
@@ -268,7 +271,8 @@
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context,
Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
- IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber) {
+ IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber,
+ int creatorUid) {
this.messenger = messenger;
asyncChannel = ac;
network = net;
@@ -282,6 +286,7 @@
mHandler = handler;
networkAgentConfig = config;
this.factorySerialNumber = factorySerialNumber;
+ this.creatorUid = creatorUid;
}
/**
diff --git a/tests/net/java/com/android/internal/net/VpnProfileTest.java b/tests/net/java/com/android/internal/net/VpnProfileTest.java
index ceca6f0..e5daa71 100644
--- a/tests/net/java/com/android/internal/net/VpnProfileTest.java
+++ b/tests/net/java/com/android/internal/net/VpnProfileTest.java
@@ -33,7 +33,9 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/** Unit tests for {@link VpnProfile}. */
@SmallTest
@@ -41,6 +43,9 @@
public class VpnProfileTest {
private static final String DUMMY_PROFILE_KEY = "Test";
+ private static final int ENCODED_INDEX_AUTH_PARAMS_INLINE = 23;
+ private static final int ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS = 24;
+
@Test
public void testDefaults() throws Exception {
final VpnProfile p = new VpnProfile(DUMMY_PROFILE_KEY);
@@ -67,10 +72,11 @@
assertFalse(p.isMetered);
assertEquals(1360, p.maxMtu);
assertFalse(p.areAuthParamsInline);
+ assertFalse(p.isRestrictedToTestNetworks);
}
private VpnProfile getSampleIkev2Profile(String key) {
- final VpnProfile p = new VpnProfile(key);
+ final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */);
p.name = "foo";
p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
@@ -116,7 +122,7 @@
@Test
public void testParcelUnparcel() {
- assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 22);
+ assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 23);
}
@Test
@@ -159,14 +165,41 @@
assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooManyValues));
}
+ private String getEncodedDecodedIkev2ProfileMissingValues(int... missingIndices) {
+ // Sort to ensure when we remove, we can do it from greatest first.
+ Arrays.sort(missingIndices);
+
+ final String encoded = new String(getSampleIkev2Profile(DUMMY_PROFILE_KEY).encode());
+ final List<String> parts =
+ new ArrayList<>(Arrays.asList(encoded.split(VpnProfile.VALUE_DELIMITER)));
+
+ // Remove from back first to ensure indexing is consistent.
+ for (int i = missingIndices.length - 1; i >= 0; i--) {
+ parts.remove(missingIndices[i]);
+ }
+
+ return String.join(VpnProfile.VALUE_DELIMITER, parts.toArray(new String[0]));
+ }
+
@Test
public void testEncodeDecodeInvalidNumberOfValues() {
- final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
- final String encoded = new String(profile.encode());
- final byte[] tooFewValues =
- encoded.substring(0, encoded.lastIndexOf(VpnProfile.VALUE_DELIMITER)).getBytes();
+ final String tooFewValues =
+ getEncodedDecodedIkev2ProfileMissingValues(
+ ENCODED_INDEX_AUTH_PARAMS_INLINE,
+ ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
- assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues));
+ assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()));
+ }
+
+ @Test
+ public void testEncodeDecodeMissingIsRestrictedToTestNetworks() {
+ final String tooFewValues =
+ getEncodedDecodedIkev2ProfileMissingValues(
+ ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
+
+ // Verify decoding without isRestrictedToTestNetworks defaults to false
+ final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
+ assertFalse(decoded.isRestrictedToTestNetworks);
}
@Test
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 3282c76..e66e264 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -75,6 +75,7 @@
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static android.net.RouteInfo.RTN_UNREACHABLE;
+import static android.os.Process.INVALID_UID;
import static android.system.OsConstants.IPPROTO_TCP;
import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType;
@@ -7048,7 +7049,7 @@
final NetworkAgentInfo naiWithoutUid =
new NetworkAgentInfo(
null, null, null, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0);
+ mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
mServiceContext.setPermission(
android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
@@ -7064,7 +7065,7 @@
final NetworkAgentInfo naiWithoutUid =
new NetworkAgentInfo(
null, null, null, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0);
+ mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
@@ -7080,7 +7081,7 @@
final NetworkAgentInfo naiWithoutUid =
new NetworkAgentInfo(
null, null, null, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0);
+ mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
@@ -7097,7 +7098,7 @@
final NetworkAgentInfo naiWithoutUid =
new NetworkAgentInfo(
null, null, network, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0);
+ mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
@@ -7131,7 +7132,7 @@
final NetworkAgentInfo naiWithUid =
new NetworkAgentInfo(
null, null, null, null, null, nc, 0, mServiceContext, null, null,
- mService, null, null, null, 0);
+ mService, null, null, null, 0, INVALID_UID);
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
@@ -7153,7 +7154,7 @@
final NetworkAgentInfo naiWithUid =
new NetworkAgentInfo(
null, null, null, null, null, nc, 0, mServiceContext, null, null,
- mService, null, null, null, 0);
+ mService, null, null, null, 0, INVALID_UID);
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 24a8717..aafa18a 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -38,6 +38,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkProvider;
+import android.os.Binder;
import android.os.INetworkManagementService;
import android.text.format.DateUtils;
@@ -354,7 +355,7 @@
caps.addTransportType(transport);
NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
- NetworkProvider.ID_NONE);
+ NetworkProvider.ID_NONE, Binder.getCallingUid());
nai.everValidated = true;
return nai;
}