From accd5fcb79e1cd1b6c9cff7b14ff4c9ba78019a6 Mon Sep 17 00:00:00 2001 From: Pierre Imai Date: Mon, 8 Feb 2016 16:01:40 +0900 Subject: [PATCH 01/14] DO NOT MERGE: Silence the obnoxious MTU 0 error message that occur when no MTU is specified for a given network. Bug: 10705136 (cherry picked from commit 54f0d9edbf7f6ea6dd805dc77fdbf2c3848188e2) Change-Id: I89e2fdfbbfa981d435a2974422d9d9c009872d76 --- .../core/java/com/android/server/ConnectivityService.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 30edd9fe8bf46..9b0a0ff073f3e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1813,11 +1813,14 @@ public class ConnectivityService extends IConnectivityManager.Stub private void updateMtu(LinkProperties newLp, LinkProperties oldLp) { final String iface = newLp.getInterfaceName(); final int mtu = newLp.getMtu(); + if (oldLp == null && mtu == 0) { + // Silently ignore unset MTU value. + return; + } if (oldLp != null && newLp.isIdenticalMtu(oldLp)) { if (VDBG) log("identical MTU - not setting"); return; } - if (LinkProperties.isValidMtu(mtu, newLp.hasGlobalIPv6Address()) == false) { if (mtu != 0) loge("Unexpected mtu value: " + mtu + ", " + iface); return; From 3841a48d0a093bbbd6ffe6338170e1e2dbc11997 Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Wed, 25 Nov 2015 12:49:38 +0900 Subject: [PATCH 02/14] DO NOT MERGE: Support timeouts for requestNetwork() invocations. (cherry-pick of 06c3ef1367e850746eef0a5462bdce8674d74c30) (cherry picked from commit 57faba9ec73fbb311d5ca1df3278aee9728589d5) Bug: 21414325 Change-Id: I1a58823a372154589f972b98c4c428eab0e0523e --- .../java/android/net/ConnectivityManager.java | 27 ++++++- .../android/server/ConnectivityService.java | 27 ++++++- .../server/ConnectivityServiceTest.java | 81 ++++++++++++++++++- 3 files changed, 127 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 0afb546aa4e47..43c8c81da2668 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -2592,7 +2592,8 @@ public class ConnectivityManager { /** * Called if no network is found in the given timeout time. If no timeout is given, - * this will not be called. + * this will not be called. The associated {@link NetworkRequest} will have already + * been removed and released, as if {@link #unregisterNetworkCallback} had been called. * @hide */ public void onUnavailable() {} @@ -2665,6 +2666,26 @@ public class ConnectivityManager { /** @hide */ public static final int CALLBACK_RESUMED = BASE + 12; + /** @hide */ + public static String getCallbackName(int whichCallback) { + switch (whichCallback) { + case CALLBACK_PRECHECK: return "CALLBACK_PRECHECK"; + case CALLBACK_AVAILABLE: return "CALLBACK_AVAILABLE"; + case CALLBACK_LOSING: return "CALLBACK_LOSING"; + case CALLBACK_LOST: return "CALLBACK_LOST"; + case CALLBACK_UNAVAIL: return "CALLBACK_UNAVAIL"; + case CALLBACK_CAP_CHANGED: return "CALLBACK_CAP_CHANGED"; + case CALLBACK_IP_CHANGED: return "CALLBACK_IP_CHANGED"; + case CALLBACK_RELEASED: return "CALLBACK_RELEASED"; + case CALLBACK_EXIT: return "CALLBACK_EXIT"; + case EXPIRE_LEGACY_REQUEST: return "EXPIRE_LEGACY_REQUEST"; + case CALLBACK_SUSPENDED: return "CALLBACK_SUSPENDED"; + case CALLBACK_RESUMED: return "CALLBACK_RESUMED"; + default: + return Integer.toString(whichCallback); + } + } + private class CallbackHandler extends Handler { private final HashMapmCallbackMap; private final AtomicInteger mRefCount; @@ -2831,7 +2852,7 @@ public class ConnectivityManager { private final static int REQUEST = 2; private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, - NetworkCallback networkCallback, int timeoutSec, int action, + NetworkCallback networkCallback, int timeoutMs, int action, int legacyType) { if (networkCallback == null) { throw new IllegalArgumentException("null NetworkCallback"); @@ -2847,7 +2868,7 @@ public class ConnectivityManager { new Messenger(sCallbackHandler), new Binder()); } else { networkCallback.networkRequest = mService.requestNetwork(need, - new Messenger(sCallbackHandler), timeoutSec, new Binder(), legacyType); + new Messenger(sCallbackHandler), timeoutMs, new Binder(), legacyType); } if (networkCallback.networkRequest != null) { sNetworkCallback.put(networkCallback.networkRequest, networkCallback); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 9b0a0ff073f3e..17a147614e9f3 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2600,14 +2600,28 @@ public class ConnectivityService extends IConnectivityManager.Stub "request NetworkCapabilities", ConnectivityManager.CALLBACK_CAP_CHANGED); } + private void handleTimedOutNetworkRequest(final NetworkRequestInfo nri) { + if (mNetworkRequests.get(nri.request) != null && mNetworkForRequestId.get( + nri.request.requestId) == null) { + handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_UNAVAIL); + } + } + private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) { final NetworkRequestInfo nri = getNriForAppRequest( request, callingUid, "release NetworkRequest"); - if (nri == null) return; + if (nri != null) { + handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_RELEASED); + } + } - if (VDBG || (DBG && nri.request.isRequest())) log("releasing " + request); + private void handleRemoveNetworkRequest(final NetworkRequestInfo nri, final int whichCallback) { + final String logCallbackType = ConnectivityManager.getCallbackName(whichCallback); + if (VDBG || (DBG && nri.request.isRequest())) { + log("releasing " + nri.request + " (" + logCallbackType + ")"); + } nri.unlinkDeathRecipient(); - mNetworkRequests.remove(request); + mNetworkRequests.remove(nri.request); synchronized (mUidToNetworkRequestCount) { int requests = mUidToNetworkRequestCount.get(nri.mUid, 0); if (requests < 1) { @@ -2701,7 +2715,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } } - callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED, 0); + callCallbackForRequest(nri, null, whichCallback, 0); } @Override @@ -2938,6 +2952,11 @@ public class ConnectivityService extends IConnectivityManager.Stub handleRegisterNetworkRequestWithIntent(msg); break; } + case EVENT_TIMEOUT_NETWORK_REQUEST: { + NetworkRequestInfo nri = (NetworkRequestInfo) msg.obj; + handleTimedOutNetworkRequest(nri); + break; + } case EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT: { handleReleaseNetworkRequestWithIntent((PendingIntent) msg.obj, msg.arg1); break; diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 4af1cf1a0df8b..0f180af2bd1fe 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -1077,7 +1077,8 @@ public class ConnectivityServiceTest extends AndroidTestCase { NETWORK_CAPABILITIES, LINK_PROPERTIES, LOSING, - LOST + LOST, + UNAVAILABLE } /** @@ -1117,6 +1118,11 @@ public class ConnectivityServiceTest extends AndroidTestCase { setLastCallback(CallbackState.AVAILABLE, network, null); } + @Override + public void onUnavailable() { + setLastCallback(CallbackState.UNAVAILABLE, null, null); + } + @Override public void onLosing(Network network, int maxMsToLive) { setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */); @@ -2221,6 +2227,79 @@ public class ConnectivityServiceTest extends AndroidTestCase { mCm.unregisterNetworkCallback(defaultCallback); } + /** + * Validate that a satisfied network request does not trigger onUnavailable() once the + * time-out period expires. + */ + @SmallTest + public void testSatisfiedNetworkRequestDoesNotTriggerOnUnavailable() { + NetworkRequest nr = new NetworkRequest.Builder().addTransportType( + NetworkCapabilities.TRANSPORT_WIFI).build(); + final TestNetworkCallback networkCallback = new TestNetworkCallback(); + mCm.requestNetwork(nr, networkCallback, 10); + + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(false); + networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent); + + // pass timeout and validate that UNAVAILABLE is not called + try { + Thread.sleep(15); + } catch (InterruptedException e) { + } + networkCallback.assertNoCallback(); + } + + /** + * Validate that when a time-out is specified for a network request the onUnavailable() + * callback is called when time-out expires. Then validate that if network request is + * (somehow) satisfied - the callback isn't called later. + */ + @SmallTest + public void testTimedoutNetworkRequest() { + NetworkRequest nr = new NetworkRequest.Builder().addTransportType( + NetworkCapabilities.TRANSPORT_WIFI).build(); + final TestNetworkCallback networkCallback = new TestNetworkCallback(); + mCm.requestNetwork(nr, networkCallback, 10); + + // pass timeout and validate that UNAVAILABLE is called + networkCallback.expectCallback(CallbackState.UNAVAILABLE, null); + + // create a network satisfying request - validate that request not triggered + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(false); + networkCallback.assertNoCallback(); + } + + /** + * Validate that when a network request is unregistered (cancelled) the time-out for that + * request doesn't trigger the onUnavailable() callback. + */ + @SmallTest + public void testTimedoutAfterUnregisteredNetworkRequest() { + NetworkRequest nr = new NetworkRequest.Builder().addTransportType( + NetworkCapabilities.TRANSPORT_WIFI).build(); + final TestNetworkCallback networkCallback = new TestNetworkCallback(); + mCm.requestNetwork(nr, networkCallback, 10); + + // remove request + mCm.unregisterNetworkCallback(networkCallback); + + // pass timeout and validate that no callbacks + // Note: doesn't validate that nothing called from CS since even if called the CM already + // unregisters the callback and won't pass it through! + try { + Thread.sleep(15); + } catch (InterruptedException e) { + } + networkCallback.assertNoCallback(); + + // create a network satisfying request - validate that request not triggered + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(false); + networkCallback.assertNoCallback(); + } + private static class TestKeepaliveCallback extends PacketKeepaliveCallback { public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR }; From 0668a61d82a424fb3714b6222f0e4213c18fc7b1 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Thu, 6 Oct 2016 15:19:36 +0900 Subject: [PATCH 03/14] DO NOT MERGE: Add fuzzing tests to ApfFilter RA processing Test: added new unit tests (cherry picked from commit 8acea76a2b7555b3bd5ca1170cca9d09e979fafc) Change-Id: I847d7e4895766042043c0bba1c9b9a698a705d87 --- .../net/java/android/net/apf/ApfFilter.java | 32 +++++++++----- .../src/android/net/apf/ApfTest.java | 42 +++++++++++++++++-- 2 files changed, 60 insertions(+), 14 deletions(-) diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java index 4c7545240c237..957a8d30e2f8f 100644 --- a/services/net/java/android/net/apf/ApfFilter.java +++ b/services/net/java/android/net/apf/ApfFilter.java @@ -289,8 +289,15 @@ public class ApfFilter { return System.currentTimeMillis() / DateUtils.SECOND_IN_MILLIS; } + public static class InvalidRaException extends Exception { + public InvalidRaException(String m) { + super(m); + } + } + // A class to hold information about an RA. - private class Ra { + @VisibleForTesting + class Ra { // From RFC4861: private static final int ICMP6_RA_HEADER_LEN = 16; private static final int ICMP6_RA_CHECKSUM_OFFSET = @@ -362,7 +369,7 @@ public class ApfFilter { } catch (UnsupportedOperationException e) { // array() failed. Cannot happen, mPacket is array-backed and read-write. return "???"; - } catch (ClassCastException | UnknownHostException e) { + } catch (ClassCastException|UnknownHostException e) { // Cannot happen. return "???"; } @@ -403,7 +410,7 @@ public class ApfFilter { rdnssOptionToString(sb, i); } return sb.toString(); - } catch (BufferUnderflowException | IndexOutOfBoundsException e) { + } catch (BufferUnderflowException|IndexOutOfBoundsException e) { return ""; } } @@ -436,7 +443,11 @@ public class ApfFilter { // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with // specifications. - Ra(byte[] packet, int length) { + Ra(byte[] packet, int length) throws InvalidRaException { + if (length < ICMP6_RA_OPTION_OFFSET) { + throw new InvalidRaException("Not an ICMP6 router advertisement"); + } + mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length)); mLastSeen = curTime(); @@ -445,7 +456,7 @@ public class ApfFilter { if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 || uint8(mPacket.get(IPV6_NEXT_HEADER_OFFSET)) != IPPROTO_ICMPV6 || uint8(mPacket.get(ICMP6_TYPE_OFFSET)) != ICMP6_ROUTER_ADVERTISEMENT) { - throw new IllegalArgumentException("Not an ICMP6 router advertisement"); + throw new InvalidRaException("Not an ICMP6 router advertisement"); } @@ -511,7 +522,7 @@ public class ApfFilter { break; } if (optionLength <= 0) { - throw new IllegalArgumentException(String.format( + throw new InvalidRaException(String.format( "Invalid option length opt=%d len=%d", optionType, optionLength)); } mPacket.position(position + optionLength); @@ -925,8 +936,8 @@ public class ApfFilter { // Execution will reach the end of the program if no filters match, which will pass the // packet to the AP. program = gen.generate(); - } catch (IllegalInstructionException e) { - Log.e(TAG, "Program failed to generate: ", e); + } catch (IllegalInstructionException|IllegalStateException e) { + Log.e(TAG, "Failed to generate APF program.", e); return; } mLastTimeInstalledProgram = curTime(); @@ -972,7 +983,8 @@ public class ApfFilter { * if the current APF program should be updated. * @return a ProcessRaResult enum describing what action was performed. */ - private synchronized ProcessRaResult processRa(byte[] packet, int length) { + @VisibleForTesting + synchronized ProcessRaResult processRa(byte[] packet, int length) { if (VDBG) hexDump("Read packet = ", packet, length); // Have we seen this RA before? @@ -1011,7 +1023,7 @@ public class ApfFilter { try { ra = new Ra(packet, length); } catch (Exception e) { - Log.e(TAG, "Error parsing RA: " + e); + Log.e(TAG, "Error parsing RA", e); return ProcessRaResult.PARSE_ERROR; } // Ignore 0 lifetime RAs. diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java index f7c61d15bb5fe..37807b22264a6 100644 --- a/services/tests/servicestests/src/android/net/apf/ApfTest.java +++ b/services/tests/servicestests/src/android/net/apf/ApfTest.java @@ -16,10 +16,6 @@ package android.net.apf; -import static android.system.OsConstants.*; - -import com.android.frameworks.servicestests.R; - import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkUtils; @@ -37,6 +33,10 @@ import android.system.ErrnoException; import android.system.Os; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; +import static android.system.OsConstants.*; + +import com.android.frameworks.servicestests.R; +import com.android.internal.util.HexDump; import org.mockito.ArgumentCaptor; import org.mockito.Mock; @@ -54,6 +54,7 @@ import java.net.InetAddress; import java.net.NetworkInterface; import java.nio.ByteBuffer; import java.util.List; +import java.util.Random; import libcore.io.IoUtils; import libcore.io.Streams; @@ -1146,6 +1147,39 @@ public class ApfTest extends AndroidTestCase { buffer.position(original); } + public void testRaParsing() throws Exception { + final int maxRandomPacketSize = 512; + final Random r = new Random(); + MockIpManagerCallback cb = new MockIpManagerCallback(); + TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST, mLog); + for (int i = 0; i < 1000; i++) { + byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)]; + r.nextBytes(packet); + try { + apfFilter.new Ra(packet, packet.length); + } catch (ApfFilter.InvalidRaException e) { + } catch (Exception e) { + throw new Exception("bad packet: " + HexDump.toHexString(packet), e); + } + } + } + + public void testRaProcessing() throws Exception { + final int maxRandomPacketSize = 512; + final Random r = new Random(); + MockIpManagerCallback cb = new MockIpManagerCallback(); + TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST, mLog); + for (int i = 0; i < 1000; i++) { + byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)]; + r.nextBytes(packet); + try { + apfFilter.processRa(packet, packet.length); + } catch (Exception e) { + throw new Exception("bad packet: " + HexDump.toHexString(packet), e); + } + } + } + /** * Call the APF interpreter the run {@code program} on {@code packet} pretending the * filter was installed {@code filter_age} seconds ago. From 4104ff922040540b73f79f0f89dab3ae42b50462 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Thu, 13 Oct 2016 09:26:01 +0900 Subject: [PATCH 04/14] DO NOT MERGE: ApfFilter: systematically use u8, u16, u32 getters This patch adds a getUint8 getter for ByteBuffers and changes ApfFilter to make uses of getUint8/16/32 everywhere. The return types of getUint16 is also changed from long to int, which will expand gracefully to long as an unsigned int as it is guaranteed to be positive after getUint16. Test: ApfTest passes (cherry picked from commit 995dd94673005b43d32456e2de5fda0090b23576) Change-Id: I606ebc5aedfcacde400d27cc6bc37145769b122c --- .../net/java/android/net/apf/ApfFilter.java | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java index 957a8d30e2f8f..18d69eca64329 100644 --- a/services/net/java/android/net/apf/ApfFilter.java +++ b/services/net/java/android/net/apf/ApfFilter.java @@ -379,16 +379,16 @@ public class ApfFilter { // TODO: Make this static once RA is its own class. private void prefixOptionToString(StringBuffer sb, int offset) { String prefix = IPv6AddresstoString(offset + 16); - int length = uint8(mPacket.get(offset + 2)); - long valid = mPacket.getInt(offset + 4); - long preferred = mPacket.getInt(offset + 8); + int length = getUint8(mPacket, offset + 2); + long valid = getUint32(mPacket, offset + 4); + long preferred = getUint32(mPacket, offset + 8); sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred)); } private void rdnssOptionToString(StringBuffer sb, int offset) { - int optLen = uint8(mPacket.get(offset + 1)) * 8; + int optLen = getUint8(mPacket, offset + 1) * 8; if (optLen < 24) return; // Malformed or empty. - long lifetime = uint32(mPacket.getInt(offset + 4)); + long lifetime = getUint32(mPacket, offset + 4); int numServers = (optLen - 8) / 16; sb.append("DNS ").append(lifetime).append("s"); for (int server = 0; server < numServers; server++) { @@ -402,7 +402,7 @@ public class ApfFilter { sb.append(String.format("RA %s -> %s %ds ", IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET), IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET), - uint16(mPacket.getShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET)))); + getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET))); for (int i: mPrefixOptionOffsets) { prefixOptionToString(sb, i); } @@ -454,8 +454,8 @@ public class ApfFilter { // Sanity check packet in case a packet arrives before we attach RA filter // to our packet socket. b/29586253 if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 || - uint8(mPacket.get(IPV6_NEXT_HEADER_OFFSET)) != IPPROTO_ICMPV6 || - uint8(mPacket.get(ICMP6_TYPE_OFFSET)) != ICMP6_ROUTER_ADVERTISEMENT) { + getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 || + getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMP6_ROUTER_ADVERTISEMENT) { throw new InvalidRaException("Not an ICMP6 router advertisement"); } @@ -477,8 +477,8 @@ public class ApfFilter { mPacket.position(ICMP6_RA_OPTION_OFFSET); while (mPacket.hasRemaining()) { final int position = mPacket.position(); - final int optionType = uint8(mPacket.get(position)); - final int optionLength = uint8(mPacket.get(position + 1)) * 8; + final int optionType = getUint8(mPacket, position); + final int optionLength = getUint8(mPacket, position + 1) * 8; long lifetime; switch (optionType) { case ICMP6_PREFIX_OPTION_TYPE: @@ -563,10 +563,10 @@ public class ApfFilter { final long optionLifetime; switch (lifetimeLength) { case 2: - optionLifetime = uint16(byteBuffer.getShort(offset)); + optionLifetime = getUint16(byteBuffer, offset); break; case 4: - optionLifetime = uint32(byteBuffer.getInt(offset)); + optionLifetime = getUint32(byteBuffer, offset); break; default: throw new IllegalStateException("bogus lifetime size " + lifetimeLength); @@ -1162,7 +1162,11 @@ public class ApfFilter { return i & 0xffffffffL; } - private static long getUint16(ByteBuffer buffer, int position) { + private static int getUint8(ByteBuffer buffer, int position) { + return uint8(buffer.get(position)); + } + + private static int getUint16(ByteBuffer buffer, int position) { return uint16(buffer.getShort(position)); } From 94dcb3c3fd84a23bbcca75eb24c8ee9aa6ffa9b1 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Tue, 4 Oct 2016 11:24:12 +0900 Subject: [PATCH 05/14] DO NOT MERGE: Do not synchronize boolean reads/writes This patch removes the synchronization around the private variable mRunning inside of IpReachabilityMonitor and instead qualifeis the field as volatile. Synchronization is not needed for reads/writes on native fields or object references because they are already guaranteed to be atomic. Synchronization here was used for enforcing memory visibility across concurrent threads indirectly through monitor acquire/release. The volatile keyword achieves this in a more explicit way. Also, this patch changes the way that probeAll() copies the IpReachabilityMonitor's mIpWatchList by temporary holding mIpWatchList keys into an ArrayList instead of a more expensive HashSet. Since Java HashSet are just degenerated HashMaps, and that key iteration order is based on key hash, the iteration order over this temporary collection will be consistent for the same mIpWatchList. Test: refactoring CL. Existing unit tests still pass. (cherry picked from commit b0f1186c034c4df9eb54ed29944d16ce6d7ade56) Change-Id: I48d2b4d837a459150cd431b400ec01b87b48c014 --- .../android/net/ip/IpReachabilityMonitor.java | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java index a6bb40c6ac0bc..a883e28e96c64 100644 --- a/services/net/java/android/net/ip/IpReachabilityMonitor.java +++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java @@ -50,9 +50,9 @@ import java.net.NetworkInterface; import java.net.SocketAddress; import java.net.SocketException; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -163,8 +163,7 @@ public class IpReachabilityMonitor { private Map mIpWatchList = new HashMap<>(); @GuardedBy("mLock") private int mIpWatchListVersion; - @GuardedBy("mLock") - private boolean mRunning; + private volatile boolean mRunning; // Time in milliseconds of the last forced probe request. private volatile long mLastProbeTimeMs; @@ -246,7 +245,7 @@ public class IpReachabilityMonitor { } public void stop() { - synchronized (mLock) { mRunning = false; } + mRunning = false; clearLinkProperties(); mNetlinkSocketObserver.clearNetlinkSocket(); } @@ -281,12 +280,6 @@ public class IpReachabilityMonitor { } } - private boolean stillRunning() { - synchronized (mLock) { - return mRunning; - } - } - private static boolean isOnLink(List routes, InetAddress ip) { for (RouteInfo route : routes) { if (!route.hasGateway() && route.matches(ip)) { @@ -390,12 +383,12 @@ public class IpReachabilityMonitor { } public void probeAll() { - Set ipProbeList = new HashSet(); + final List ipProbeList; synchronized (mLock) { - ipProbeList.addAll(mIpWatchList.keySet()); + ipProbeList = new ArrayList<>(mIpWatchList.keySet()); } - if (!ipProbeList.isEmpty() && stillRunning()) { + if (!ipProbeList.isEmpty() && mRunning) { // Keep the CPU awake long enough to allow all ARP/ND // probes a reasonable chance at success. See b/23197666. // @@ -406,7 +399,7 @@ public class IpReachabilityMonitor { } for (InetAddress target : ipProbeList) { - if (!stillRunning()) { + if (!mRunning) { break; } final int returnValue = probeNeighbor(mInterfaceIndex, target); @@ -451,21 +444,21 @@ public class IpReachabilityMonitor { @Override public void run() { if (VDBG) { Log.d(TAG, "Starting observing thread."); } - synchronized (mLock) { mRunning = true; } + mRunning = true; try { setupNetlinkSocket(); } catch (ErrnoException | SocketException e) { Log.e(TAG, "Failed to suitably initialize a netlink socket", e); - synchronized (mLock) { mRunning = false; } + mRunning = false; } - ByteBuffer byteBuffer; - while (stillRunning()) { + while (mRunning) { + final ByteBuffer byteBuffer; try { byteBuffer = recvKernelReply(); } catch (ErrnoException e) { - if (stillRunning()) { Log.w(TAG, "ErrnoException: ", e); } + if (mRunning) { Log.w(TAG, "ErrnoException: ", e); } break; } final long whenMs = SystemClock.elapsedRealtime(); @@ -477,7 +470,7 @@ public class IpReachabilityMonitor { clearNetlinkSocket(); - synchronized (mLock) { mRunning = false; } + mRunning = false; // Not a no-op when ErrnoException happened. if (VDBG) { Log.d(TAG, "Finishing observing thread."); } } From dafc44ea11972b3152e67dc305a98d658f1465ba Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Mon, 17 Oct 2016 14:21:33 +0900 Subject: [PATCH 06/14] DO NOT MERGE: ApfFilter: use elapsedRealTime for RA lifetime This patch replaces System.currentTimeMillis() with SystemClock.elapsedRealTime() to make RA lifetime computation more resilient to various external events inducing jumps in currentTimeMillis(). Test: ApfTest passes. (cherry picked from commit 305af8e98a4fce712c1a93daf3b050dac2e8b91a) Change-Id: If19011fc0c905948f2e42b975cfcc5f8672a95fb --- services/net/java/android/net/apf/ApfFilter.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java index 18d69eca64329..a8356dc4658e7 100644 --- a/services/net/java/android/net/apf/ApfFilter.java +++ b/services/net/java/android/net/apf/ApfFilter.java @@ -283,10 +283,9 @@ public class ApfFilter { mReceiveThread.start(); } - // Returns seconds since Unix Epoch. - // TODO: use SystemClock.elapsedRealtime() instead + // Returns seconds since device boot. private static long curTime() { - return System.currentTimeMillis() / DateUtils.SECOND_IN_MILLIS; + return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS; } public static class InvalidRaException extends Exception { From 1f64f3fd14caca5ace9bfdbb036e3711d5484de3 Mon Sep 17 00:00:00 2001 From: Calvin On Date: Tue, 11 Oct 2016 15:10:46 -0700 Subject: [PATCH 07/14] DO NOT MERGE: Add option to skip and avoid captive portals. Test: ConnectivityServiceTest updated with test cases. Test: Manually tested against att-wifi in B42. Bug: 30222699 (cherry picked from commit be96da11ccb5dd500f920c3ba90d350857293b3d) Change-Id: I90c0f97fe0e41de4059bceae7b56ab3a70145696 --- core/java/android/provider/Settings.java | 38 ++++++++++- .../android/server/ConnectivityService.java | 16 ++++- .../server/connectivity/NetworkMonitor.java | 12 +++- .../server/ConnectivityServiceTest.java | 65 +++++++++++++++++-- 4 files changed, 120 insertions(+), 11 deletions(-) diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ea0f6b6785d18..1a8ba74556406 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8024,11 +8024,45 @@ public final class Settings { public static final String PAC_CHANGE_DELAY = "pac_change_delay"; /** - * Setting to turn off captive portal detection. Feature is enabled by - * default and the setting needs to be set to 0 to disable it. + * Don't attempt to detect captive portals. * * @hide */ + public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; + + /** + * When detecting a captive portal, display a notification that + * prompts the user to sign in. + * + * @hide + */ + public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; + + /** + * When detecting a captive portal, immediately disconnect from the + * network and do not reconnect to that network in the future. + * + * @hide + */ + public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; + + /** + * What to do when connecting a network that presents a captive portal. + * Must be one of the CAPTIVE_PORTAL_MODE_* constants above. + * + * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT. + * @hide + */ + public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode"; + + /** + * Setting to turn off captive portal detection. Feature is enabled by + * default and the setting needs to be set to 0 to disable it. + * + * @deprecated use CAPTIVE_PORTAL_MODE_IGNORE to disable captive portal detection + * @hide + */ + @Deprecated public static final String CAPTIVE_PORTAL_DETECTION_ENABLED = "captive_portal_detection_enabled"; diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 17a147614e9f3..ca9a2290249a9 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2266,11 +2266,19 @@ public class ConnectivityService extends IConnectivityManager.Stub synchronized (mNetworkForNetId) { nai = mNetworkForNetId.get(netId); } - // If captive portal status has changed, update capabilities. + // If captive portal status has changed, update capabilities or disconnect. if (nai != null && (visible != nai.lastCaptivePortalDetected)) { final int oldScore = nai.getCurrentScore(); nai.lastCaptivePortalDetected = visible; nai.everCaptivePortalDetected |= visible; + if (nai.lastCaptivePortalDetected && + Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) { + if (DBG) log("Avoiding captive portal network: " + nai.name()); + nai.asyncChannel.sendMessage( + NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT); + teardownUnneededNetwork(nai); + break; + } updateCapabilities(oldScore, nai, nai.networkCapabilities); } if (!visible) { @@ -2291,6 +2299,12 @@ public class ConnectivityService extends IConnectivityManager.Stub return true; } + private int getCaptivePortalMode() { + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.CAPTIVE_PORTAL_MODE, + Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); + } + private boolean maybeHandleNetworkAgentInfoMessage(Message msg) { switch (msg.what) { default: diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index 6eb89facca76d..c73d1dd954375 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -211,7 +211,9 @@ public class NetworkMonitor extends StateMachine { private final NetworkRequest mDefaultRequest; private final IpConnectivityLog mMetricsLog; - private boolean mIsCaptivePortalCheckEnabled; + @VisibleForTesting + protected boolean mIsCaptivePortalCheckEnabled; + private boolean mUseHttps; // Set if the user explicitly selected "Do not use this network" in captive portal sign-in app. @@ -265,7 +267,8 @@ public class NetworkMonitor extends StateMachine { setInitialState(mDefaultState); mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1; + Settings.Global.CAPTIVE_PORTAL_MODE, Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT) + != Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE; mUseHttps = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.CAPTIVE_PORTAL_USE_HTTPS, 1) == 1; @@ -632,7 +635,10 @@ public class NetworkMonitor extends StateMachine { @VisibleForTesting protected CaptivePortalProbeResult isCaptivePortal() { - if (!mIsCaptivePortalCheckEnabled) return new CaptivePortalProbeResult(204); + if (!mIsCaptivePortalCheckEnabled) { + validationLog("Validation disabled."); + return new CaptivePortalProbeResult(204); + } URL pacUrl = null, httpsUrl = null, httpUrl = null, fallbackUrl = null; diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 0f180af2bd1fe..a921e8acaf8ec 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -236,6 +236,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { private final IdleableHandlerThread mHandlerThread; private final ConditionVariable mDisconnected = new ConditionVariable(); private final ConditionVariable mNetworkStatusReceived = new ConditionVariable(); + private final ConditionVariable mPreventReconnectReceived = new ConditionVariable(); private int mScore; private NetworkAgent mNetworkAgent; private int mStartKeepaliveError = PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED; @@ -291,6 +292,11 @@ public class ConnectivityServiceTest extends AndroidTestCase { mRedirectUrl = redirectUrl; mNetworkStatusReceived.open(); } + + @Override + protected void preventAutomaticReconnect() { + mPreventReconnectReceived.open(); + } }; // Waits for the NetworkAgent to be registered, which includes the creation of the // NetworkMonitor. @@ -375,11 +381,6 @@ public class ConnectivityServiceTest extends AndroidTestCase { mWrappedNetworkMonitor.gen204ProbeResult = 200; mWrappedNetworkMonitor.gen204ProbeRedirectUrl = redirectUrl; connect(false); - waitFor(new Criteria() { public boolean get() { - NetworkCapabilities caps = mCm.getNetworkCapabilities(getNetwork()); - return caps != null && caps.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL);} }); - mWrappedNetworkMonitor.gen204ProbeResult = 500; - mWrappedNetworkMonitor.gen204ProbeRedirectUrl = null; } public void disconnect() { @@ -391,6 +392,10 @@ public class ConnectivityServiceTest extends AndroidTestCase { return new Network(mNetworkAgent.netId); } + public ConditionVariable getPreventReconnectReceived() { + return mPreventReconnectReceived; + } + public ConditionVariable getDisconnectedCV() { return mDisconnected; } @@ -597,6 +602,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { @Override protected CaptivePortalProbeResult isCaptivePortal() { + if (!mIsCaptivePortalCheckEnabled) { return new CaptivePortalProbeResult(204); } return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl, null); } } @@ -743,6 +749,9 @@ public class ConnectivityServiceTest extends AndroidTestCase { mService.systemReady(); mCm = new WrappedConnectivityManager(getContext(), mService); mCm.bindProcessToNetwork(null); + + // Ensure that the default setting for Captive Portals is used for most tests + setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); } public void tearDown() throws Exception { @@ -1710,6 +1719,47 @@ public class ConnectivityServiceTest extends AndroidTestCase { validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); } + @LargeTest + public void testAvoidOrIgnoreCaptivePortals() { + final TestNetworkCallback captivePortalCallback = new TestNetworkCallback(); + final NetworkRequest captivePortalRequest = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build(); + mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback); + + final TestNetworkCallback validatedCallback = new TestNetworkCallback(); + final NetworkRequest validatedRequest = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_VALIDATED).build(); + mCm.registerNetworkCallback(validatedRequest, validatedCallback); + + setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_AVOID); + // Bring up a network with a captive portal. + // Expect it to fail to connect and not result in any callbacks. + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + String firstRedirectUrl = "http://example.com/firstPath"; + + ConditionVariable disconnectCv = mWiFiNetworkAgent.getDisconnectedCV(); + ConditionVariable avoidCv = mWiFiNetworkAgent.getPreventReconnectReceived(); + mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl); + waitFor(disconnectCv); + waitFor(avoidCv); + + assertNoCallbacks(captivePortalCallback, validatedCallback); + + // Now test ignore mode. + setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE); + + // Bring up a network with a captive portal. + // Since we're ignoring captive portals, the network will validate. + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + String secondRedirectUrl = "http://example.com/secondPath"; + mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl); + + // Expect NET_CAPABILITY_VALIDATED onAvailable callback. + validatedCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent); + // But there should be no CaptivePortal callback. + captivePortalCallback.assertNoCallback(); + } + @SmallTest public void testInvalidNetworkSpecifier() { boolean execptionCalled = true; @@ -1850,6 +1900,11 @@ public class ConnectivityServiceTest extends AndroidTestCase { mCm.unregisterNetworkCallback(cellNetworkCallback); } + private void setCaptivePortalMode(int mode) { + ContentResolver cr = mServiceContext.getContentResolver(); + Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, mode); + } + private void setMobileDataAlwaysOn(boolean enable) { ContentResolver cr = mServiceContext.getContentResolver(); Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0); From 5d540d141027d818d1beb8b030d35ee9489b2e8a Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Mon, 17 Oct 2016 15:54:51 +0900 Subject: [PATCH 08/14] DO NOT MERGE: ConnectivityServiceTest: mark flaky test as such This patch extracts into its own independent test a test sub-block looking for a race condition when not waiting on handlers to become idle: there is no way to prevent the race from not happening when looking for it this way. This makes the test flakky. This new independent test is tagged with @FlakkyTest(tolerance = 3). Test: ConnectivityServiceTest passes, with higher probability. Bug: 31479480 (cherry picked from commit c8c1027762d66c12c9c153ccbb8f80acdee8571c) Change-Id: I3c702bd981ed80ed606be0fb52d61eb3d7195a6f --- .../com/android/server/ConnectivityServiceTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index a921e8acaf8ec..826aeeb528839 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -68,6 +68,7 @@ import android.os.Process; import android.os.SystemClock; import android.provider.Settings; import android.test.AndroidTestCase; +import android.test.FlakyTest; import android.test.mock.MockContentResolver; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.SmallTest; @@ -215,8 +216,20 @@ public class ConnectivityServiceTest extends AndroidTestCase { mService.waitForIdle(); assertEquals(i, mCm.getNetworkCapabilities(n).getSignalStrength()); } + } + + @FlakyTest(tolerance = 3) + public void testNotWaitingForIdleCausesRaceConditions() { + // Bring up a network that we can use to send messages to ConnectivityService. + ConditionVariable cv = waitForConnectivityBroadcasts(1); + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(false); + waitFor(cv); + Network n = mWiFiNetworkAgent.getNetwork(); + assertNotNull(n); // Ensure that not calling waitForIdle causes a race condition. + final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng. for (int i = 0; i < attempts; i++) { mWiFiNetworkAgent.setSignalStrength(i); if (i != mCm.getNetworkCapabilities(n).getSignalStrength()) { From b8df76e413d0b8235d0bd71adf8f368f00391fcb Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 28 Oct 2016 12:37:38 +0900 Subject: [PATCH 09/14] DO NOT MERGE: Move FakeSettingsProvider to a common location. (cherry picked from commit 7df1a82802cdf842d07a86a80383c7d5ea7ae53a) Test: runtest frameworks-util -c com.android.internal.util.test.FakeSettingsProviderTest Test: runtest frameworks-services -c com.android.server.ConnectivityServiceTest Test: runtest frameworks-services -c com.android.server.retaildemo.PreloadAppsInstallerTest Test: runtest frameworks-services -c com.android.server.retaildemo.RetailDemoModeServiceTest Bug: 31479480 Change-Id: I8d4d4de2937012dd33924f53e68f96241a9b2b4f --- core/tests/utiltests/Android.mk | 1 + .../android/internal/util/test}/FakeSettingsProviderTest.java | 2 +- .../src/com/android/server/ConnectivityServiceTest.java | 2 +- tests/utils/testutils/Android.mk | 2 ++ .../com/android/internal/util/test}/FakeSettingsProvider.java | 2 +- 5 files changed, 6 insertions(+), 3 deletions(-) rename {services/tests/servicestests/src/com/android/internal/util => core/tests/utiltests/src/com/android/internal/util/test}/FakeSettingsProviderTest.java (98%) rename {services/tests/servicestests/src/com/android/internal/util => tests/utils/testutils/java/com/android/internal/util/test}/FakeSettingsProvider.java (99%) diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk index 6d1ebb4a6f58a..981be112a22d5 100644 --- a/core/tests/utiltests/Android.mk +++ b/core/tests/utiltests/Android.mk @@ -14,6 +14,7 @@ LOCAL_SRC_FILES += src/android/util/IRemoteMemoryIntArray.aidl LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test \ + frameworks-base-testutils \ mockito-target LOCAL_JAVA_LIBRARIES := android.test.runner diff --git a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java b/core/tests/utiltests/src/com/android/internal/util/test/FakeSettingsProviderTest.java similarity index 98% rename from services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java rename to core/tests/utiltests/src/com/android/internal/util/test/FakeSettingsProviderTest.java index 05de0a53e0550..f2be109c86026 100644 --- a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java +++ b/core/tests/utiltests/src/com/android/internal/util/test/FakeSettingsProviderTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.util; +package com.android.internal.util.test; import android.content.ContentResolver; import android.database.ContentObserver; diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 826aeeb528839..5160b951c2b29 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -75,8 +75,8 @@ import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; import android.util.LogPrinter; -import com.android.internal.util.FakeSettingsProvider; import com.android.internal.util.WakeupMessage; +import com.android.internal.util.test.FakeSettingsProvider; import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkMonitor; import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult; diff --git a/tests/utils/testutils/Android.mk b/tests/utils/testutils/Android.mk index d53167f19ebe6..acbe4bcb235b7 100644 --- a/tests/utils/testutils/Android.mk +++ b/tests/utils/testutils/Android.mk @@ -27,4 +27,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test \ mockito-target +LOCAL_JAVA_LIBRARIES := android.test.runner + include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProvider.java b/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProvider.java similarity index 99% rename from services/tests/servicestests/src/com/android/internal/util/FakeSettingsProvider.java rename to tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProvider.java index 808f4dd7b84ef..8ca849b8d37ee 100644 --- a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProvider.java +++ b/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProvider.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.util; +package com.android.internal.util.test; import android.net.Uri; import android.os.Bundle; From 3c295b59f5767904656235db48692906148ab631 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 28 Oct 2016 12:56:03 +0900 Subject: [PATCH 10/14] DO NOT MERGE: De-guava BroadcastInterceptingContext and move it to testutils. Removing the static dependency on guava reduces test compile time by about 20 seconds on a Z840, thus substantially speeding up the compile/test cycle. Make FutureIntent public instead of package-private because it is used directly by NetworkPolicyManagementServiceTest, which as of this CL is now in a different package. (cherry picked from commit 281a17c9580de5c9898be7d9654d428801976511) Test: runtest frameworks-services -c com.android.server.ConnectivityServiceTest # PASS Test: runtest frameworks-services -c com.android.server.NetworkPolicyManagerServiceTest # PASS Test: runtest frameworks-services -c com.android.server.net.NetworkStatsServiceTest # PASS Test: runtest frameworks-services -c com.android.server.NetworkManagementServiceTest # Already failing. Bug: 31479480 Change-Id: Ifab32c9214e9caab71dbf93b3d3ca88df6f49636 --- .../server/ConnectivityServiceTest.java | 1 + .../server/NetworkManagementServiceTest.java | 1 + .../NetworkPolicyManagerServiceTest.java | 1 + .../server/net/NetworkStatsServiceTest.java | 2 +- .../test}/BroadcastInterceptingContext.java | 23 ++++++++++++------- 5 files changed, 19 insertions(+), 9 deletions(-) rename {services/tests/servicestests/src/com/android/server => tests/utils/testutils/java/com/android/internal/util/test}/BroadcastInterceptingContext.java (89%) diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 5160b951c2b29..885e8a74b2907 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -76,6 +76,7 @@ import android.util.Log; import android.util.LogPrinter; import com.android.internal.util.WakeupMessage; +import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkMonitor; diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java index 0d5daa5def975..f841bf9bff229 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java @@ -24,6 +24,7 @@ import android.os.Binder; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import com.android.server.net.BaseNetworkObserver; +import com.android.internal.util.test.BroadcastInterceptingContext; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index 541be3dad376c..8d36ac993e527 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -78,6 +78,7 @@ import android.test.suitebuilder.annotation.Suppress; import android.text.format.Time; import android.util.TrustedTime; +import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.server.net.NetworkPolicyManagerService; import com.google.common.util.concurrent.AbstractFuture; diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java index 94c6711da9ae0..4b69eb3ac35b3 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java @@ -88,7 +88,7 @@ import android.test.suitebuilder.annotation.Suppress; import android.util.TrustedTime; import com.android.internal.net.VpnInfo; -import com.android.server.BroadcastInterceptingContext; +import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.server.net.NetworkStatsService; import com.android.server.net.NetworkStatsService.NetworkStatsSettings; import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config; diff --git a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java similarity index 89% rename from services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java rename to tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java index 13657ab7f02d6..27b7419f227a3 100644 --- a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java +++ b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.internal.util.test; import android.content.BroadcastReceiver; import android.content.Context; @@ -25,13 +25,12 @@ import android.os.Bundle; import android.os.Handler; import android.os.UserHandle; -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.AbstractFuture; - +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -42,9 +41,17 @@ import java.util.concurrent.TimeoutException; public class BroadcastInterceptingContext extends ContextWrapper { private static final String TAG = "WatchingContext"; - private final List mInterceptors = Lists.newArrayList(); + private final List mInterceptors = new ArrayList<>(); - public class BroadcastInterceptor extends AbstractFuture { + public abstract class FutureIntent extends FutureTask { + public FutureIntent() { + super( + () -> { throw new IllegalStateException("Cannot happen"); } + ); + } + } + + public class BroadcastInterceptor extends FutureIntent { private final BroadcastReceiver mReceiver; private final IntentFilter mFilter; @@ -82,11 +89,11 @@ public class BroadcastInterceptingContext extends ContextWrapper { super(base); } - public Future nextBroadcastIntent(String action) { + public FutureIntent nextBroadcastIntent(String action) { return nextBroadcastIntent(new IntentFilter(action)); } - public Future nextBroadcastIntent(IntentFilter filter) { + public FutureIntent nextBroadcastIntent(IntentFilter filter) { final BroadcastInterceptor interceptor = new BroadcastInterceptor(null, filter); synchronized (mInterceptors) { mInterceptors.add(interceptor); From 7ceef950a02b22bdf90609bdab8119b4bcd88edf Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 28 Oct 2016 12:48:36 +0900 Subject: [PATCH 11/14] DO NOT MERGE: Move the connectivity tests to frameworks/base/tests/net. This will give us a good place to put all the networking tests. Fix: 31479480 Test: adb shell am instrument -w -e notClass com.android.server.connectivity.tethering.TetherInterfaceStateMachineTest 'com.android.frameworks.tests.net/android.support.test.runner.AndroidJUnitRunner' # PASS (cherry picked from commit ecc986d430f4b8158f177ed97d2edb741f11ff71) Change-Id: I993eeaa5dec001c39389023f355f506129b356e7 --- tests/net/Android.mk | 80 ++++++++++++++++++ tests/net/AndroidManifest.xml | 57 +++++++++++++ .../net/ConnectivityMetricsLoggerTest.java | 0 .../net/java}/android/net/UidRangeTest.java | 2 +- .../net/java}/android/net/apf/ApfTest.java | 4 +- .../net/java}/android/net/apf/Bpf2Apf.java | 0 .../android/net/dhcp/DhcpPacketTest.java | 0 .../net/netlink/NetlinkErrorMessageTest.java | 0 .../net/netlink/NetlinkSocketTest.java | 0 .../netlink/RtNetlinkNeighborMessageTest.java | 0 .../java}/android/net/util/IpUtilsTest.java | 0 .../server/ConnectivityServiceTest.java | 0 .../IpConnectivityEventBuilderTest.java | 0 .../IpConnectivityMetricsTest.java | 0 .../connectivity/LingerMonitorTest.java | 0 .../MetricsLoggerServiceTest.java | 0 .../server/connectivity/MetricsTestUtil.java | 0 .../NetdEventListenerServiceTest.java | 0 .../server/connectivity/TetheringTest.java | 0 .../android/server/connectivity/VpnTest.java | 0 .../TetherInterfaceStateMachineTest.java | 0 .../net}/jni/UidRangeTest.cpp | 0 .../net}/jni/UidRangeTest.h | 0 .../net}/jni/apf_jni.cpp | 0 .../net}/res/raw/apf.pcap | Bin 25 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 tests/net/Android.mk create mode 100644 tests/net/AndroidManifest.xml rename {services/tests/servicestests/src => tests/net/java}/android/net/ConnectivityMetricsLoggerTest.java (100%) rename {services/tests/servicestests/src => tests/net/java}/android/net/UidRangeTest.java (98%) rename {services/tests/servicestests/src => tests/net/java}/android/net/apf/ApfTest.java (99%) rename {services/tests/servicestests/src => tests/net/java}/android/net/apf/Bpf2Apf.java (100%) rename {services/tests/servicestests/src => tests/net/java}/android/net/dhcp/DhcpPacketTest.java (100%) rename {services/tests/servicestests/src => tests/net/java}/android/net/netlink/NetlinkErrorMessageTest.java (100%) rename {services/tests/servicestests/src => tests/net/java}/android/net/netlink/NetlinkSocketTest.java (100%) rename {services/tests/servicestests/src => tests/net/java}/android/net/netlink/RtNetlinkNeighborMessageTest.java (100%) rename {services/tests/servicestests/src => tests/net/java}/android/net/util/IpUtilsTest.java (100%) rename {services/tests/servicestests/src => tests/net/java}/com/android/server/ConnectivityServiceTest.java (100%) rename {services/tests/servicestests/src => tests/net/java}/com/android/server/connectivity/IpConnectivityEventBuilderTest.java (100%) rename {services/tests/servicestests/src => tests/net/java}/com/android/server/connectivity/IpConnectivityMetricsTest.java (100%) rename {services/tests/servicestests/src => tests/net/java}/com/android/server/connectivity/LingerMonitorTest.java (100%) rename {services/tests/servicestests/src => tests/net/java}/com/android/server/connectivity/MetricsLoggerServiceTest.java (100%) rename {services/tests/servicestests/src => tests/net/java}/com/android/server/connectivity/MetricsTestUtil.java (100%) rename {services/tests/servicestests/src => tests/net/java}/com/android/server/connectivity/NetdEventListenerServiceTest.java (100%) rename {services/tests/servicestests/src => tests/net/java}/com/android/server/connectivity/TetheringTest.java (100%) rename {services/tests/servicestests/src => tests/net/java}/com/android/server/connectivity/VpnTest.java (100%) rename {services/tests/servicestests/src => tests/net/java}/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java (100%) rename {services/tests/servicestests => tests/net}/jni/UidRangeTest.cpp (100%) rename {services/tests/servicestests => tests/net}/jni/UidRangeTest.h (100%) rename {services/tests/servicestests => tests/net}/jni/apf_jni.cpp (100%) rename {services/tests/servicestests => tests/net}/res/raw/apf.pcap (100%) diff --git a/tests/net/Android.mk b/tests/net/Android.mk new file mode 100644 index 0000000000000..8aa27a9559b88 --- /dev/null +++ b/tests/net/Android.mk @@ -0,0 +1,80 @@ +######################################################################### +# Build FrameworksNetTests package +######################################################################### + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# We only want this apk build for tests. +LOCAL_MODULE_TAGS := tests + +# Include all test java files. +LOCAL_SRC_FILES := $(call all-java-files-under, java) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + frameworks-base-testutils \ + framework-protos \ + android-support-test \ + mockito-target-minus-junit4 \ + platform-test-annotations \ + services.core \ + services.net + +LOCAL_JAVA_LIBRARIES := \ + android.test.runner + +LOCAL_PACKAGE_NAME := FrameworksNetTests + +LOCAL_CERTIFICATE := platform + +# These are not normally accessible from apps so they must be explicitly included. +LOCAL_JNI_SHARED_LIBRARIES := libframeworksnettestsjni \ + libbacktrace \ + libbase \ + libbinder \ + libc++ \ + libcutils \ + liblog \ + liblzma \ + libnativehelper \ + libnetdaidl \ + libui \ + libunwind \ + libutils + +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk + +include $(BUILD_PACKAGE) + +######################################################################### +# Build JNI Shared Library +######################################################################### + +LOCAL_PATH:= $(LOCAL_PATH)/jni + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_CFLAGS := -Wall -Wextra -Werror + +LOCAL_C_INCLUDES := \ + libpcap \ + hardware/google/apf + +LOCAL_SRC_FILES := $(call all-cpp-files-under) + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + liblog \ + libcutils \ + libnativehelper \ + libnetdaidl + +LOCAL_STATIC_LIBRARIES := \ + libpcap \ + libapf + +LOCAL_MODULE := libframeworksnettestsjni + +include $(BUILD_SHARED_LIBRARY) diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml new file mode 100644 index 0000000000000..e069dd052d82c --- /dev/null +++ b/tests/net/AndroidManifest.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/src/android/net/ConnectivityMetricsLoggerTest.java b/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java similarity index 100% rename from services/tests/servicestests/src/android/net/ConnectivityMetricsLoggerTest.java rename to tests/net/java/android/net/ConnectivityMetricsLoggerTest.java diff --git a/services/tests/servicestests/src/android/net/UidRangeTest.java b/tests/net/java/android/net/UidRangeTest.java similarity index 98% rename from services/tests/servicestests/src/android/net/UidRangeTest.java rename to tests/net/java/android/net/UidRangeTest.java index 221fe0f99f0bc..0a56e1be6cae5 100644 --- a/services/tests/servicestests/src/android/net/UidRangeTest.java +++ b/tests/net/java/android/net/UidRangeTest.java @@ -26,7 +26,7 @@ import static org.junit.Assert.assertArrayEquals; public class UidRangeTest extends TestCase { static { - System.loadLibrary("servicestestsjni"); + System.loadLibrary("frameworksnettestsjni"); } private static native byte[] readAndWriteNative(byte[] inParcel); diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java similarity index 99% rename from services/tests/servicestests/src/android/net/apf/ApfTest.java rename to tests/net/java/android/net/apf/ApfTest.java index 37807b22264a6..b7ec00460ae63 100644 --- a/services/tests/servicestests/src/android/net/apf/ApfTest.java +++ b/tests/net/java/android/net/apf/ApfTest.java @@ -35,7 +35,7 @@ import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import static android.system.OsConstants.*; -import com.android.frameworks.servicestests.R; +import com.android.frameworks.tests.net.R; import com.android.internal.util.HexDump; import org.mockito.ArgumentCaptor; @@ -75,7 +75,7 @@ public class ApfTest extends AndroidTestCase { super.setUp(); MockitoAnnotations.initMocks(this); // Load up native shared library containing APF interpreter exposed via JNI. - System.loadLibrary("servicestestsjni"); + System.loadLibrary("frameworksnettestsjni"); } // Expected return codes from APF interpreter. diff --git a/services/tests/servicestests/src/android/net/apf/Bpf2Apf.java b/tests/net/java/android/net/apf/Bpf2Apf.java similarity index 100% rename from services/tests/servicestests/src/android/net/apf/Bpf2Apf.java rename to tests/net/java/android/net/apf/Bpf2Apf.java diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/tests/net/java/android/net/dhcp/DhcpPacketTest.java similarity index 100% rename from services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java rename to tests/net/java/android/net/dhcp/DhcpPacketTest.java diff --git a/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java b/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java similarity index 100% rename from services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java rename to tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java diff --git a/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java b/tests/net/java/android/net/netlink/NetlinkSocketTest.java similarity index 100% rename from services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java rename to tests/net/java/android/net/netlink/NetlinkSocketTest.java diff --git a/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java b/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java similarity index 100% rename from services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java rename to tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java diff --git a/services/tests/servicestests/src/android/net/util/IpUtilsTest.java b/tests/net/java/android/net/util/IpUtilsTest.java similarity index 100% rename from services/tests/servicestests/src/android/net/util/IpUtilsTest.java rename to tests/net/java/android/net/util/IpUtilsTest.java diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java similarity index 100% rename from services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java rename to tests/net/java/com/android/server/ConnectivityServiceTest.java diff --git a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java similarity index 100% rename from services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java rename to tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java diff --git a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java similarity index 100% rename from services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java rename to tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java diff --git a/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java similarity index 100% rename from services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java rename to tests/net/java/com/android/server/connectivity/LingerMonitorTest.java diff --git a/services/tests/servicestests/src/com/android/server/connectivity/MetricsLoggerServiceTest.java b/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java similarity index 100% rename from services/tests/servicestests/src/com/android/server/connectivity/MetricsLoggerServiceTest.java rename to tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java diff --git a/services/tests/servicestests/src/com/android/server/connectivity/MetricsTestUtil.java b/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java similarity index 100% rename from services/tests/servicestests/src/com/android/server/connectivity/MetricsTestUtil.java rename to tests/net/java/com/android/server/connectivity/MetricsTestUtil.java diff --git a/services/tests/servicestests/src/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java similarity index 100% rename from services/tests/servicestests/src/com/android/server/connectivity/NetdEventListenerServiceTest.java rename to tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java diff --git a/services/tests/servicestests/src/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java similarity index 100% rename from services/tests/servicestests/src/com/android/server/connectivity/TetheringTest.java rename to tests/net/java/com/android/server/connectivity/TetheringTest.java diff --git a/services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java similarity index 100% rename from services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java rename to tests/net/java/com/android/server/connectivity/VpnTest.java diff --git a/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java similarity index 100% rename from services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java rename to tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java diff --git a/services/tests/servicestests/jni/UidRangeTest.cpp b/tests/net/jni/UidRangeTest.cpp similarity index 100% rename from services/tests/servicestests/jni/UidRangeTest.cpp rename to tests/net/jni/UidRangeTest.cpp diff --git a/services/tests/servicestests/jni/UidRangeTest.h b/tests/net/jni/UidRangeTest.h similarity index 100% rename from services/tests/servicestests/jni/UidRangeTest.h rename to tests/net/jni/UidRangeTest.h diff --git a/services/tests/servicestests/jni/apf_jni.cpp b/tests/net/jni/apf_jni.cpp similarity index 100% rename from services/tests/servicestests/jni/apf_jni.cpp rename to tests/net/jni/apf_jni.cpp diff --git a/services/tests/servicestests/res/raw/apf.pcap b/tests/net/res/raw/apf.pcap similarity index 100% rename from services/tests/servicestests/res/raw/apf.pcap rename to tests/net/res/raw/apf.pcap From 5bce5a16b17498981253d7a2d1a490667cd71798 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 28 Oct 2016 17:45:55 +0900 Subject: [PATCH 12/14] DO NOT MERGE: Unbreak TetherInterfaceStateMachineTest. This was broken by the implementation of IPv6 tethering, which relies on various private classes which end up calling unmockable final classes like NetworkInterface. Making everything public like this is almost certainly not the best way of fixing this test, but on the other hand there is value to the test continuing to pass. Test: runtest frameworks-net # Everything passes. Test: IPv6 tethering continues to work. (cherry picked from commit 7e0eeca8ba4063d0d35dda9a8dfcc612e45efb87) Change-Id: I8a3cf466871c026f4ae0f5cfa73071338cdf5b7e --- .../java/com/android/server/connectivity/Tethering.java | 4 +++- .../tethering/IPv6TetheringInterfaceServices.java | 4 ++-- .../tethering/TetherInterfaceStateMachine.java | 4 ++-- .../tethering/TetherInterfaceStateMachineTest.java | 8 +++++--- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 0beb227e58253..6d96a1015aa23 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -71,6 +71,7 @@ import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.server.connectivity.tethering.IControlsTethering; import com.android.server.connectivity.tethering.IPv6TetheringCoordinator; +import com.android.server.connectivity.tethering.IPv6TetheringInterfaceServices; import com.android.server.connectivity.tethering.TetherInterfaceStateMachine; import com.android.server.net.BaseNetworkObserver; @@ -1939,7 +1940,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering private void trackNewTetherableInterface(String iface, int interfaceType) { TetherState tetherState; tetherState = new TetherState(new TetherInterfaceStateMachine(iface, mLooper, - interfaceType, mNMService, mStatsService, this)); + interfaceType, mNMService, mStatsService, this, + new IPv6TetheringInterfaceServices(iface, mNMService))); mTetherStates.put(iface, tetherState); tetherState.mStateMachine.start(); } diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java index c2c1a8c5fef7f..dec2f77b64559 100644 --- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java +++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java @@ -45,7 +45,7 @@ import java.util.Objects; /** * @hide */ -class IPv6TetheringInterfaceServices { +public class IPv6TetheringInterfaceServices { private static final String TAG = IPv6TetheringInterfaceServices.class.getSimpleName(); private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64"); private static final int RFC7421_IP_PREFIX_LENGTH = 64; @@ -59,7 +59,7 @@ class IPv6TetheringInterfaceServices { private RouterAdvertisementDaemon mRaDaemon; private RaParams mLastRaParams; - IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) { + public IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) { mIfName = ifname; mNMService = nms; } diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java index 6ca4e271ec55b..37221a971ad19 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java @@ -94,14 +94,14 @@ public class TetherInterfaceStateMachine extends StateMachine { public TetherInterfaceStateMachine(String ifaceName, Looper looper, int interfaceType, INetworkManagementService nMService, INetworkStatsService statsService, - IControlsTethering tetherController) { + IControlsTethering tetherController, IPv6TetheringInterfaceServices ipv6Svc) { super(ifaceName, looper); mNMService = nMService; mStatsService = statsService; mTetherController = tetherController; mIfaceName = ifaceName; mInterfaceType = interfaceType; - mIPv6TetherSvc = new IPv6TetheringInterfaceServices(mIfaceName, mNMService); + mIPv6TetherSvc = ipv6Svc; mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; mInitialState = new InitialState(); diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java index a30b3629d5c43..9f7261dc6019d 100644 --- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java +++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java @@ -59,13 +59,14 @@ public class TetherInterfaceStateMachineTest { @Mock private INetworkStatsService mStatsService; @Mock private IControlsTethering mTetherHelper; @Mock private InterfaceConfiguration mInterfaceConfiguration; + @Mock private IPv6TetheringInterfaceServices mIPv6TetheringInterfaceServices; private final TestLooper mLooper = new TestLooper(); private TetherInterfaceStateMachine mTestedSm; private void initStateMachine(int interfaceType) throws Exception { mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), interfaceType, - mNMService, mStatsService, mTetherHelper); + mNMService, mStatsService, mTetherHelper, mIPv6TetheringInterfaceServices); mTestedSm.start(); // Starting the state machine always puts us in a consistent state and notifies // the test of the world that we've changed from an unknown to available state. @@ -91,7 +92,8 @@ public class TetherInterfaceStateMachineTest { @Test public void startsOutAvailable() { mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), - ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper); + ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper, + mIPv6TetheringInterfaceServices); mTestedSm.start(); mLooper.dispatchAll(); verify(mTetherHelper).notifyInterfaceStateChange( @@ -274,4 +276,4 @@ public class TetherInterfaceStateMachineTest { upstreamIface); mLooper.dispatchAll(); } -} \ No newline at end of file +} From 5d2654124e9e77dbda102a4435595c552cbc8e36 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Wed, 2 Nov 2016 13:43:22 +0900 Subject: [PATCH 13/14] DO NOT MERGE: ApfTest: tag tests with @SmallTest or @MediumTest Test methods not tagged with @{Small,Medium,Large}Test will not appear in the Android Platform Continuous Testing dashboard. Test methods tagged with @LargeTest will not be run in the Android Platform Continuous Testing dashboard. Test: ApfTest passes ($runtest frameworks-net) Bug: 31479480 (cherry picked from commit 4195c28347cc100954f83c3c92b4dde4673f8608) Change-Id: Ia215fc8e2ccc61f6223c24fdf390e1e759de302f --- tests/net/java/android/net/apf/ApfTest.java | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java index b7ec00460ae63..81f66a5bc95af 100644 --- a/tests/net/java/android/net/apf/ApfTest.java +++ b/tests/net/java/android/net/apf/ApfTest.java @@ -32,7 +32,8 @@ import android.os.Parcelable; import android.system.ErrnoException; import android.system.Os; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.MediumTest; import static android.system.OsConstants.*; import com.android.frameworks.tests.net.R; @@ -154,7 +155,7 @@ public class ApfTest extends AndroidTestCase { * generating bytecode for that program and running it through the * interpreter to verify it functions correctly. */ - @LargeTest + @MediumTest public void testApfInstructions() throws IllegalInstructionException { // Empty program should pass because having the program counter reach the // location immediately after the program indicates the packet should be @@ -562,7 +563,7 @@ public class ApfTest extends AndroidTestCase { * Generate some BPF programs, translate them to APF, then run APF and BPF programs * over packet traces and verify both programs filter out the same packets. */ - @LargeTest + @MediumTest public void testApfAgainstBpf() throws Exception { String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53", "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24", @@ -720,7 +721,7 @@ public class ApfTest extends AndroidTestCase { private static final byte[] ANOTHER_IPV4_ADDR = {10, 0, 0, 2}; private static final byte[] IPV4_ANY_HOST_ADDR = {0, 0, 0, 0}; - @LargeTest + @MediumTest public void testApfFilterIPv4() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19); @@ -775,7 +776,7 @@ public class ApfTest extends AndroidTestCase { apfFilter.shutdown(); } - @LargeTest + @MediumTest public void testApfFilterIPv6() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog); @@ -801,7 +802,7 @@ public class ApfTest extends AndroidTestCase { apfFilter.shutdown(); } - @LargeTest + @MediumTest public void testApfFilterMulticast() throws Exception { final byte[] unicastIpv4Addr = {(byte)192,0,2,63}; final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255}; @@ -911,7 +912,7 @@ public class ApfTest extends AndroidTestCase { assertDrop(program, garpReply()); } - @LargeTest + @MediumTest public void testApfFilterArp() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog); @@ -1030,7 +1031,7 @@ public class ApfTest extends AndroidTestCase { ipManagerCallback.assertNoProgramUpdate(); } - @LargeTest + @MediumTest public void testApfFilterRa() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog); @@ -1147,6 +1148,7 @@ public class ApfTest extends AndroidTestCase { buffer.position(original); } + @SmallTest public void testRaParsing() throws Exception { final int maxRandomPacketSize = 512; final Random r = new Random(); @@ -1164,6 +1166,7 @@ public class ApfTest extends AndroidTestCase { } } + @SmallTest public void testRaProcessing() throws Exception { final int maxRandomPacketSize = 512; final Random r = new Random(); @@ -1201,6 +1204,7 @@ public class ApfTest extends AndroidTestCase { private native static boolean compareBpfApf(String filter, String pcap_filename, byte[] apf_program); + @SmallTest public void testBytesToInt() { assertEquals(0x00000000, ApfFilter.bytesToInt(IPV4_ANY_HOST_ADDR)); assertEquals(0xffffffff, ApfFilter.bytesToInt(IPV4_BROADCAST_ADDRESS)); From bf3b1bad15f45033d409669ac20e4b4e597065fd Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Thu, 27 Oct 2016 15:05:50 -0700 Subject: [PATCH 14/14] DO NOT MERGE: [CS] Remove timeout event after first available Guarantees that timeouts are only delivered if a network never becomes available. Once a network is available the timeout is canceled. Bug: 31402633 Test: all timeout related unit tests pass (new one added) (cherry picked from commit 681fcda5896fd6c94f8a543ef9983c0a0644e87e) Change-Id: I7cd3086544c881915fc6dbf14b87a24ab0cd8748 --- .../android/server/ConnectivityService.java | 1 + .../server/ConnectivityServiceTest.java | 47 ++++++++++++++----- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index ca9a2290249a9..090c7444c1e73 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5351,6 +5351,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // notify only this one new request of the current state protected void notifyNetworkCallback(NetworkAgentInfo nai, NetworkRequestInfo nri) { int notifyType = ConnectivityManager.CALLBACK_AVAILABLE; + mHandler.removeMessages(EVENT_TIMEOUT_NETWORK_REQUEST, nri); if (nri.mPendingIntent == null) { callCallbackForRequest(nri, nai, notifyType, 0); } else { diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 885e8a74b2907..fc8cc81332055 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -727,10 +727,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { static private void waitFor(Criteria criteria) { int delays = 0; while (!criteria.get()) { - try { - Thread.sleep(50); - } catch (InterruptedException e) { - } + sleepFor(50); if (++delays == 10) fail(); } } @@ -2312,10 +2309,30 @@ public class ConnectivityServiceTest extends AndroidTestCase { networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent); // pass timeout and validate that UNAVAILABLE is not called - try { - Thread.sleep(15); - } catch (InterruptedException e) { - } + sleepFor(15); + networkCallback.assertNoCallback(); + } + + /** + * Validate that a satisfied network request followed by a disconnected (lost) network does + * not trigger onUnavailable() once the time-out period expires. + */ + @SmallTest + public void testSatisfiedThenLostNetworkRequestDoesNotTriggerOnUnavailable() { + NetworkRequest nr = new NetworkRequest.Builder().addTransportType( + NetworkCapabilities.TRANSPORT_WIFI).build(); + final TestNetworkCallback networkCallback = new TestNetworkCallback(); + mCm.requestNetwork(nr, networkCallback, 500); + + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(false); + networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent); + sleepFor(20); + mWiFiNetworkAgent.disconnect(); + networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); + + // pass timeout and validate that UNAVAILABLE is not called + sleepFor(600); networkCallback.assertNoCallback(); } @@ -2357,10 +2374,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { // pass timeout and validate that no callbacks // Note: doesn't validate that nothing called from CS since even if called the CM already // unregisters the callback and won't pass it through! - try { - Thread.sleep(15); - } catch (InterruptedException e) { - } + sleepFor(15); networkCallback.assertNoCallback(); // create a network satisfying request - validate that request not triggered @@ -2773,4 +2787,13 @@ public class ConnectivityServiceTest extends AndroidTestCase { mCm.unregisterNetworkCallback(pendingIntent); } } + + /* test utilities */ + static private void sleepFor(int ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + } + + } }