Merge "Introduce network link quality statistics" into klp-dev
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index f6a114c..a390add 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -32,27 +32,56 @@
/**
* IPv4 or IPv6 address.
*/
- private final InetAddress address;
+ private InetAddress address;
/**
* Network prefix length
*/
- private final int prefixLength;
+ private int prefixLength;
- public LinkAddress(InetAddress address, int prefixLength) {
+ private void init(InetAddress address, int prefixLength) {
if (address == null || prefixLength < 0 ||
((address instanceof Inet4Address) && prefixLength > 32) ||
(prefixLength > 128)) {
throw new IllegalArgumentException("Bad LinkAddress params " + address +
- prefixLength);
+ "/" + prefixLength);
}
this.address = address;
this.prefixLength = prefixLength;
}
+ public LinkAddress(InetAddress address, int prefixLength) {
+ init(address, prefixLength);
+ }
+
public LinkAddress(InterfaceAddress interfaceAddress) {
- this.address = interfaceAddress.getAddress();
- this.prefixLength = interfaceAddress.getNetworkPrefixLength();
+ init(interfaceAddress.getAddress(),
+ interfaceAddress.getNetworkPrefixLength());
+ }
+
+ /**
+ * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
+ * "2001:db8::1/64".
+ * @param string The string to parse.
+ */
+ public LinkAddress(String address) {
+ InetAddress inetAddress = null;
+ int prefixLength = -1;
+ try {
+ String [] pieces = address.split("/", 2);
+ prefixLength = Integer.parseInt(pieces[1]);
+ inetAddress = InetAddress.parseNumericAddress(pieces[0]);
+ } catch (NullPointerException e) { // Null string.
+ } catch (ArrayIndexOutOfBoundsException e) { // No prefix length.
+ } catch (NumberFormatException e) { // Non-numeric prefix.
+ } catch (IllegalArgumentException e) { // Invalid IP address.
+ }
+
+ if (inetAddress == null || prefixLength == -1) {
+ throw new IllegalArgumentException("Bad LinkAddress params " + address);
+ }
+
+ init(inetAddress, prefixLength);
}
@Override
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 6ab810c..1f73c4a 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -23,6 +23,7 @@
import java.net.InetAddress;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.UnknownHostException;
import java.util.ArrayList;
@@ -153,8 +154,28 @@
return addresses;
}
- public void addLinkAddress(LinkAddress address) {
- if (address != null) mLinkAddresses.add(address);
+ /**
+ * Adds a link address if it does not exist, or update it if it does.
+ * @param address The {@code LinkAddress} to add.
+ * @return true if the address was added, false if it already existed.
+ */
+ public boolean addLinkAddress(LinkAddress address) {
+ // TODO: when the LinkAddress has other attributes beyond the
+ // address and the prefix length, update them here.
+ if (address != null && !mLinkAddresses.contains(address)) {
+ mLinkAddresses.add(address);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Removes a link address.
+ * @param address The {@code LinkAddress} to remove.
+ * @return true if the address was removed, false if it did not exist.
+ */
+ public boolean removeLinkAddress(LinkAddress toRemove) {
+ return mLinkAddresses.remove(toRemove);
}
/**
@@ -245,11 +266,14 @@
* of stacked links. If link is null, nothing changes.
*
* @param link The link to add.
+ * @return true if the link was stacked, false otherwise.
*/
- public void addStackedLink(LinkProperties link) {
+ public boolean addStackedLink(LinkProperties link) {
if (link != null && link.getInterfaceName() != null) {
mStackedLinks.put(link.getInterfaceName(), link);
+ return true;
}
+ return false;
}
/**
@@ -258,12 +282,15 @@
* If there a stacked link with the same interfacename as link, it is
* removed. Otherwise, nothing changes.
*
- * @param link The link to add.
+ * @param link The link to remove.
+ * @return true if the link was removed, false otherwise.
*/
- public void removeStackedLink(LinkProperties link) {
+ public boolean removeStackedLink(LinkProperties link) {
if (link != null && link.getInterfaceName() != null) {
- mStackedLinks.remove(link.getInterfaceName());
+ LinkProperties removed = mStackedLinks.remove(link.getInterfaceName());
+ return removed != null;
}
+ return false;
}
/**
@@ -340,6 +367,20 @@
}
/**
+ * Returns true if this link has an IPv6 address.
+ *
+ * @return {@code true} if there is an IPv6 address, {@code false} otherwise.
+ */
+ public boolean hasIPv6Address() {
+ for (LinkAddress address : mLinkAddresses) {
+ if (address.getAddress() instanceof Inet6Address) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Compares this {@code LinkProperties} interface name against the target
*
* @param target LinkProperties to compare.
diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
index 9fdfd0e..a570802 100644
--- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java
+++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
@@ -306,5 +306,61 @@
for (LinkProperties link : rmnet0.getStackedLinks()) {
assertFalse("newname".equals(link.getInterfaceName()));
}
+
+ assertTrue(rmnet0.removeStackedLink(clat4));
+ assertEquals(0, rmnet0.getStackedLinks().size());
+ assertEquals(1, rmnet0.getAddresses().size());
+ assertEquals(1, rmnet0.getLinkAddresses().size());
+ assertEquals(1, rmnet0.getAllAddresses().size());
+ assertEquals(1, rmnet0.getAllLinkAddresses().size());
+
+ assertFalse(rmnet0.removeStackedLink(clat4));
+ }
+
+ @SmallTest
+ public void testAddressMethods() {
+ LinkProperties lp = new LinkProperties();
+
+ // No addresses.
+ assertFalse(lp.hasIPv4Address());
+ assertFalse(lp.hasIPv6Address());
+
+ // Addresses on stacked links don't count.
+ LinkProperties stacked = new LinkProperties();
+ stacked.setInterfaceName("stacked");
+ lp.addStackedLink(stacked);
+ stacked.addLinkAddress(LINKADDRV4);
+ stacked.addLinkAddress(LINKADDRV6);
+ assertTrue(stacked.hasIPv4Address());
+ assertTrue(stacked.hasIPv6Address());
+ assertFalse(lp.hasIPv4Address());
+ assertFalse(lp.hasIPv6Address());
+ lp.removeStackedLink(stacked);
+ assertFalse(lp.hasIPv4Address());
+ assertFalse(lp.hasIPv6Address());
+
+ // Addresses on the base link.
+ // Check the return values of hasIPvXAddress and ensure the add/remove methods return true
+ // iff something changes.
+ assertTrue(lp.addLinkAddress(LINKADDRV6));
+ assertFalse(lp.hasIPv4Address());
+ assertTrue(lp.hasIPv6Address());
+
+ assertTrue(lp.removeLinkAddress(LINKADDRV6));
+ assertTrue(lp.addLinkAddress(LINKADDRV4));
+ assertTrue(lp.hasIPv4Address());
+ assertFalse(lp.hasIPv6Address());
+
+ assertTrue(lp.addLinkAddress(LINKADDRV6));
+ assertTrue(lp.hasIPv4Address());
+ assertTrue(lp.hasIPv6Address());
+
+ // Adding an address twice has no effect.
+ // Removing an address that's not present has no effect.
+ assertFalse(lp.addLinkAddress(LINKADDRV4));
+ assertTrue(lp.hasIPv4Address());
+ assertTrue(lp.removeLinkAddress(LINKADDRV4));
+ assertFalse(lp.hasIPv4Address());
+ assertFalse(lp.removeLinkAddress(LINKADDRV4));
}
}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 27614d0..ec6b063 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -4038,8 +4038,8 @@
// Get the type of addresses supported by this link
LinkProperties lp = mCs.getLinkProperties(
ConnectivityManager.TYPE_MOBILE_HIPRI);
- boolean linkHasIpv4 = hasIPv4Address(lp);
- boolean linkHasIpv6 = hasIPv6Address(lp);
+ boolean linkHasIpv4 = lp.hasIPv4Address();
+ boolean linkHasIpv6 = lp.hasIPv6Address();
log("isMobileOk: linkHasIpv4=" + linkHasIpv4
+ " linkHasIpv6=" + linkHasIpv6);
@@ -4185,20 +4185,6 @@
}
}
- public boolean hasIPv4Address(LinkProperties lp) {
- return lp.hasIPv4Address();
- }
-
- // Not implemented in LinkProperties, do it here.
- public boolean hasIPv6Address(LinkProperties lp) {
- for (LinkAddress address : lp.getLinkAddresses()) {
- if (address.getAddress() instanceof Inet6Address) {
- return true;
- }
- }
- return false;
- }
-
private void log(String s) {
Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s);
}