Loading core/java/android/net/LinkProperties.java +133 −6 Original line number Diff line number Diff line Loading @@ -23,10 +23,13 @@ import android.text.TextUtils; import android.util.Log; import java.net.InetAddress; import java.net.Inet4Address; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Hashtable; /** * Describes the properties of a network link. Loading @@ -48,10 +51,15 @@ import java.util.Collections; * don't care which is used. The gateways will be * selected based on the destination address and the * source address has no relavence. * * Links can also be stacked on top of each other. * This can be used, for example, to represent a tunnel * interface that runs on top of a physical interface. * * @hide */ public class LinkProperties implements Parcelable { // The interface described by the network link. private String mIfaceName; private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>(); private Collection<InetAddress> mDnses = new ArrayList<InetAddress>(); Loading @@ -60,6 +68,11 @@ public class LinkProperties implements Parcelable { private ProxyProperties mHttpProxy; public boolean mLogMe; // Stores the properties of links that are "stacked" above this link. // Indexed by interface name to allow modification and to prevent duplicates being added. private Hashtable<String, LinkProperties> mStackedLinks = new Hashtable<String, LinkProperties>(); public static class CompareResult<T> { public Collection<T> removed = new ArrayList<T>(); public Collection<T> added = new ArrayList<T>(); Loading Loading @@ -90,6 +103,9 @@ public class LinkProperties implements Parcelable { for (RouteInfo r : source.getRoutes()) mRoutes.add(r); mHttpProxy = (source.getHttpProxy() == null) ? null : new ProxyProperties(source.getHttpProxy()); for (LinkProperties l: source.mStackedLinks.values()) { addStackedLink(l); } } } Loading Loading @@ -165,10 +181,25 @@ public class LinkProperties implements Parcelable { } } /** * Returns all the routes on this link. */ public Collection<RouteInfo> getRoutes() { return Collections.unmodifiableCollection(mRoutes); } /** * Returns all the routes on this link and all the links stacked above it. */ public Collection<RouteInfo> getAllRoutes() { Collection<RouteInfo> routes = new ArrayList(); routes.addAll(mRoutes); for (LinkProperties stacked: mStackedLinks.values()) { routes.addAll(stacked.getAllRoutes()); } return Collections.unmodifiableCollection(routes); } public void setHttpProxy(ProxyProperties proxy) { mHttpProxy = proxy; } Loading @@ -176,6 +207,46 @@ public class LinkProperties implements Parcelable { return mHttpProxy; } /** * Adds a stacked link. * * If there is already a stacked link with the same interfacename as link, * that link is replaced with link. Otherwise, link is added to the list * of stacked links. If link is null, nothing changes. * * @param link The link to add. */ public void addStackedLink(LinkProperties link) { if (link != null && link.getInterfaceName() != null) { mStackedLinks.put(link.getInterfaceName(), link); } } /** * Removes a stacked link. * * If there a stacked link with the same interfacename as link, it is * removed. Otherwise, nothing changes. * * @param link The link to add. */ public void removeStackedLink(LinkProperties link) { if (link != null && link.getInterfaceName() != null) { mStackedLinks.remove(link.getInterfaceName()); } } /** * Returns all the links stacked on top of this link. */ public Collection<LinkProperties> getStackedLinks() { Collection<LinkProperties> stacked = new ArrayList<LinkProperties>(); for (LinkProperties link : mStackedLinks.values()) { stacked.add(new LinkProperties(link)); } return Collections.unmodifiableCollection(stacked); } public void clear() { if (mLogMe) { Log.d("LinkProperties", "clear from " + mIfaceName); Loading @@ -190,6 +261,7 @@ public class LinkProperties implements Parcelable { mDomains = null; mRoutes.clear(); mHttpProxy = null; mStackedLinks.clear(); } /** Loading Loading @@ -219,7 +291,29 @@ public class LinkProperties implements Parcelable { routes += "] "; String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " "); return ifaceName + linkAddresses + routes + dns + domainName + proxy; String stacked = ""; if (mStackedLinks.values().size() > 0) { stacked += " Stacked: ["; for (LinkProperties link: mStackedLinks.values()) { stacked += " [" + link.toString() + " ],"; } stacked += "] "; } return ifaceName + linkAddresses + routes + dns + domainName + proxy + stacked; } /** * Returns true if this link has an IPv4 address. * * @return {@code true} if there is an IPv4 address, {@code false} otherwise. */ public boolean hasIPv4Address() { for (LinkAddress address : mLinkAddresses) { if (address.getAddress() instanceof Inet4Address) { return true; } } return false; } /** Loading Loading @@ -286,6 +380,26 @@ public class LinkProperties implements Parcelable { getHttpProxy().equals(target.getHttpProxy()); } /** * Compares this {@code LinkProperties} stacked links against the target * * @param target LinkProperties to compare. * @return {@code true} if both are identical, {@code false} otherwise. */ public boolean isIdenticalStackedLinks(LinkProperties target) { if (!mStackedLinks.keys().equals(target.mStackedLinks.keys())) { return false; } for (LinkProperties stacked : mStackedLinks.values()) { // Hashtable values can never be null. String iface = stacked.getInterfaceName(); if (!stacked.equals(target.mStackedLinks.get(iface))) { return false; } } return true; } @Override /** * Compares this {@code LinkProperties} instance against the target Loading @@ -298,6 +412,10 @@ public class LinkProperties implements Parcelable { * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal. * 2. Worst case performance is O(n^2). * * This method does not check that stacked interfaces are equal, because * stacked interfaces are not so much a property of the link as a * description of connections between links. * * @param obj the object to be tested for equality. * @return {@code true} if both objects are equal, {@code false} otherwise. */ Loading @@ -312,7 +430,8 @@ public class LinkProperties implements Parcelable { isIdenticalAddresses(target) && isIdenticalDnses(target) && isIdenticalRoutes(target) && isIdenticalHttpProxy(target); isIdenticalHttpProxy(target) && isIdenticalStackedLinks(target); } /** Loading Loading @@ -394,10 +513,10 @@ public class LinkProperties implements Parcelable { */ CompareResult<RouteInfo> result = new CompareResult<RouteInfo>(); result.removed = new ArrayList<RouteInfo>(mRoutes); result.removed = getAllRoutes(); result.added.clear(); if (target != null) { for (RouteInfo r : target.getRoutes()) { for (RouteInfo r : target.getAllRoutes()) { if (! result.removed.remove(r)) { result.added.add(r); } Loading @@ -419,7 +538,8 @@ public class LinkProperties implements Parcelable { + mDnses.size() * 37 + ((null == mDomains) ? 0 : mDomains.hashCode()) + mRoutes.size() * 41 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())); + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()) + mStackedLinks.hashCode() * 47); } /** Loading Loading @@ -449,6 +569,8 @@ public class LinkProperties implements Parcelable { } else { dest.writeByte((byte)0); } ArrayList<LinkProperties> stackedLinks = new ArrayList(mStackedLinks.values()); dest.writeList(stackedLinks); } /** Loading Loading @@ -481,6 +603,11 @@ public class LinkProperties implements Parcelable { if (in.readByte() == 1) { netProp.setHttpProxy((ProxyProperties)in.readParcelable(null)); } ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>(); in.readList(stackedLinks, LinkProperties.class.getClassLoader()); for (LinkProperties stackedLink: stackedLinks) { netProp.addStackedLink(stackedLink); } return netProp; } Loading core/tests/coretests/src/android/net/LinkPropertiesTest.java +26 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; import java.net.InetAddress; import java.util.ArrayList; public class LinkPropertiesTest extends TestCase { private static String ADDRV4 = "75.208.6.1"; Loading Loading @@ -255,5 +256,30 @@ public class LinkPropertiesTest extends TestCase { assertAllRoutesHaveInterface("p2p0", lp2); assertEquals(3, lp.compareRoutes(lp2).added.size()); assertEquals(3, lp.compareRoutes(lp2).removed.size()); @SmallTest public void testStackedInterfaces() { LinkProperties rmnet0 = new LinkProperties(); rmnet0.setInterfaceName("rmnet0"); LinkProperties clat4 = new LinkProperties(); clat4.setInterfaceName("clat4"); assertEquals(0, rmnet0.getStackedLinks().size()); rmnet0.addStackedLink(clat4); assertEquals(1, rmnet0.getStackedLinks().size()); rmnet0.addStackedLink(clat4); assertEquals(1, rmnet0.getStackedLinks().size()); assertEquals(0, clat4.getStackedLinks().size()); // Modify an item in the returned collection to see what happens. for (LinkProperties link : rmnet0.getStackedLinks()) { if (link.getInterfaceName().equals("clat4")) { link.setInterfaceName("newname"); } } for (LinkProperties link : rmnet0.getStackedLinks()) { assertFalse("newname".equals(link.getInterfaceName())); } } } Loading
core/java/android/net/LinkProperties.java +133 −6 Original line number Diff line number Diff line Loading @@ -23,10 +23,13 @@ import android.text.TextUtils; import android.util.Log; import java.net.InetAddress; import java.net.Inet4Address; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Hashtable; /** * Describes the properties of a network link. Loading @@ -48,10 +51,15 @@ import java.util.Collections; * don't care which is used. The gateways will be * selected based on the destination address and the * source address has no relavence. * * Links can also be stacked on top of each other. * This can be used, for example, to represent a tunnel * interface that runs on top of a physical interface. * * @hide */ public class LinkProperties implements Parcelable { // The interface described by the network link. private String mIfaceName; private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>(); private Collection<InetAddress> mDnses = new ArrayList<InetAddress>(); Loading @@ -60,6 +68,11 @@ public class LinkProperties implements Parcelable { private ProxyProperties mHttpProxy; public boolean mLogMe; // Stores the properties of links that are "stacked" above this link. // Indexed by interface name to allow modification and to prevent duplicates being added. private Hashtable<String, LinkProperties> mStackedLinks = new Hashtable<String, LinkProperties>(); public static class CompareResult<T> { public Collection<T> removed = new ArrayList<T>(); public Collection<T> added = new ArrayList<T>(); Loading Loading @@ -90,6 +103,9 @@ public class LinkProperties implements Parcelable { for (RouteInfo r : source.getRoutes()) mRoutes.add(r); mHttpProxy = (source.getHttpProxy() == null) ? null : new ProxyProperties(source.getHttpProxy()); for (LinkProperties l: source.mStackedLinks.values()) { addStackedLink(l); } } } Loading Loading @@ -165,10 +181,25 @@ public class LinkProperties implements Parcelable { } } /** * Returns all the routes on this link. */ public Collection<RouteInfo> getRoutes() { return Collections.unmodifiableCollection(mRoutes); } /** * Returns all the routes on this link and all the links stacked above it. */ public Collection<RouteInfo> getAllRoutes() { Collection<RouteInfo> routes = new ArrayList(); routes.addAll(mRoutes); for (LinkProperties stacked: mStackedLinks.values()) { routes.addAll(stacked.getAllRoutes()); } return Collections.unmodifiableCollection(routes); } public void setHttpProxy(ProxyProperties proxy) { mHttpProxy = proxy; } Loading @@ -176,6 +207,46 @@ public class LinkProperties implements Parcelable { return mHttpProxy; } /** * Adds a stacked link. * * If there is already a stacked link with the same interfacename as link, * that link is replaced with link. Otherwise, link is added to the list * of stacked links. If link is null, nothing changes. * * @param link The link to add. */ public void addStackedLink(LinkProperties link) { if (link != null && link.getInterfaceName() != null) { mStackedLinks.put(link.getInterfaceName(), link); } } /** * Removes a stacked link. * * If there a stacked link with the same interfacename as link, it is * removed. Otherwise, nothing changes. * * @param link The link to add. */ public void removeStackedLink(LinkProperties link) { if (link != null && link.getInterfaceName() != null) { mStackedLinks.remove(link.getInterfaceName()); } } /** * Returns all the links stacked on top of this link. */ public Collection<LinkProperties> getStackedLinks() { Collection<LinkProperties> stacked = new ArrayList<LinkProperties>(); for (LinkProperties link : mStackedLinks.values()) { stacked.add(new LinkProperties(link)); } return Collections.unmodifiableCollection(stacked); } public void clear() { if (mLogMe) { Log.d("LinkProperties", "clear from " + mIfaceName); Loading @@ -190,6 +261,7 @@ public class LinkProperties implements Parcelable { mDomains = null; mRoutes.clear(); mHttpProxy = null; mStackedLinks.clear(); } /** Loading Loading @@ -219,7 +291,29 @@ public class LinkProperties implements Parcelable { routes += "] "; String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " "); return ifaceName + linkAddresses + routes + dns + domainName + proxy; String stacked = ""; if (mStackedLinks.values().size() > 0) { stacked += " Stacked: ["; for (LinkProperties link: mStackedLinks.values()) { stacked += " [" + link.toString() + " ],"; } stacked += "] "; } return ifaceName + linkAddresses + routes + dns + domainName + proxy + stacked; } /** * Returns true if this link has an IPv4 address. * * @return {@code true} if there is an IPv4 address, {@code false} otherwise. */ public boolean hasIPv4Address() { for (LinkAddress address : mLinkAddresses) { if (address.getAddress() instanceof Inet4Address) { return true; } } return false; } /** Loading Loading @@ -286,6 +380,26 @@ public class LinkProperties implements Parcelable { getHttpProxy().equals(target.getHttpProxy()); } /** * Compares this {@code LinkProperties} stacked links against the target * * @param target LinkProperties to compare. * @return {@code true} if both are identical, {@code false} otherwise. */ public boolean isIdenticalStackedLinks(LinkProperties target) { if (!mStackedLinks.keys().equals(target.mStackedLinks.keys())) { return false; } for (LinkProperties stacked : mStackedLinks.values()) { // Hashtable values can never be null. String iface = stacked.getInterfaceName(); if (!stacked.equals(target.mStackedLinks.get(iface))) { return false; } } return true; } @Override /** * Compares this {@code LinkProperties} instance against the target Loading @@ -298,6 +412,10 @@ public class LinkProperties implements Parcelable { * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal. * 2. Worst case performance is O(n^2). * * This method does not check that stacked interfaces are equal, because * stacked interfaces are not so much a property of the link as a * description of connections between links. * * @param obj the object to be tested for equality. * @return {@code true} if both objects are equal, {@code false} otherwise. */ Loading @@ -312,7 +430,8 @@ public class LinkProperties implements Parcelable { isIdenticalAddresses(target) && isIdenticalDnses(target) && isIdenticalRoutes(target) && isIdenticalHttpProxy(target); isIdenticalHttpProxy(target) && isIdenticalStackedLinks(target); } /** Loading Loading @@ -394,10 +513,10 @@ public class LinkProperties implements Parcelable { */ CompareResult<RouteInfo> result = new CompareResult<RouteInfo>(); result.removed = new ArrayList<RouteInfo>(mRoutes); result.removed = getAllRoutes(); result.added.clear(); if (target != null) { for (RouteInfo r : target.getRoutes()) { for (RouteInfo r : target.getAllRoutes()) { if (! result.removed.remove(r)) { result.added.add(r); } Loading @@ -419,7 +538,8 @@ public class LinkProperties implements Parcelable { + mDnses.size() * 37 + ((null == mDomains) ? 0 : mDomains.hashCode()) + mRoutes.size() * 41 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())); + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()) + mStackedLinks.hashCode() * 47); } /** Loading Loading @@ -449,6 +569,8 @@ public class LinkProperties implements Parcelable { } else { dest.writeByte((byte)0); } ArrayList<LinkProperties> stackedLinks = new ArrayList(mStackedLinks.values()); dest.writeList(stackedLinks); } /** Loading Loading @@ -481,6 +603,11 @@ public class LinkProperties implements Parcelable { if (in.readByte() == 1) { netProp.setHttpProxy((ProxyProperties)in.readParcelable(null)); } ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>(); in.readList(stackedLinks, LinkProperties.class.getClassLoader()); for (LinkProperties stackedLink: stackedLinks) { netProp.addStackedLink(stackedLink); } return netProp; } Loading
core/tests/coretests/src/android/net/LinkPropertiesTest.java +26 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; import java.net.InetAddress; import java.util.ArrayList; public class LinkPropertiesTest extends TestCase { private static String ADDRV4 = "75.208.6.1"; Loading Loading @@ -255,5 +256,30 @@ public class LinkPropertiesTest extends TestCase { assertAllRoutesHaveInterface("p2p0", lp2); assertEquals(3, lp.compareRoutes(lp2).added.size()); assertEquals(3, lp.compareRoutes(lp2).removed.size()); @SmallTest public void testStackedInterfaces() { LinkProperties rmnet0 = new LinkProperties(); rmnet0.setInterfaceName("rmnet0"); LinkProperties clat4 = new LinkProperties(); clat4.setInterfaceName("clat4"); assertEquals(0, rmnet0.getStackedLinks().size()); rmnet0.addStackedLink(clat4); assertEquals(1, rmnet0.getStackedLinks().size()); rmnet0.addStackedLink(clat4); assertEquals(1, rmnet0.getStackedLinks().size()); assertEquals(0, clat4.getStackedLinks().size()); // Modify an item in the returned collection to see what happens. for (LinkProperties link : rmnet0.getStackedLinks()) { if (link.getInterfaceName().equals("clat4")) { link.setInterfaceName("newname"); } } for (LinkProperties link : rmnet0.getStackedLinks()) { assertFalse("newname".equals(link.getInterfaceName())); } } }