From ccb0045f935bc6d8b71c33405e7fa6e22d3cb84d Mon Sep 17 00:00:00 2001 From: Pierre Imai Date: Mon, 8 Feb 2016 16:01:40 +0900 Subject: [PATCH 01/45] 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 4c90794555d62..4cd7d41ca9d23 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1804,11 +1804,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 95be623a270e6baac6125e20736eeaf6052e9738 Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Wed, 25 Nov 2015 12:49:38 +0900 Subject: [PATCH 02/45] 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 4cd7d41ca9d23..64ca629bf0ec6 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2591,14 +2591,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) { @@ -2692,7 +2706,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } } - callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED, 0); + callCallbackForRequest(nri, null, whichCallback, 0); } @Override @@ -2929,6 +2943,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 cb9d9629db9de..c5cca251c8de9 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 } private static class CallbackInfo { @@ -1125,6 +1126,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 */); @@ -2236,6 +2242,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 5cd994ee9c76c0dd1197e51c5faef4c5430335d3 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Thu, 6 Oct 2016 15:19:36 +0900 Subject: [PATCH 03/45] 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 3098e4cc95a2262df63e8e3dd9af42bf334a687d Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Thu, 13 Oct 2016 09:26:01 +0900 Subject: [PATCH 04/45] 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 eaa786958ffc92449a224eaa565d17d88bced615 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Tue, 4 Oct 2016 11:24:12 +0900 Subject: [PATCH 05/45] 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 02bab164b74b3d62e0bb4d975fefac2b3282e338 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Mon, 17 Oct 2016 14:21:33 +0900 Subject: [PATCH 06/45] 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 d2bd69aec05a7030d14921a22d2792fdb7805bec Mon Sep 17 00:00:00 2001 From: Calvin On Date: Tue, 11 Oct 2016 15:10:46 -0700 Subject: [PATCH 07/45] 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 ba1e8d8934ded..d251467f6c6c1 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8049,11 +8049,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 64ca629bf0ec6..eae4bc78226b2 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2257,11 +2257,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) { @@ -2282,6 +2290,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 c5cca251c8de9..c5a5678a52362 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 { @@ -1725,6 +1734,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; @@ -1865,6 +1915,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 a5605c3ede50d2702a3f4d22ffefb10d51171f13 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Mon, 17 Oct 2016 15:54:51 +0900 Subject: [PATCH 08/45] 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 c5a5678a52362..794d028123287 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 c869089383481a676223375ee4ad6a9f6673f955 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 28 Oct 2016 12:37:38 +0900 Subject: [PATCH 09/45] 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 794d028123287..9bf3c2cf5efd4 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 be13a4e57546b..3f2416709389e 100644 --- a/tests/utils/testutils/Android.mk +++ b/tests/utils/testutils/Android.mk @@ -28,4 +28,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ legacy-android-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 adaa65233712507e12dea541cb14aa9b6ed886b9 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 28 Oct 2016 12:56:03 +0900 Subject: [PATCH 10/45] 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 9bf3c2cf5efd4..f95a8c6de58dc 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 1a943a36c085b..aeeca79a8473e 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 47a44ba2b1012d611e2a82bcd7e48892d766b050 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 28 Oct 2016 12:48:36 +0900 Subject: [PATCH 11/45] 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 f537c5eb74bfdd8942dca986e35d46ab2444491d Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 28 Oct 2016 17:45:55 +0900 Subject: [PATCH 12/45] 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 5fc47490eadee..b0e45097aff69 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -75,6 +75,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.TetheringConfiguration; import com.android.server.connectivity.tethering.TetherInterfaceStateMachine; import com.android.server.connectivity.tethering.UpstreamNetworkMonitor; @@ -1645,7 +1646,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 f488ffd3be718682cbd9b41478408b45d9358d84 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Wed, 2 Nov 2016 13:43:22 +0900 Subject: [PATCH 13/45] 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 1256590348b1fc2d74eb38048e37f9742cda18ff Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Thu, 27 Oct 2016 15:05:50 -0700 Subject: [PATCH 14/45] [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 eae4bc78226b2..8c38ed63e6a3c 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5319,6 +5319,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 f95a8c6de58dc..a06577e6dab91 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(); } } @@ -2327,10 +2324,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(); } @@ -2372,10 +2389,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 @@ -2788,4 +2802,13 @@ public class ConnectivityServiceTest extends AndroidTestCase { mCm.unregisterNetworkCallback(pendingIntent); } } + + /* test utilities */ + static private void sleepFor(int ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + } + + } } From d19752c3d0ad4c3a9dbf8c3cccc168ef2b1dde9b Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Thu, 13 Oct 2016 13:16:16 +0900 Subject: [PATCH 15/45] IpConnectivity metrics: add version number This patch adds a version field to ipconnectivity.proto and populates it to 2, which is the logical version number for NYC-MR2. Test: IpConnectivity{EventBuilder,Metrics}Test pass Bug: 32127906 (cherry picked from commit d680d4c856f54bea0c60dea74ba4204822391e49) Change-Id: If8f167c0dc4c1abe0e235e2adfd131168a4ddc52 --- .../IpConnectivityEventBuilder.java | 4 +++ .../connectivity/IpConnectivityMetrics.java | 7 ++++ services/core/proto/ipconnectivity.proto | 13 +++++++- .../IpConnectivityEventBuilderTest.java | 33 ++++++++++++------- .../IpConnectivityMetricsTest.java | 3 +- 5 files changed, 47 insertions(+), 13 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java index f1ef947f34726..f1d01e06911a2 100644 --- a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java +++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java @@ -48,6 +48,10 @@ final public class IpConnectivityEventBuilder { final IpConnectivityLog log = new IpConnectivityLog(); log.events = toProto(events); log.droppedEvents = dropped; + if ((log.events.length > 0) || (dropped > 0)) { + // Only write version number if log has some information at all. + log.version = IpConnectivityMetrics.VERSION; + } return IpConnectivityLog.toByteArray(log); } diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java index 28e724c2a7a1d..85c4303e926d1 100644 --- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java +++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java @@ -40,6 +40,13 @@ final public class IpConnectivityMetrics extends SystemService { private static final String TAG = IpConnectivityMetrics.class.getSimpleName(); private static final boolean DBG = false; + // The logical version numbers of ipconnectivity.proto, corresponding to the + // "version" field of IpConnectivityLog. + private static final int NYC = 0; + private static final int NYC_MR1 = 1; + private static final int NYC_MR2 = 2; + public static final int VERSION = NYC_MR2; + private static final String SERVICE_NAME = IpConnectivityLog.SERVICE_NAME; // Default size of the event buffer. Once the buffer is full, incoming events are dropped. diff --git a/services/core/proto/ipconnectivity.proto b/services/core/proto/ipconnectivity.proto index e0d7f0984eb0d..29b318f5ca892 100644 --- a/services/core/proto/ipconnectivity.proto +++ b/services/core/proto/ipconnectivity.proto @@ -53,6 +53,7 @@ message IpReachabilityEvent { // The event type code of the probe, represented by constants defined in // android.net.metrics.IpReachabilityEvent. + // NUD_FAILED_ORGANIC and PROVISIONING_LOST_ORGANIC recorded since version 1. optional int32 event_type = 2; }; @@ -126,11 +127,12 @@ message DHCPEvent { // Lifetime duration in milliseconds of a DhcpClient state, or transition // time in milliseconds between specific pairs of DhcpClient's states. - // Only populated when state_transition is populated. + // Only populated since version 1, when state_transition is populated. optional int32 duration_ms = 4; } // Represents the generation of an Android Packet Filter program. +// Since version 1. message ApfProgramEvent { // Lifetime of the program in seconds. optional int64 lifetime = 1; @@ -154,6 +156,7 @@ message ApfProgramEvent { // Represents Router Advertisement listening statistics for an interface with // Android Packet Filter enabled. +// Since version 1. message ApfStatistics { // The time interval in milliseconds these stastistics cover. optional int64 duration_ms = 1; @@ -183,6 +186,7 @@ message ApfStatistics { // Represents the reception of a Router Advertisement packet for an interface // with Android Packet Filter enabled. +// Since version 1. message RaEvent { // All lifetime values are expressed in seconds. The default value for an // option lifetime that was not present in the RA option list is -1. @@ -271,4 +275,11 @@ message IpConnectivityLog { // The number of events that had to be dropped due to a full buffer. optional int32 dropped_events = 2; + + // The version number of the metrics events being collected. + // nyc-dev: not populated, implicitly 0 + // nyc-dr1: not populated, implicitly 1 (sailfish and marlin only) + // nyc-mr1: not populated, implicitly 1 + // nyc-mr2: 2 + optional int32 version = 3; }; diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java index aed3635245607..84f0f9040b0c2 100644 --- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java +++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java @@ -71,7 +71,8 @@ public class IpConnectivityEventBuilderTest extends TestCase { " transport_types: 3", " >", " time_ms: 1", - ">"); + ">", + "version: 2"); verifySerialization(want, ev); } @@ -93,7 +94,8 @@ public class IpConnectivityEventBuilderTest extends TestCase { " state_transition: \"SomeState\"", " >", " time_ms: 1", - ">"); + ">", + "version: 2"); verifySerialization(want, ev); } @@ -114,7 +116,8 @@ public class IpConnectivityEventBuilderTest extends TestCase { " state_transition: \"\"", " >", " time_ms: 1", - ">"); + ">", + "version: 2"); verifySerialization(want, ev); } @@ -160,7 +163,8 @@ public class IpConnectivityEventBuilderTest extends TestCase { " return_codes: 178", " >", " time_ms: 1", - ">"); + ">", + "version: 2"); verifySerialization(want, ev); } @@ -181,7 +185,8 @@ public class IpConnectivityEventBuilderTest extends TestCase { " latency_ms: 5678", " >", " time_ms: 1", - ">"); + ">", + "version: 2"); verifySerialization(want, ev); } @@ -200,7 +205,8 @@ public class IpConnectivityEventBuilderTest extends TestCase { " if_name: \"wlan0\"", " >", " time_ms: 1", - ">"); + ">", + "version: 2"); verifySerialization(want, ev); } @@ -223,7 +229,8 @@ public class IpConnectivityEventBuilderTest extends TestCase { " >", " >", " time_ms: 1", - ">"); + ">", + "version: 2"); verifySerialization(want, ev); } @@ -248,7 +255,8 @@ public class IpConnectivityEventBuilderTest extends TestCase { " probe_result: 204", " probe_type: 1", " >", - ">"); + ">", + "version: 2"); verifySerialization(want, ev); } @@ -274,7 +282,8 @@ public class IpConnectivityEventBuilderTest extends TestCase { " program_length: 2048", " >", " time_ms: 1", - ">"); + ">", + "version: 2"); verifySerialization(want, ev); } @@ -305,7 +314,8 @@ public class IpConnectivityEventBuilderTest extends TestCase { " zero_lifetime_ras: 1", " >", " time_ms: 1", - ">"); + ">", + "version: 2"); verifySerialization(want, ev); } @@ -332,7 +342,8 @@ public class IpConnectivityEventBuilderTest extends TestCase { " router_lifetime: 2000", " >", " time_ms: 1", - ">"); + ">", + "version: 2"); verifySerialization(want, ev); } diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java index 3fc89b9ff12d3..8bdc829f7bfa3 100644 --- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java +++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java @@ -204,7 +204,8 @@ public class IpConnectivityMetricsTest extends TestCase { " router_lifetime: 2000", " >", " time_ms: 700", - ">"); + ">", + "version: 2"); verifySerialization(want, getdump("flush")); } From 7e52973f2c0fb739eb530d5be6a885d59904e7b1 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Wed, 19 Oct 2016 13:48:40 +0900 Subject: [PATCH 16/45] Add IP conn metrics to dumpsys and bug reports Test: manually created a bug report and inspected content. (cherry picked from commit 51d14cb60793a9a073b8a29ff7875bb518cd7d54) Change-Id: I9649cc2f9bb7a1975e60baaae55fcdb2a48c3b93 --- .../com/android/server/connectivity/IpConnectivityMetrics.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java index 85c4303e926d1..e176fe1575c10 100644 --- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java +++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java @@ -193,6 +193,7 @@ final public class IpConnectivityMetrics extends SystemService { static final String CMD_FLUSH = "flush"; static final String CMD_LIST = "list"; static final String CMD_STATS = "stats"; + static final String CMD_DUMPSYS = "-a"; // dumpsys.cpp dumps services with "-a" as arguments static final String CMD_DEFAULT = CMD_STATS; @Override @@ -210,6 +211,8 @@ final public class IpConnectivityMetrics extends SystemService { case CMD_FLUSH: cmdFlush(fd, pw, args); return; + case CMD_DUMPSYS: + // Fallthrough to CMD_LIST when dumpsys.cpp dumps services states (bug reports) case CMD_LIST: cmdList(fd, pw, args); return; From 26a2dc528490b49c8407f0bddeb4465da94cb148 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 21 Oct 2016 18:41:25 +0900 Subject: [PATCH 17/45] CaptivePortalLogin: set mixed content policy to compatibility. This makes the policy for mixed HTTP/HTTPS content match Chrome. This allows us to display login pages where unimportant subresources are HTTP. Bug: 32171569 (cherry picked from commit 625166377b2d7c5f09d1e7617b3eac3a464fba53) Change-Id: Ia82958192d978280715442e182c34f9da5c88c66 --- .../android/captiveportallogin/CaptivePortalLoginActivity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java index b58c87a5094d3..bb8eb2cd07977 100644 --- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java +++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java @@ -115,6 +115,7 @@ public class CaptivePortalLoginActivity extends Activity { myWebView.clearCache(true); WebSettings webSettings = myWebView.getSettings(); webSettings.setJavaScriptEnabled(true); + webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE); mWebViewClient = new MyWebViewClient(); myWebView.setWebViewClient(mWebViewClient); myWebView.setWebChromeClient(new MyWebChromeClient()); From 728842ad4722ff25c810766d71ac43b9a75a6692 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Wed, 19 Oct 2016 11:17:28 +0900 Subject: [PATCH 18/45] IpConnectivityMetrics reads buffer size in settings Test: IpConnectivityMetricsTest passes. Also manually changed the new setting and verified the buffer size is as expected after flushing the buffer. Bug: 32198637 (cherry picked from commit 05686dbb6b965eb1a54591d2ed2334337886c6ee) Change-Id: Iefbeac3a688b260fb3f92dfe0bfd9db28e26749d --- core/java/android/provider/Settings.java | 7 ++++++ .../connectivity/IpConnectivityMetrics.java | 24 +++++++++++++++++-- .../IpConnectivityMetricsTest.java | 2 +- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index d251467f6c6c1..b1dcb812f5312 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7173,6 +7173,13 @@ public final class Settings { */ public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on"; + /** + * Size of the event buffer for IP connectivity metrics. + * @hide + */ + public static final String CONNECTIVITY_METRICS_BUFFER_SIZE = + "connectivity_metrics_buffer_size"; + /** {@hide} */ public static final String NETSTATS_ENABLED = "netstats_enabled"; /** {@hide} */ diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java index e176fe1575c10..642f2e01987bf 100644 --- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java +++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java @@ -22,6 +22,7 @@ import android.net.IIpConnectivityMetrics; import android.net.metrics.IpConnectivityLog; import android.os.IBinder; import android.os.Parcelable; +import android.provider.Settings; import android.text.TextUtils; import android.util.Base64; import android.util.Log; @@ -32,6 +33,7 @@ import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.function.ToIntFunction; import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityEvent; @@ -51,6 +53,8 @@ final public class IpConnectivityMetrics extends SystemService { // Default size of the event buffer. Once the buffer is full, incoming events are dropped. private static final int DEFAULT_BUFFER_SIZE = 2000; + // Maximum size of the event buffer. + private static final int MAXIMUM_BUFFER_SIZE = DEFAULT_BUFFER_SIZE * 10; // Lock ensuring that concurrent manipulations of the event buffer are correct. // There are three concurrent operations to synchronize: @@ -70,11 +74,18 @@ final public class IpConnectivityMetrics extends SystemService { @GuardedBy("mLock") private int mCapacity; - public IpConnectivityMetrics(Context ctx) { + private final ToIntFunction mCapacityGetter; + + public IpConnectivityMetrics(Context ctx, ToIntFunction capacityGetter) { super(ctx); + mCapacityGetter = capacityGetter; initBuffer(); } + public IpConnectivityMetrics(Context ctx) { + this(ctx, READ_BUFFER_SIZE); + } + @Override public void onStart() { if (DBG) Log.d(TAG, "onStart"); @@ -93,7 +104,7 @@ final public class IpConnectivityMetrics extends SystemService { @VisibleForTesting public int bufferCapacity() { - return DEFAULT_BUFFER_SIZE; // TODO: read from config + return mCapacityGetter.applyAsInt(getContext()); } private void initBuffer() { @@ -236,4 +247,13 @@ final public class IpConnectivityMetrics extends SystemService { getContext().enforceCallingOrSelfPermission(what, "IpConnectivityMetrics"); } }; + + private static final ToIntFunction READ_BUFFER_SIZE = (ctx) -> { + int size = Settings.Global.getInt(ctx.getContentResolver(), + Settings.Global.CONNECTIVITY_METRICS_BUFFER_SIZE, DEFAULT_BUFFER_SIZE); + if (size <= 0) { + return DEFAULT_BUFFER_SIZE; + } + return Math.min(size, MAXIMUM_BUFFER_SIZE); + }; } diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java index 8bdc829f7bfa3..14b5cbeb9276d 100644 --- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java +++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java @@ -57,7 +57,7 @@ public class IpConnectivityMetricsTest extends TestCase { public void setUp() { MockitoAnnotations.initMocks(this); - mService = new IpConnectivityMetrics(mCtx); + mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000); } public void testLoggingEvents() throws Exception { From 4bee7e4edb3f532f5064ab6378b6a0437f83ea62 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Tue, 18 Oct 2016 08:43:30 +0900 Subject: [PATCH 19/45] TokenBucket for rate-limiting and throttling This patch adds a TokenBucket class that can accumulate and distribute tokens over time. Test: comes with unit tests. Bug: 32198637 (cherry picked from commit 998493f0ee39ae0e9ffdea27f48f1b11b0807fcb) Change-Id: I4012ae6d02f7004bceee9a2ba03914f2a2506031 --- .../android/internal/util/TokenBucket.java | 126 ++++++++++++ .../src/android/util/TokenBucketTest.java | 180 ++++++++++++++++++ 2 files changed, 306 insertions(+) create mode 100644 core/java/com/android/internal/util/TokenBucket.java create mode 100644 core/tests/coretests/src/android/util/TokenBucketTest.java diff --git a/core/java/com/android/internal/util/TokenBucket.java b/core/java/com/android/internal/util/TokenBucket.java new file mode 100644 index 0000000000000..effb82ba7a2d0 --- /dev/null +++ b/core/java/com/android/internal/util/TokenBucket.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +import android.os.SystemClock; + +import static com.android.internal.util.Preconditions.checkArgumentNonnegative; +import static com.android.internal.util.Preconditions.checkArgumentPositive; + +/** + * A class useful for rate-limiting or throttling that stores and distributes tokens. + * + * A TokenBucket starts with a fixed capacity of tokens, an initial amount of tokens, and + * a fixed filling period (in milliseconds). + * + * For every filling period, the bucket gains one token, up to its maximum capacity from + * which point tokens simply overflow and are lost. Tokens can be obtained one by one or n by n. + * + * The available amount of tokens is computed lazily when the bucket state is inspected. + * Therefore it is purely synchronous and does not involve any asynchronous activity. + * It is not synchronized in any way and not a thread-safe object. + */ +public class TokenBucket { + + private final int mFillDelta; // Time in ms it takes to generate one token. + private final int mCapacity; // Maximum number of tokens that can be stored. + private long mLastFill; // Last time in ms the bucket generated tokens. + private int mAvailable; // Current number of available tokens. + + /** + * Create a new TokenBucket. + * @param deltaMs the time in milliseconds it takes to generate a new token. + * Must be strictly positive. + * @param capacity the maximum token capacity. Must be strictly positive. + * @param tokens the starting amount of token. Must be positive or zero. + */ + public TokenBucket(int deltaMs, int capacity, int tokens) { + mFillDelta = checkArgumentPositive(deltaMs, "deltaMs must be strictly positive"); + mCapacity = checkArgumentPositive(capacity, "capacity must be strictly positive"); + mAvailable = Math.min(checkArgumentNonnegative(tokens), mCapacity); + mLastFill = scaledTime(); + } + + /** + * Create a new TokenBucket that starts completely filled. + * @param deltaMs the time in milliseconds it takes to generate a new token. + * Must be strictly positive. + * @param capacity the maximum token capacity. Must be strictly positive. + */ + public TokenBucket(int deltaMs, int capacity) { + this(deltaMs, capacity, capacity); + } + + /** Reset this TokenBucket and set its number of available tokens. */ + public void reset(int tokens) { + checkArgumentNonnegative(tokens); + mAvailable = Math.min(tokens, mCapacity); + mLastFill = scaledTime(); + } + + /** Returns this TokenBucket maximum token capacity. */ + public int capacity() { + return mCapacity; + } + + /** Returns this TokenBucket currently number of available tokens. */ + public int available() { + fill(); + return mAvailable; + } + + /** Returns true if this TokenBucket as one or more tokens available. */ + public boolean has() { + fill(); + return mAvailable > 0; + } + + /** Consumes a token from this TokenBucket and returns true if a token is available. */ + public boolean get() { + return (get(1) == 1); + } + + /** + * Try to consume many tokens from this TokenBucket. + * @param n the number of tokens to consume. + * @return the number of tokens that were actually consumed. + */ + public int get(int n) { + fill(); + if (n <= 0) { + return 0; + } + if (n > mAvailable) { + int got = mAvailable; + mAvailable = 0; + return got; + } + mAvailable -= n; + return n; + } + + private void fill() { + final long now = scaledTime(); + final int diff = (int) (now - mLastFill); + mAvailable = Math.min(mCapacity, mAvailable + diff); + mLastFill = now; + } + + private long scaledTime() { + return SystemClock.elapsedRealtime() / mFillDelta; + } +} diff --git a/core/tests/coretests/src/android/util/TokenBucketTest.java b/core/tests/coretests/src/android/util/TokenBucketTest.java new file mode 100644 index 0000000000000..a053ad33f589f --- /dev/null +++ b/core/tests/coretests/src/android/util/TokenBucketTest.java @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +import android.os.SystemClock; +import android.text.format.DateUtils; +import junit.framework.TestCase; + +public class TokenBucketTest extends TestCase { + + static final int FILL_DELTA_VERY_SHORT = 1; + static final int FILL_DELTA_VERY_LONG = Integer.MAX_VALUE; + + public void testArgumentValidation() { + assertThrow(() -> new TokenBucket(0, 1, 1)); + assertThrow(() -> new TokenBucket(1, 0, 1)); + assertThrow(() -> new TokenBucket(1, 1, 0)); + assertThrow(() -> new TokenBucket(0, 1)); + assertThrow(() -> new TokenBucket(1, 0)); + assertThrow(() -> new TokenBucket(-1, 1, 1)); + assertThrow(() -> new TokenBucket(1, -1, 1)); + assertThrow(() -> new TokenBucket(1, 1, -1)); + assertThrow(() -> new TokenBucket(-1, 1)); + assertThrow(() -> new TokenBucket(1, -1)); + + new TokenBucket(1000, 100, 0); + new TokenBucket(1000, 100, 10); + new TokenBucket(5000, 50); + new TokenBucket(5000, 1); + } + + public void testInitialCapacity() { + drain(new TokenBucket(FILL_DELTA_VERY_LONG, 1), 1); + drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10), 10); + drain(new TokenBucket(FILL_DELTA_VERY_LONG, 1000), 1000); + + drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 0), 0); + drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 3), 3); + drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 10), 10); + + drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 100), 10); + + drain(new TokenBucket((int)DateUtils.MINUTE_IN_MILLIS, 50), 50); + drain(new TokenBucket((int)DateUtils.HOUR_IN_MILLIS, 10), 10); + drain(new TokenBucket((int)DateUtils.DAY_IN_MILLIS, 200), 200); + } + + public void testReset() { + TokenBucket tb = new TokenBucket(FILL_DELTA_VERY_LONG, 100, 10); + drain(tb, 10); + + tb.reset(50); + drain(tb, 50); + + tb.reset(50); + getOneByOne(tb, 10); + assertTrue(tb.has()); + + tb.reset(30); + drain(tb, 30); + } + + public void testFill() throws Exception { + int delta = 50; + TokenBucket tb = new TokenBucket(delta, 10, 0); + + assertEmpty(tb); + + Thread.sleep(3 * delta / 2); + + assertTrue(tb.has()); + } + + public void testRefill() throws Exception { + TokenBucket tb = new TokenBucket(FILL_DELTA_VERY_SHORT, 10, 10); + + assertEquals(5, tb.get(5)); + assertEquals(5, tb.get(5)); + + while (tb.available() < 10) { + Thread.sleep(2); + } + + assertEquals(10, tb.get(10)); + + while (tb.available() < 10) { + Thread.sleep(2); + } + + assertEquals(10, tb.get(100)); + } + + public void testAverage() throws Exception { + final int delta = 3; + final int want = 60; + + long start = SystemClock.elapsedRealtime(); + TokenBucket tb = new TokenBucket(delta, 20, 0); + + for (int i = 0; i < want; i++) { + while (!tb.has()) { + Thread.sleep(5 * delta); + } + tb.get(); + } + + assertDuration(want * delta, SystemClock.elapsedRealtime() - start); + } + + public void testBurst() throws Exception { + final int delta = 2; + final int capacity = 20; + final int want = 100; + + long start = SystemClock.elapsedRealtime(); + TokenBucket tb = new TokenBucket(delta, capacity, 0); + + int total = 0; + while (total < want) { + while (!tb.has()) { + Thread.sleep(capacity * delta - 2); + } + total += tb.get(tb.available()); + } + + assertDuration(total * delta, SystemClock.elapsedRealtime() - start); + } + + static void getOneByOne(TokenBucket tb, int n) { + while (n > 0) { + assertTrue(tb.has()); + assertTrue(tb.available() >= n); + assertTrue(tb.get()); + assertTrue(tb.available() >= n - 1); + n--; + } + } + + void assertEmpty(TokenBucket tb) { + assertFalse(tb.has()); + assertEquals(0, tb.available()); + assertFalse(tb.get()); + } + + void drain(TokenBucket tb, int n) { + getOneByOne(tb, n); + assertEmpty(tb); + } + + void assertDuration(long expected, long elapsed) { + String msg = String.format( + "expected elapsed time at least %d ms, but was %d ms", expected, elapsed); + elapsed += 1; // one millisecond extra guard + assertTrue(msg, elapsed >= expected); + } + + void assertThrow(Fn fn) { + try { + fn.call(); + fail("expected n exception to be thrown."); + } catch (Throwable t) {} + } + + interface Fn { void call(); } +} + From a17dabeddee21dd5eae25310ecb755ad8e6f8de6 Mon Sep 17 00:00:00 2001 From: Jeremy Klein Date: Sat, 12 Mar 2016 16:29:54 -0800 Subject: [PATCH 20/45] Add a null check for the OnStartTetheringCallback. This avoids a NullPointerException when trying to call the callback and gives a more readable error message. (cherry picked from commit 5f277e1667b49976a77c9fa79b9a04d775f3b49e) Change-Id: Ia419ff68ef10f308f9e44be47420e27099ee6070 --- core/java/android/net/ConnectivityManager.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 43c8c81da2668..772a2ccc57a56 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -2079,6 +2079,8 @@ public class ConnectivityManager { @SystemApi public void startTethering(int type, boolean showProvisioningUi, final OnStartTetheringCallback callback, Handler handler) { + checkNotNull(callback, "OnStartTetheringCallback cannot be null."); + ResultReceiver wrappedCallback = new ResultReceiver(handler) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { @@ -2089,6 +2091,7 @@ public class ConnectivityManager { } } }; + try { mService.startTethering(type, wrappedCallback, showProvisioningUi); } catch (RemoteException e) { From 092feb5b1c64eec8e62b26fadc0f6fccb33c66a8 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Mon, 18 Apr 2016 16:23:06 -0700 Subject: [PATCH 21/45] Indicate the NsdServiceInfo attributes are only filled in for a resolved service. Fixes: 28530428 (cherry picked from commit 7d5da4b044183826ac8388c8bdb94ac979a81797) Change-Id: If2bfc06589adb361f11b89cd5923cb5c255cb680 --- core/java/android/net/nsd/NsdManager.java | 10 +++++----- core/java/android/net/nsd/NsdServiceInfo.java | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 86bd5028266bc..33d12a3a3fb84 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -103,11 +103,11 @@ import com.android.internal.util.Protocol; * to {@link DiscoveryListener#onServiceFound} and a service lost is notified on * {@link DiscoveryListener#onServiceLost}. * - *

Once the peer application discovers the "Example" http srevice, and needs to receive data - * from the "Example" application, it can initiate a resolve with {@link #resolveService} to - * resolve the host and port details for the purpose of establishing a connection. A successful - * resolve is notified on {@link ResolveListener#onServiceResolved} and a failure is notified - * on {@link ResolveListener#onResolveFailed}. + *

Once the peer application discovers the "Example" http service, and either needs to read the + * attributes of the service or wants to receive data from the "Example" application, it can + * initiate a resolve with {@link #resolveService} to resolve the attributes, host, and port + * details. A successful resolve is notified on {@link ResolveListener#onServiceResolved} and a + * failure is notified on {@link ResolveListener#onResolveFailed}. * * Applications can reserve for a service type at * http://www.iana.org/form/ports-service. Existing services can be found at diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java index 4a06fb1220a71..7b845be749216 100644 --- a/core/java/android/net/nsd/NsdServiceInfo.java +++ b/core/java/android/net/nsd/NsdServiceInfo.java @@ -250,7 +250,8 @@ public final class NsdServiceInfo implements Parcelable { } /** - * Retrive attributes as a map of String keys to byte[] values. + * Retrieve attributes as a map of String keys to byte[] values. The attributes map is only + * valid for a resolved service. * *

The returned map is unmodifiable; changes must be made through {@link #setAttribute} and * {@link #removeAttribute}. From 9c58a11f98ec94895dba8c13d0c2523b400cb5fe Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Wed, 6 Jul 2016 22:53:17 +0900 Subject: [PATCH 22/45] ConnectivityManager: a simpler CallbackHandler This patch simplifies CallbackHandler in the following way: - CallbackHandler directly uses the static references to sNetworkCallback and sCallbackRefCount. This allows to remove instance fields in CallbackHandler. - CallbackHandler does not have a reference to ConnectivityManager anymore - CallbackHandler.getObject() is now generic in a type-safe way. Test: ConnectivityServiceTest passes Bug: 28537383 Bug: 32130437 (cherry picked from commit d42650faaa33ec6274278c65a6042228555ddd4f) Change-Id: I1b5fe2a361b5f623a8310ae698497c83d72f3034 --- .../java/android/net/ConnectivityManager.java | 68 +++++++++---------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 772a2ccc57a56..780a9c8acf30b 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -2690,24 +2690,17 @@ public class ConnectivityManager { } private class CallbackHandler extends Handler { - private final HashMapmCallbackMap; - private final AtomicInteger mRefCount; private static final String TAG = "ConnectivityManager.CallbackHandler"; - private final ConnectivityManager mCm; private static final boolean DBG = false; - CallbackHandler(Looper looper, HashMapcallbackMap, - AtomicInteger refCount, ConnectivityManager cm) { + CallbackHandler(Looper looper) { super(looper); - mCallbackMap = callbackMap; - mRefCount = refCount; - mCm = cm; } @Override public void handleMessage(Message message) { - NetworkRequest request = (NetworkRequest) getObject(message, NetworkRequest.class); - Network network = (Network) getObject(message, Network.class); + NetworkRequest request = getObject(message, NetworkRequest.class); + Network network = getObject(message, Network.class); if (DBG) { Log.d(TAG, whatToString(message.what) + " for network " + network); } @@ -2750,9 +2743,7 @@ public class ConnectivityManager { case CALLBACK_CAP_CHANGED: { NetworkCallback callback = getCallback(request, "CAP_CHANGED"); if (callback != null) { - NetworkCapabilities cap = (NetworkCapabilities)getObject(message, - NetworkCapabilities.class); - + NetworkCapabilities cap = getObject(message, NetworkCapabilities.class); callback.onCapabilitiesChanged(network, cap); } break; @@ -2760,9 +2751,7 @@ public class ConnectivityManager { case CALLBACK_IP_CHANGED: { NetworkCallback callback = getCallback(request, "IP_CHANGED"); if (callback != null) { - LinkProperties lp = (LinkProperties)getObject(message, - LinkProperties.class); - + LinkProperties lp = getObject(message, LinkProperties.class); callback.onLinkPropertiesChanged(network, lp); } break; @@ -2783,12 +2772,12 @@ public class ConnectivityManager { } case CALLBACK_RELEASED: { NetworkCallback callback = null; - synchronized(mCallbackMap) { - callback = mCallbackMap.remove(request); + synchronized(sCallbacks) { + callback = sCallbacks.remove(request); } if (callback != null) { - synchronized(mRefCount) { - if (mRefCount.decrementAndGet() == 0) { + synchronized(sCallbackRefCount) { + if (sCallbackRefCount.decrementAndGet() == 0) { getLooper().quit(); } } @@ -2809,14 +2798,14 @@ public class ConnectivityManager { } } - private Object getObject(Message msg, Class c) { - return msg.getData().getParcelable(c.getSimpleName()); + private T getObject(Message msg, Class c) { + return (T) msg.getData().getParcelable(c.getSimpleName()); } private NetworkCallback getCallback(NetworkRequest req, String name) { NetworkCallback callback; - synchronized(mCallbackMap) { - callback = mCallbackMap.get(req); + synchronized(sCallbacks) { + callback = sCallbacks.get(req); } if (callback == null) { Log.e(TAG, "callback not found for " + name + " message"); @@ -2831,8 +2820,7 @@ public class ConnectivityManager { // TODO: switch this to ConnectivityThread HandlerThread callbackThread = new HandlerThread("ConnectivityManager"); callbackThread.start(); - sCallbackHandler = new CallbackHandler(callbackThread.getLooper(), - sNetworkCallback, sCallbackRefCount, this); + sCallbackHandler = new CallbackHandler(callbackThread.getLooper()); } } } @@ -2846,8 +2834,7 @@ public class ConnectivityManager { } } - static final HashMap sNetworkCallback = - new HashMap(); + static final HashMap sCallbacks = new HashMap<>(); static final AtomicInteger sCallbackRefCount = new AtomicInteger(0); static CallbackHandler sCallbackHandler = null; @@ -2863,25 +2850,32 @@ public class ConnectivityManager { if (need == null && action != REQUEST) { throw new IllegalArgumentException("null NetworkCapabilities"); } + // TODO: throw an exception if networkCallback.networkRequest is not null. + // http://b/20701525 + final NetworkRequest request; try { incCallbackHandlerRefCount(); - synchronized(sNetworkCallback) { + synchronized(sCallbacks) { + Messenger messenger = new Messenger(sCallbackHandler); + Binder binder = new Binder(); if (action == LISTEN) { - networkCallback.networkRequest = mService.listenForNetwork(need, - new Messenger(sCallbackHandler), new Binder()); + request = mService.listenForNetwork(need, messenger, binder); } else { - networkCallback.networkRequest = mService.requestNetwork(need, - new Messenger(sCallbackHandler), timeoutMs, new Binder(), legacyType); + request = mService.requestNetwork( + need, messenger, timeoutMs, binder, legacyType); } - if (networkCallback.networkRequest != null) { - sNetworkCallback.put(networkCallback.networkRequest, networkCallback); + if (request != null) { + sCallbacks.put(request, networkCallback); } + networkCallback.networkRequest = request; } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - if (networkCallback.networkRequest == null) decCallbackHandlerRefCount(); - return networkCallback.networkRequest; + if (request == null) { + decCallbackHandlerRefCount(); + } + return request; } /** From 1e19aefa6f9e2368f34745bc0eb38dc2618e4f06 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Thu, 7 Jul 2016 10:15:56 +0900 Subject: [PATCH 23/45] ConnectivityManager: use ConnectivityThread looper This patch removes the static singleton looper used by ConnectivityManager and instead uses the common ConnectivityThread. This allows to removes the static atomic counter used to track the number of registered NetworkCallback in ConnectivityManager, because the looper is not turned off anymore when no callbacks are registered. Also an overloaded version of sendRequestForNetwork is added taking as a new parameter a Handler. This will allow to overload various callback and request related API calls with user provided Handlers. Test: ConnectivityServiceTest passes Bug: 26749700 Bug: 28537383 Bug: 32130437 (cherry picked from commit 7724cdd8b90006c852644d06cf6c8a28450c71c6) Change-Id: If956addbf8e7b11b36a4b966de7fca00e8f362c1 --- .../java/android/net/ConnectivityManager.java | 59 +++++++------------ 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 780a9c8acf30b..51431ebfaf146 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -2660,6 +2660,7 @@ public class ConnectivityManager { public static final int CALLBACK_IP_CHANGED = BASE + 7; /** @hide */ public static final int CALLBACK_RELEASED = BASE + 8; + // TODO: consider deleting CALLBACK_EXIT and shifting following enum codes down by 1. /** @hide */ public static final int CALLBACK_EXIT = BASE + 9; /** @hide obj = NetworkCapabilities, arg1 = seq number */ @@ -2771,24 +2772,16 @@ public class ConnectivityManager { break; } case CALLBACK_RELEASED: { - NetworkCallback callback = null; + final NetworkCallback callback; synchronized(sCallbacks) { callback = sCallbacks.remove(request); } - if (callback != null) { - synchronized(sCallbackRefCount) { - if (sCallbackRefCount.decrementAndGet() == 0) { - getLooper().quit(); - } - } - } else { + if (callback == null) { Log.e(TAG, "callback not found for RELEASED message"); } break; } case CALLBACK_EXIT: { - Log.d(TAG, "Listener quitting"); - getLooper().quit(); break; } case EXPIRE_LEGACY_REQUEST: { @@ -2814,49 +2807,40 @@ public class ConnectivityManager { } } - private void incCallbackHandlerRefCount() { - synchronized(sCallbackRefCount) { - if (sCallbackRefCount.incrementAndGet() == 1) { - // TODO: switch this to ConnectivityThread - HandlerThread callbackThread = new HandlerThread("ConnectivityManager"); - callbackThread.start(); - sCallbackHandler = new CallbackHandler(callbackThread.getLooper()); - } - } - } - - private void decCallbackHandlerRefCount() { - synchronized(sCallbackRefCount) { - if (sCallbackRefCount.decrementAndGet() == 0) { - sCallbackHandler.obtainMessage(CALLBACK_EXIT).sendToTarget(); - sCallbackHandler = null; + private CallbackHandler getHandler() { + synchronized (sCallbacks) { + if (sCallbackHandler == null) { + sCallbackHandler = new CallbackHandler(ConnectivityThread.getInstanceLooper()); } + return sCallbackHandler; } } static final HashMap sCallbacks = new HashMap<>(); - static final AtomicInteger sCallbackRefCount = new AtomicInteger(0); - static CallbackHandler sCallbackHandler = null; + static CallbackHandler sCallbackHandler; private final static int LISTEN = 1; private final static int REQUEST = 2; private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, - NetworkCallback networkCallback, int timeoutMs, int action, - int legacyType) { - if (networkCallback == null) { + NetworkCallback callback, int timeoutMs, int action, int legacyType) { + return sendRequestForNetwork(need, callback, getHandler(), timeoutMs, action, legacyType); + } + + private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, + NetworkCallback callback, Handler handler, int timeoutMs, int action, int legacyType) { + if (callback == null) { throw new IllegalArgumentException("null NetworkCallback"); } if (need == null && action != REQUEST) { throw new IllegalArgumentException("null NetworkCapabilities"); } - // TODO: throw an exception if networkCallback.networkRequest is not null. + // TODO: throw an exception if callback.networkRequest is not null. // http://b/20701525 final NetworkRequest request; try { - incCallbackHandlerRefCount(); synchronized(sCallbacks) { - Messenger messenger = new Messenger(sCallbackHandler); + Messenger messenger = new Messenger(handler); Binder binder = new Binder(); if (action == LISTEN) { request = mService.listenForNetwork(need, messenger, binder); @@ -2865,16 +2849,13 @@ public class ConnectivityManager { need, messenger, timeoutMs, binder, legacyType); } if (request != null) { - sCallbacks.put(request, networkCallback); + sCallbacks.put(request, callback); } - networkCallback.networkRequest = request; + callback.networkRequest = request; } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - if (request == null) { - decCallbackHandlerRefCount(); - } return request; } From d28766c74d3e5b7a272e3ad40660c46828d0cdf9 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Thu, 13 Oct 2016 16:48:42 +0900 Subject: [PATCH 24/45] ConnectivityThread: use lazy holder idiom This patch changes the way that the ConnectivityThread is lazily instantiated by using the "lazy initialization holder class idiom". The first code point that tries to obtain a reference to the unique ConnectivityThread instance will trigger the creation of the Singleton class, which will guarantee a thread-safe initialization of the static INSTANCE field inside Singleton according to the language specs. This is the Item #71 of Effective Java. The unique static instance of ConnectivityThread is not stored directly inside ConnectivityThread class but is stored in a static nested class. This is to avoid triggering the creation of that unique instance when Zygote does class preloading at phone startup. Otherwise this would lead to Zygote creating a new OS thread during preloading, which is a fatal error. Test: frameworks-wifi tests pass Bug: 26749700 Bug: 28537383 Bug: 32130437 (cherry picked from commit c4fe5d373caa9f53686e4d58e61394dd40558957) Change-Id: If13b363889a8e9396273a90c3d9f9421a48aecbc --- core/java/android/net/ConnectivityThread.java | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/ConnectivityThread.java b/core/java/android/net/ConnectivityThread.java index 55c3402bf39db..0b218e738b779 100644 --- a/core/java/android/net/ConnectivityThread.java +++ b/core/java/android/net/ConnectivityThread.java @@ -27,25 +27,30 @@ import android.os.Looper; * @hide */ public final class ConnectivityThread extends HandlerThread { - private static ConnectivityThread sInstance; + + // A class implementing the lazy holder idiom: the unique static instance + // of ConnectivityThread is instantiated in a thread-safe way (guaranteed by + // the language specs) the first time that Singleton is referenced in get() + // or getInstanceLooper(). + private static class Singleton { + private static final ConnectivityThread INSTANCE = createInstance(); + } private ConnectivityThread() { super("ConnectivityThread"); } - private static synchronized ConnectivityThread getInstance() { - if (sInstance == null) { - sInstance = new ConnectivityThread(); - sInstance.start(); - } - return sInstance; + private static ConnectivityThread createInstance() { + ConnectivityThread t = new ConnectivityThread(); + t.start(); + return t; } public static ConnectivityThread get() { - return getInstance(); + return Singleton.INSTANCE; } public static Looper getInstanceLooper() { - return getInstance().getLooper(); + return Singleton.INSTANCE.getLooper(); } } From fe1ce2f90c8099c5548a580d09ee613dbb2b866a Mon Sep 17 00:00:00 2001 From: Jeremy Joslin Date: Mon, 8 Aug 2016 16:07:37 -0700 Subject: [PATCH 25/45] VPN network stat accounting changes. Properly account for VPN apps that make heavy use of the tun interface. Prior to this change a VPN app could be incorrectly charged for more data than it actually used if it sent more traffic through the tun interface than the underlying interface. This change excludes VPN app traffic on the tun interface from the adjustment pool and doesn't redistribute traffic to the VPN app. Instead all of the redistributed traffic is deducted from the VPN app which effectively represents any overhead incurred by the VPN app. BUG: 30557871 (cherry picked from commit 8b436d865c9f287e9ae491e5278cd8874f4a865b) Change-Id: I06f01aa8fe5fdc06b2d36cfb9c68feb244c2e5de --- core/java/android/net/NetworkStats.java | 18 +++-- .../src/android/net/NetworkStatsTest.java | 75 ++++++++++++++++--- 2 files changed, 74 insertions(+), 19 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 25806fa776740..f65a50f02df32 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -904,7 +904,8 @@ public class NetworkStats implements Parcelable { if (pool.isEmpty()) { return true; } - Entry moved = addTrafficToApplications(tunIface, underlyingIface, tunIfaceTotal, pool); + Entry moved = + addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool); deductTrafficFromVpnApp(tunUid, underlyingIface, moved); if (!moved.isEmpty()) { @@ -919,9 +920,9 @@ public class NetworkStats implements Parcelable { * Initializes the data used by the migrateTun() method. * * This is the first pass iteration which does the following work: - * (1) Adds up all the traffic through tun0. - * (2) Adds up all the traffic through the tunUid's underlyingIface + * (1) Adds up all the traffic through the tunUid's underlyingIface * (both foreground and background). + * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself. */ private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface, Entry tunIfaceTotal, Entry underlyingIfaceTotal) { @@ -941,8 +942,9 @@ public class NetworkStats implements Parcelable { underlyingIfaceTotal.add(recycle); } - if (recycle.tag == TAG_NONE && Objects.equals(tunIface, recycle.iface)) { - // Add up all tunIface traffic. + if (recycle.uid != tunUid && recycle.tag == TAG_NONE + && Objects.equals(tunIface, recycle.iface)) { + // Add up all tunIface traffic excluding traffic from the vpn app itself. tunIfaceTotal.add(recycle); } } @@ -958,13 +960,15 @@ public class NetworkStats implements Parcelable { return pool; } - private Entry addTrafficToApplications(String tunIface, String underlyingIface, + private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface, Entry tunIfaceTotal, Entry pool) { Entry moved = new Entry(); Entry tmpEntry = new Entry(); tmpEntry.iface = underlyingIface; for (int i = 0; i < size; i++) { - if (Objects.equals(iface[i], tunIface)) { + // the vpn app is excluded from the redistribution but all moved traffic will be + // deducted from the vpn app (see deductTrafficFromVpnApp below). + if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) { if (tunIfaceTotal.rxBytes > 0) { tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; } else { diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java index 9074f8a97132e..d48a67a4c72f7 100644 --- a/core/tests/coretests/src/android/net/NetworkStatsTest.java +++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java @@ -454,7 +454,7 @@ public class NetworkStatsTest extends TestCase { .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L); assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface)); - assertEquals(21, delta.size()); + assertEquals(20, delta.size()); // tunIface and TEST_IFACE entries are not changed. assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO, @@ -478,38 +478,89 @@ public class NetworkStatsTest extends TestCase { // Existing underlying Iface entries are updated assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO, - 44783L, 54L, 13829L, 60L, 0L); + 44783L, 54L, 14178L, 62L, 0L); assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 0L, 0L, 0L, 0L, 0L); // VPN underlying Iface entries are updated assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO, - 28304L, 27L, 1719L, 12L, 0L); + 28304L, 27L, 1L, 2L, 0L); assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 0L, 0L, 0L, 0L, 0L); // New entries are added for new application's underlying Iface traffic assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_NO, - 72667L, 197L, 41872L, 219L, 0L); + 72667L, 197L, 43123L, 227L, 0L); assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_NO, - 9297L, 17L, 3936, 19L, 0L); + 9297L, 17L, 4054, 19L, 0L); assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, ROAMING_NO, - 21691L, 41L, 13179L, 46L, 0L); + 21691L, 41L, 13572L, 48L, 0L); assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, ROAMING_NO, - 1281L, 2L, 634L, 1L, 0L); + 1281L, 2L, 653L, 1L, 0L); // New entries are added for debug purpose assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO, - 39605L, 46L, 11690, 49, 0); + 39605L, 46L, 12039, 51, 0); assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO, - 81964, 214, 45808, 238, 0); - assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO, - 4983, 10, 1717, 10, 0); + 81964, 214, 47177, 246, 0); assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, ROAMING_ALL, - 126552, 270, 59215, 297, 0); + 121569, 260, 59216, 297, 0); } + // Tests a case where all of the data received by the tun0 interface is echo back into the tun0 + // interface by the vpn app before it's sent out of the underlying interface. The VPN app should + // not be charged for the echoed data but it should still be charged for any extra data it sends + // via the underlying interface. + public void testMigrateTun_VpnAsLoopback() { + final int tunUid = 10030; + final String tunIface = "tun0"; + final String underlyingIface = "wlan0"; + NetworkStats delta = new NetworkStats(TEST_START, 9) + // 2 different apps sent/receive data via tun0. + .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, 50000L, 25L, 100000L, 50L, 0L) + .addValues(tunIface, 20100, SET_DEFAULT, TAG_NONE, 500L, 2L, 200L, 5L, 0L) + // VPN package resends data through the tunnel (with exaggerated overhead) + .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, 240000, 100L, 120000L, 60L, 0L) + // 1 app already has some traffic on the underlying interface, the other doesn't yet + .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, 1000L, 10L, 2000L, 20L, 0L) + // Traffic through the underlying interface via the vpn app. + // This test should redistribute this data correctly. + .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, + 75500L, 37L, 130000L, 70L, 0L); + + assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface)); + assertEquals(9, delta.size()); + + // tunIface entries should not be changed. + assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO, + 50000L, 25L, 100000L, 50L, 0L); + assertValues(delta, 1, tunIface, 20100, SET_DEFAULT, TAG_NONE, ROAMING_NO, + 500L, 2L, 200L, 5L, 0L); + assertValues(delta, 2, tunIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO, + 240000L, 100L, 120000L, 60L, 0L); + + // Existing underlying Iface entries are updated + assertValues(delta, 3, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO, + 51000L, 35L, 102000L, 70L, 0L); + + // VPN underlying Iface entries are updated + assertValues(delta, 4, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO, + 25000L, 10L, 29800L, 15L, 0L); + + // New entries are added for new application's underlying Iface traffic + assertContains(delta, underlyingIface, 20100, SET_DEFAULT, TAG_NONE, ROAMING_NO, + 500L, 2L, 200L, 5L, 0L); + + // New entries are added for debug purpose + assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO, + 50000L, 25L, 100000L, 50L, 0L); + assertContains(delta, underlyingIface, 20100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO, + 500, 2L, 200L, 5L, 0L); + assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, ROAMING_ALL, + 50500L, 27L, 100200L, 55, 0); + } + private static void assertContains(NetworkStats stats, String iface, int uid, int set, int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { From 439ac32c7cd9c92a6efaac3ebdf0c584c69c4318 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 18 Aug 2016 15:31:45 -0700 Subject: [PATCH 26/45] Fixed NetworkStatsServiceTest and converted it to JUnit4. Most tests were failing because due to a null NetworkCapabilities. Example: 1) testNetworkStatsWifi(com.android.server.net.NetworkStatsServiceTest) java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.net.NetworkCapabilities.hasCapability(int)' on a null object reference at com.android.server.net.NetworkStatsService.updateIfacesLocked(NetworkStatsService.java:983) BUG: 30839080 (cherry picked from commit 574f370c6da52eeffe747248d68ef044617c7bcf) Change-Id: Ie09b2f43cf6ec745e404d5ec98bd0b072d211ea3 --- .../server/net/NetworkStatsServiceTest.java | 58 ++++++++++++------- 1 file changed, 38 insertions(+), 20 deletions(-) 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 4b69eb3ac35b3..9176675c4dd49 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java @@ -40,7 +40,9 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.WEEK_IN_MILLIS; + import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL; + import static org.easymock.EasyMock.anyInt; import static org.easymock.EasyMock.anyLong; import static org.easymock.EasyMock.anyObject; @@ -49,12 +51,12 @@ import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.eq; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expectLastCall; -import static org.easymock.EasyMock.isA; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.app.AlarmManager; -import android.app.IAlarmListener; -import android.app.IAlarmManager; -import android.app.PendingIntent; import android.app.usage.NetworkStatsManager; import android.content.Context; import android.content.Intent; @@ -63,6 +65,7 @@ import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsSession; import android.net.LinkProperties; +import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkState; @@ -80,11 +83,10 @@ import android.os.MessageQueue; import android.os.MessageQueue.IdleHandler; import android.os.Message; import android.os.PowerManager; -import android.os.WorkSource; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; import android.telephony.TelephonyManager; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.LargeTest; -import android.test.suitebuilder.annotation.Suppress; import android.util.TrustedTime; import com.android.internal.net.VpnInfo; @@ -97,6 +99,10 @@ import libcore.io.IoUtils; import org.easymock.Capture; import org.easymock.EasyMock; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; import java.io.File; import java.util.ArrayList; @@ -109,8 +115,8 @@ import java.util.List; * TODO: This test is really brittle, largely due to overly-strict use of Easymock. * Rewrite w/ Mockito. */ -@LargeTest -public class NetworkStatsServiceTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class NetworkStatsServiceTest { private static final String TAG = "NetworkStatsServiceTest"; private static final String TEST_IFACE = "test0"; @@ -148,12 +154,12 @@ public class NetworkStatsServiceTest extends AndroidTestCase { private INetworkStatsSession mSession; private INetworkManagementEventObserver mNetworkObserver; - @Override + @Before public void setUp() throws Exception { - super.setUp(); + final Context context = InstrumentationRegistry.getContext(); - mServiceContext = new BroadcastInterceptingContext(getContext()); - mStatsDir = getContext().getFilesDir(); + mServiceContext = new BroadcastInterceptingContext(context); + mStatsDir = context.getFilesDir(); if (mStatsDir.exists()) { IoUtils.deleteContents(mStatsDir); } @@ -205,7 +211,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { } - @Override + @After public void tearDown() throws Exception { IoUtils.deleteContents(mStatsDir); @@ -219,10 +225,9 @@ public class NetworkStatsServiceTest extends AndroidTestCase { mSession.close(); mService = null; - - super.tearDown(); } + @Test public void testNetworkStatsWifi() throws Exception { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. @@ -276,6 +281,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { } + @Test public void testStatsRebootPersist() throws Exception { assertStatsFilesExist(false); @@ -366,7 +372,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { } // TODO: simulate reboot to test bucket resize - @Suppress + // @Test public void testStatsBucketResize() throws Exception { NetworkStatsHistory history = null; @@ -425,6 +431,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { } + @Test public void testUidStatsAcrossNetworks() throws Exception { // pretend first mobile network comes online expectCurrentTime(); @@ -515,6 +522,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { } + @Test public void testUidRemovedIsMoved() throws Exception { // pretend that network comes online expectCurrentTime(); @@ -585,6 +593,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { } + @Test public void testUid3g4gCombinedByTemplate() throws Exception { // pretend that network comes online expectCurrentTime(); @@ -658,6 +667,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { verifyAndReset(); } + @Test public void testSummaryForAllUid() throws Exception { // pretend that network comes online expectCurrentTime(); @@ -729,6 +739,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { verifyAndReset(); } + @Test public void testForegroundBackground() throws Exception { // pretend that network comes online expectCurrentTime(); @@ -799,6 +810,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { verifyAndReset(); } + @Test public void testRoaming() throws Exception { // pretend that network comes online expectCurrentTime(); @@ -846,6 +858,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { verifyAndReset(); } + @Test public void testTethering() throws Exception { // pretend first mobile network comes online expectCurrentTime(); @@ -887,6 +900,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { } + @Test public void testRegisterUsageCallback() throws Exception { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. @@ -1005,6 +1019,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { EasyMock.verify(mockBinder); } + @Test public void testUnregisterUsageCallback_unknown_noop() throws Exception { String callingPackage = "the.calling.package"; long thresholdInBytes = 10 * 1024 * 1024; // 10 MB @@ -1204,7 +1219,8 @@ public class NetworkStatsServiceTest extends AndroidTestCase { info.setDetailedState(DetailedState.CONNECTED, null, null); final LinkProperties prop = new LinkProperties(); prop.setInterfaceName(TEST_IFACE); - return new NetworkState(info, prop, null, null, null, TEST_SSID); + final NetworkCapabilities capabilities = new NetworkCapabilities(); + return new NetworkState(info, prop, capabilities, null, null, TEST_SSID); } private static NetworkState buildMobile3gState(String subscriberId) { @@ -1218,7 +1234,8 @@ public class NetworkStatsServiceTest extends AndroidTestCase { info.setRoaming(isRoaming); final LinkProperties prop = new LinkProperties(); prop.setInterfaceName(TEST_IFACE); - return new NetworkState(info, prop, null, null, subscriberId, null); + final NetworkCapabilities capabilities = new NetworkCapabilities(); + return new NetworkState(info, prop, capabilities, null, subscriberId, null); } private static NetworkState buildMobile4gState(String iface) { @@ -1226,7 +1243,8 @@ public class NetworkStatsServiceTest extends AndroidTestCase { info.setDetailedState(DetailedState.CONNECTED, null, null); final LinkProperties prop = new LinkProperties(); prop.setInterfaceName(iface); - return new NetworkState(info, prop, null, null, null, null); + final NetworkCapabilities capabilities = new NetworkCapabilities(); + return new NetworkState(info, prop, capabilities, null, null, null); } private NetworkStats buildEmptyStats() { From 96808e68bf011cc775361864198c82aadf4addc7 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Mon, 22 Aug 2016 08:50:43 -0700 Subject: [PATCH 27/45] Use @Ignore to explicitly disable a @Test method. BUG: 30839080 BUG: 31007021 (cherry picked from commit fc7d7a359f800d7320d29055ef3b4b75157aaf13) Change-Id: I35942e60493adebb22871541a34240368c691ee7 --- .../src/com/android/server/net/NetworkStatsServiceTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 9176675c4dd49..a810f440d002e 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java @@ -101,6 +101,7 @@ import org.easymock.Capture; import org.easymock.EasyMock; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -372,7 +373,8 @@ public class NetworkStatsServiceTest { } // TODO: simulate reboot to test bucket resize - // @Test + @Test + @Ignore public void testStatsBucketResize() throws Exception { NetworkStatsHistory history = null; From 925f48a6ad1d75d161a65e1d9265f4154ef7f1fc Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 18 Aug 2016 16:20:01 -0700 Subject: [PATCH 28/45] Refactored NetworkStatsServiceTest to use Mockito instead of EasyMock. Test: m -j32 FrameworksServicesTests && adb install -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && adb shell am instrument -e class "com.android.server.net.NetworkStatsServiceTest" -w "com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner" BUG: 30943463 (cherry picked from commit b8f946dc4b24998f14e28573e452ab13ed533347) Change-Id: Ia9929295ab2396a7ebb133e65d157f98414e4dfa --- services/tests/servicestests/Android.mk | 1 - .../server/net/NetworkStatsServiceTest.java | 304 +++++------------- 2 files changed, 79 insertions(+), 226 deletions(-) diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk index d7f90c26e04ed..d3235d8fb086c 100644 --- a/services/tests/servicestests/Android.mk +++ b/services/tests/servicestests/Android.mk @@ -17,7 +17,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ services.devicepolicy \ services.net \ services.usage \ - easymocklib \ guava \ android-support-test \ mockito-target \ 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 a810f440d002e..f2cf90ca916f0 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java @@ -43,18 +43,16 @@ import static android.text.format.DateUtils.WEEK_IN_MILLIS; import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL; -import static org.easymock.EasyMock.anyInt; -import static org.easymock.EasyMock.anyLong; -import static org.easymock.EasyMock.anyObject; -import static org.easymock.EasyMock.capture; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.eq; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.expectLastCall; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; import android.app.AlarmManager; import android.app.usage.NetworkStatsManager; @@ -97,13 +95,14 @@ import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config; import libcore.io.IoUtils; -import org.easymock.Capture; -import org.easymock.EasyMock; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.io.File; import java.util.ArrayList; @@ -113,8 +112,8 @@ import java.util.List; /** * Tests for {@link NetworkStatsService}. * - * TODO: This test is really brittle, largely due to overly-strict use of Easymock. - * Rewrite w/ Mockito. + * TODO: This test used to be really brittle because it used Easymock - it uses Mockito now, but + * still uses the Easymock structure, which could be simplified. */ @RunWith(AndroidJUnit4.class) public class NetworkStatsServiceTest { @@ -144,10 +143,12 @@ public class NetworkStatsServiceTest { private BroadcastInterceptingContext mServiceContext; private File mStatsDir; - private INetworkManagementService mNetManager; - private TrustedTime mTime; - private NetworkStatsSettings mSettings; - private IConnectivityManager mConnManager; + private @Mock INetworkManagementService mNetManager; + private @Mock TrustedTime mTime; + private @Mock NetworkStatsSettings mSettings; + private @Mock IConnectivityManager mConnManager; + private @Mock IBinder mBinder; + private @Mock AlarmManager mAlarmManager; private IdleableHandlerThread mHandlerThread; private Handler mHandler; @@ -157,6 +158,7 @@ public class NetworkStatsServiceTest { @Before public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); final Context context = InstrumentationRegistry.getContext(); mServiceContext = new BroadcastInterceptingContext(context); @@ -165,22 +167,13 @@ public class NetworkStatsServiceTest { IoUtils.deleteContents(mStatsDir); } - mNetManager = createMock(INetworkManagementService.class); - - // TODO: Mock AlarmManager when migrating this test to Mockito. - AlarmManager alarmManager = (AlarmManager) mServiceContext - .getSystemService(Context.ALARM_SERVICE); - mTime = createMock(TrustedTime.class); - mSettings = createMock(NetworkStatsSettings.class); - mConnManager = createMock(IConnectivityManager.class); - PowerManager powerManager = (PowerManager) mServiceContext.getSystemService( Context.POWER_SERVICE); PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mService = new NetworkStatsService( - mServiceContext, mNetManager, alarmManager, wakeLock, mTime, + mServiceContext, mNetManager, mAlarmManager, wakeLock, mTime, TelephonyManager.getDefault(), mSettings, new NetworkStatsObservers(), mStatsDir, getBaseDir(mStatsDir)); mHandlerThread = new IdleableHandlerThread("HandlerThread"); @@ -197,17 +190,15 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(buildEmptyStats()); expectSystemReady(); - // catch INetworkManagementEventObserver during systemReady() - final Capture networkObserver = new Capture< - INetworkManagementEventObserver>(); - mNetManager.registerObserver(capture(networkObserver)); - expectLastCall().atLeastOnce(); - - replay(); mService.systemReady(); mSession = mService.openSession(); - verifyAndReset(); + assertNotNull("openSession() failed", mSession); + + // catch INetworkManagementEventObserver during systemReady() + ArgumentCaptor networkObserver = + ArgumentCaptor.forClass(INetworkManagementEventObserver.class); + verify(mNetManager).registerObserver(networkObserver.capture()); mNetworkObserver = networkObserver.getValue(); } @@ -237,15 +228,13 @@ public class NetworkStatsServiceTest { expectNetworkState(buildWifiState()); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); expectBandwidthControlCheck(); - replay(); mService.forceUpdateIfaces(); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); - verifyAndReset(); + // modify some number on wifi, and trigger poll event incrementCurrentTime(HOUR_IN_MILLIS); @@ -254,14 +243,11 @@ public class NetworkStatsServiceTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L)); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); forcePollAndWaitForIdle(); // verify service recorded history assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0); - verifyAndReset(); + // and bump forward again, with counters going higher. this is // important, since polling should correctly subtract last snapshot. @@ -271,14 +257,10 @@ public class NetworkStatsServiceTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 4096L, 4L, 8192L, 8L)); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); forcePollAndWaitForIdle(); // verify service recorded history assertNetworkTotal(sTemplateWifi, 4096L, 4L, 8192L, 8L, 0); - verifyAndReset(); } @@ -293,15 +275,13 @@ public class NetworkStatsServiceTest { expectNetworkState(buildWifiState()); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); expectBandwidthControlCheck(); - replay(); mService.forceUpdateIfaces(); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); - verifyAndReset(); + // modify some number on wifi, and trigger poll event incrementCurrentTime(HOUR_IN_MILLIS); @@ -315,14 +295,11 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L) .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L) .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L)); - expectNetworkStatsPoll(); - mService.setUidForeground(UID_RED, false); mService.incrementOperationCount(UID_RED, 0xFAAD, 4); mService.setUidForeground(UID_RED, true); mService.incrementOperationCount(UID_RED, 0xFAAD, 6); - replay(); forcePollAndWaitForIdle(); // verify service recorded history @@ -332,16 +309,13 @@ public class NetworkStatsServiceTest { assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_NO, 512L, 4L, 256L, 2L, 6); assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0); - verifyAndReset(); + // graceful shutdown system, which should trigger persist of stats, and // clear any values in memory. expectCurrentTime(); expectDefaultSettings(); - replay(); mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN)); - verifyAndReset(); - assertStatsFilesExist(true); // boot through serviceReady() again @@ -350,17 +324,8 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(buildEmptyStats()); expectSystemReady(); - // catch INetworkManagementEventObserver during systemReady() - final Capture networkObserver = new Capture< - INetworkManagementEventObserver>(); - mNetManager.registerObserver(capture(networkObserver)); - expectLastCall().atLeastOnce(); - - replay(); mService.systemReady(); - mNetworkObserver = networkObserver.getValue(); - // after systemReady(), we should have historical stats loaded again assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0); assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10); @@ -368,7 +333,6 @@ public class NetworkStatsServiceTest { assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_NO, 512L, 4L, 256L, 2L, 6); assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0); - verifyAndReset(); } @@ -387,12 +351,10 @@ public class NetworkStatsServiceTest { expectNetworkState(buildWifiState()); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); expectBandwidthControlCheck(); - replay(); mService.forceUpdateIfaces(); - verifyAndReset(); + // modify some number on wifi, and trigger poll event incrementCurrentTime(2 * HOUR_IN_MILLIS); @@ -401,9 +363,6 @@ public class NetworkStatsServiceTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 512L, 4L, 512L, 4L)); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); forcePollAndWaitForIdle(); // verify service recorded history @@ -411,7 +370,7 @@ public class NetworkStatsServiceTest { assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0); assertEquals(HOUR_IN_MILLIS, history.getBucketDuration()); assertEquals(2, history.size()); - verifyAndReset(); + // now change bucket duration setting and trigger another poll with // exact same values, which should resize existing buckets. @@ -419,9 +378,6 @@ public class NetworkStatsServiceTest { expectSettings(0L, 30 * MINUTE_IN_MILLIS, WEEK_IN_MILLIS); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); forcePollAndWaitForIdle(); // verify identical stats, but spread across 4 buckets now @@ -429,7 +385,6 @@ public class NetworkStatsServiceTest { assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0); assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration()); assertEquals(4, history.size()); - verifyAndReset(); } @@ -441,12 +396,10 @@ public class NetworkStatsServiceTest { expectNetworkState(buildMobile3gState(IMSI_1)); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); expectBandwidthControlCheck(); - replay(); mService.forceUpdateIfaces(); - verifyAndReset(); + // create some traffic on first network incrementCurrentTime(HOUR_IN_MILLIS); @@ -458,11 +411,8 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); - expectNetworkStatsPoll(); - mService.incrementOperationCount(UID_RED, 0xF00D, 10); - replay(); forcePollAndWaitForIdle(); // verify service recorded history @@ -470,7 +420,7 @@ public class NetworkStatsServiceTest { assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 512L, 4L, 10); assertUidTotal(sTemplateImsi1, UID_BLUE, 512L, 4L, 0L, 0L, 0); - verifyAndReset(); + // now switch networks; this also tests that we're okay with interfaces // disappearing, to verify we don't count backwards. @@ -484,13 +434,11 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); - expectNetworkStatsPoll(); expectBandwidthControlCheck(); - replay(); mService.forceUpdateIfaces(); forcePollAndWaitForIdle(); - verifyAndReset(); + // create traffic on second network incrementCurrentTime(HOUR_IN_MILLIS); @@ -503,11 +451,8 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L) .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L)); - expectNetworkStatsPoll(); - mService.incrementOperationCount(UID_BLUE, 0xFAAD, 10); - replay(); forcePollAndWaitForIdle(); // verify original history still intact @@ -520,7 +465,6 @@ public class NetworkStatsServiceTest { assertNetworkTotal(sTemplateImsi2, 128L, 1L, 1024L, 8L, 0); assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); assertUidTotal(sTemplateImsi2, UID_BLUE, 128L, 1L, 1024L, 8L, 10); - verifyAndReset(); } @@ -532,12 +476,10 @@ public class NetworkStatsServiceTest { expectNetworkState(buildWifiState()); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); expectBandwidthControlCheck(); - replay(); mService.forceUpdateIfaces(); - verifyAndReset(); + // create some traffic incrementCurrentTime(HOUR_IN_MILLIS); @@ -550,11 +492,8 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L) .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); - expectNetworkStatsPoll(); - mService.incrementOperationCount(UID_RED, 0xFAAD, 10); - replay(); forcePollAndWaitForIdle(); // verify service recorded history @@ -562,7 +501,7 @@ public class NetworkStatsServiceTest { assertUidTotal(sTemplateWifi, UID_RED, 16L, 1L, 16L, 1L, 10); assertUidTotal(sTemplateWifi, UID_BLUE, 4096L, 258L, 512L, 32L, 0); assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0); - verifyAndReset(); + // now pretend two UIDs are uninstalled, which should migrate stats to // special "removed" bucket. @@ -575,9 +514,6 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L) .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); - expectNetworkStatsPoll(); - - replay(); final Intent intent = new Intent(ACTION_UID_REMOVED); intent.putExtra(EXTRA_UID, UID_BLUE); mServiceContext.sendBroadcast(intent); @@ -591,7 +527,6 @@ public class NetworkStatsServiceTest { assertUidTotal(sTemplateWifi, UID_BLUE, 0L, 0L, 0L, 0L, 0); assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0); assertUidTotal(sTemplateWifi, UID_REMOVED, 4112L, 259L, 528L, 33L, 10); - verifyAndReset(); } @@ -603,12 +538,10 @@ public class NetworkStatsServiceTest { expectNetworkState(buildMobile3gState(IMSI_1)); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); expectBandwidthControlCheck(); - replay(); mService.forceUpdateIfaces(); - verifyAndReset(); + // create some traffic incrementCurrentTime(HOUR_IN_MILLIS); @@ -618,16 +551,13 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); - expectNetworkStatsPoll(); - mService.incrementOperationCount(UID_RED, 0xF00D, 5); - replay(); forcePollAndWaitForIdle(); // verify service recorded history assertUidTotal(sTemplateImsi1, UID_RED, 1024L, 8L, 1024L, 8L, 5); - verifyAndReset(); + // now switch over to 4g network incrementCurrentTime(HOUR_IN_MILLIS); @@ -638,13 +568,11 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); - expectNetworkStatsPoll(); expectBandwidthControlCheck(); - replay(); mService.forceUpdateIfaces(); forcePollAndWaitForIdle(); - verifyAndReset(); + // create traffic on second network incrementCurrentTime(HOUR_IN_MILLIS); @@ -656,17 +584,12 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L)); - expectNetworkStatsPoll(); - mService.incrementOperationCount(UID_RED, 0xFAAD, 5); - replay(); forcePollAndWaitForIdle(); // verify that ALL_MOBILE template combines both assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 1280L, 10L, 10); - - verifyAndReset(); } @Test @@ -677,12 +600,10 @@ public class NetworkStatsServiceTest { expectNetworkState(buildWifiState()); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); expectBandwidthControlCheck(); - replay(); mService.forceUpdateIfaces(); - verifyAndReset(); + // create some traffic for two apps incrementCurrentTime(HOUR_IN_MILLIS); @@ -693,17 +614,14 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L)); - expectNetworkStatsPoll(); - mService.incrementOperationCount(UID_RED, 0xF00D, 1); - replay(); forcePollAndWaitForIdle(); // verify service recorded history assertUidTotal(sTemplateWifi, UID_RED, 50L, 5L, 50L, 5L, 1); assertUidTotal(sTemplateWifi, UID_BLUE, 1024L, 8L, 512L, 4L, 0); - verifyAndReset(); + // now create more traffic in next hour, but only for one app incrementCurrentTime(HOUR_IN_MILLIS); @@ -714,9 +632,6 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0L)); - expectNetworkStatsPoll(); - - replay(); forcePollAndWaitForIdle(); // first verify entire history present @@ -737,8 +652,6 @@ public class NetworkStatsServiceTest { assertEquals(1, stats.size()); assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L, 512L, 4L, 0); - - verifyAndReset(); } @Test @@ -749,12 +662,10 @@ public class NetworkStatsServiceTest { expectNetworkState(buildWifiState()); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); expectBandwidthControlCheck(); - replay(); mService.forceUpdateIfaces(); - verifyAndReset(); + // create some initial traffic incrementCurrentTime(HOUR_IN_MILLIS); @@ -764,16 +675,13 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)); - expectNetworkStatsPoll(); - mService.incrementOperationCount(UID_RED, 0xF00D, 1); - replay(); forcePollAndWaitForIdle(); // verify service recorded history assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1); - verifyAndReset(); + // now switch to foreground incrementCurrentTime(HOUR_IN_MILLIS); @@ -785,12 +693,9 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L) .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L) .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L)); - expectNetworkStatsPoll(); - mService.setUidForeground(UID_RED, true); mService.incrementOperationCount(UID_RED, 0xFAAD, 1); - replay(); forcePollAndWaitForIdle(); // test that we combined correctly @@ -808,8 +713,6 @@ public class NetworkStatsServiceTest { 32L, 2L, 1); assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, ROAMING_NO, 1L, 1L, 1L, 1L, 1); - - verifyAndReset(); } @Test @@ -820,12 +723,10 @@ public class NetworkStatsServiceTest { expectNetworkState(buildMobile3gState(IMSI_1, true /* isRoaming */)); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); expectBandwidthControlCheck(); - replay(); mService.forceUpdateIfaces(); - verifyAndReset(); + // Create some traffic incrementCurrentTime(HOUR_IN_MILLIS); @@ -840,9 +741,6 @@ public class NetworkStatsServiceTest { 128L, 2L, 0L) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 1L, 64L, 1L, 0L)); - expectNetworkStatsPoll(); - - replay(); forcePollAndWaitForIdle(); // verify service recorded history @@ -856,8 +754,6 @@ public class NetworkStatsServiceTest { 128L, 2L, 0); assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_YES, 64L, 1L, 64L, 1L, 0); - - verifyAndReset(); } @Test @@ -868,12 +764,10 @@ public class NetworkStatsServiceTest { expectNetworkState(buildMobile3gState(IMSI_1)); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); expectBandwidthControlCheck(); - replay(); mService.forceUpdateIfaces(); - verifyAndReset(); + // create some tethering traffic incrementCurrentTime(HOUR_IN_MILLIS); @@ -889,16 +783,12 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, 0L); expectNetworkStatsUidDetail(uidStats, tetherIfacePairs, tetherStats); - expectNetworkStatsPoll(); - - replay(); forcePollAndWaitForIdle(); // verify service recorded history assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0); assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0); assertUidTotal(sTemplateImsi1, UID_TETHERING, 1920L, 14L, 384L, 2L, 0); - verifyAndReset(); } @@ -911,16 +801,12 @@ public class NetworkStatsServiceTest { expectNetworkState(buildWifiState()); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); expectBandwidthControlCheck(); - replay(); mService.forceUpdateIfaces(); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); - verifyAndReset(); - String callingPackage = "the.calling.package"; long thresholdInBytes = 1L; // very small; should be overriden by framework DataUsageRequest inputRequest = new DataUsageRequest( @@ -931,23 +817,18 @@ public class NetworkStatsServiceTest { LatchedHandler latchedHandler = new LatchedHandler(Looper.getMainLooper(), cv); Messenger messenger = new Messenger(latchedHandler); - // Allow binder to connect - IBinder mockBinder = createMock(IBinder.class); - mockBinder.linkToDeath((IBinder.DeathRecipient) anyObject(), anyInt()); - EasyMock.replay(mockBinder); - // Force poll expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - replay(); + + // Register and verify request and that binder was called DataUsageRequest request = mService.registerUsageCallback(callingPackage, inputRequest, - messenger, mockBinder); + messenger, mBinder); assertTrue(request.requestId > 0); assertTrue(Objects.equals(sTemplateWifi, request.template)); long minThresholdInBytes = 2 * 1024 * 1024; // 2 MB @@ -957,11 +838,11 @@ public class NetworkStatsServiceTest { mHandler.sendMessage(mHandler.obtainMessage(-1)); mHandlerThread.waitForIdle(WAIT_TIMEOUT); - verifyAndReset(); + // Make sure that the caller binder gets connected - EasyMock.verify(mockBinder); - EasyMock.reset(mockBinder); + verify(mBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt()); + // modify some number on wifi, and trigger poll event // not enough traffic to call data usage callback @@ -971,13 +852,9 @@ public class NetworkStatsServiceTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L)); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); forcePollAndWaitForIdle(); // verify service recorded history - verifyAndReset(); assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0); // make sure callback has not being called @@ -991,14 +868,11 @@ public class NetworkStatsServiceTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 4096000L, 4L, 8192000L, 8L)); expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); forcePollAndWaitForIdle(); // verify service recorded history assertNetworkTotal(sTemplateWifi, 4096000L, 4L, 8192000L, 8L, 0); - verifyAndReset(); + // Wait for the caller to ack receipt of CALLBACK_LIMIT_REACHED assertTrue(cv.block(WAIT_TIMEOUT)); @@ -1006,9 +880,7 @@ public class NetworkStatsServiceTest { cv.close(); // Allow binder to disconnect - expect(mockBinder.unlinkToDeath((IBinder.DeathRecipient) anyObject(), anyInt())) - .andReturn(true); - EasyMock.replay(mockBinder); + when(mBinder.unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt())).thenReturn(true); // Unregister request mService.unregisterUsageRequest(request); @@ -1018,7 +890,7 @@ public class NetworkStatsServiceTest { assertEquals(NetworkStatsManager.CALLBACK_RELEASED, latchedHandler.mLastMessageType); // Make sure that the caller binder gets disconnected - EasyMock.verify(mockBinder); + verify(mBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt()); } @Test @@ -1078,33 +950,30 @@ public class NetworkStatsServiceTest { } private void expectSystemReady() throws Exception { - mNetManager.setGlobalAlert(anyLong()); - expectLastCall().atLeastOnce(); - expectNetworkStatsSummary(buildEmptyStats()); expectBandwidthControlCheck(); } private void expectNetworkState(NetworkState... state) throws Exception { - expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); + when(mConnManager.getAllNetworkState()).thenReturn(state); final LinkProperties linkProp = state.length > 0 ? state[0].linkProperties : null; - expect(mConnManager.getActiveLinkProperties()).andReturn(linkProp).atLeastOnce(); + when(mConnManager.getActiveLinkProperties()).thenReturn(linkProp); } private void expectNetworkStatsSummary(NetworkStats summary) throws Exception { - expect(mConnManager.getAllVpnInfo()).andReturn(new VpnInfo[0]).atLeastOnce(); + when(mConnManager.getAllVpnInfo()).thenReturn(new VpnInfo[0]); expectNetworkStatsSummaryDev(summary); expectNetworkStatsSummaryXt(summary); } private void expectNetworkStatsSummaryDev(NetworkStats summary) throws Exception { - expect(mNetManager.getNetworkStatsSummaryDev()).andReturn(summary).atLeastOnce(); + when(mNetManager.getNetworkStatsSummaryDev()).thenReturn(summary); } private void expectNetworkStatsSummaryXt(NetworkStats summary) throws Exception { - expect(mNetManager.getNetworkStatsSummaryXt()).andReturn(summary).atLeastOnce(); + when(mNetManager.getNetworkStatsSummaryXt()).thenReturn(summary); } private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception { @@ -1114,11 +983,10 @@ public class NetworkStatsServiceTest { private void expectNetworkStatsUidDetail( NetworkStats detail, String[] tetherIfacePairs, NetworkStats tetherStats) throws Exception { - expect(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL))).andReturn(detail).atLeastOnce(); + when(mNetManager.getNetworkStatsUidDetail(UID_ALL)).thenReturn(detail); // also include tethering details, since they are folded into UID - expect(mNetManager.getNetworkStatsTethering()) - .andReturn(tetherStats).atLeastOnce(); + when(mNetManager.getNetworkStatsTethering()).thenReturn(tetherStats); } private void expectDefaultSettings() throws Exception { @@ -1127,38 +995,33 @@ public class NetworkStatsServiceTest { private void expectSettings(long persistBytes, long bucketDuration, long deleteAge) throws Exception { - expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes(); - expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes(); - expect(mSettings.getSampleEnabled()).andReturn(true).anyTimes(); + when(mSettings.getPollInterval()).thenReturn(HOUR_IN_MILLIS); + when(mSettings.getTimeCacheMaxAge()).thenReturn(DAY_IN_MILLIS); + when(mSettings.getSampleEnabled()).thenReturn(true); final Config config = new Config(bucketDuration, deleteAge, deleteAge); - expect(mSettings.getDevConfig()).andReturn(config).anyTimes(); - expect(mSettings.getXtConfig()).andReturn(config).anyTimes(); - expect(mSettings.getUidConfig()).andReturn(config).anyTimes(); - expect(mSettings.getUidTagConfig()).andReturn(config).anyTimes(); + when(mSettings.getDevConfig()).thenReturn(config); + when(mSettings.getXtConfig()).thenReturn(config); + when(mSettings.getUidConfig()).thenReturn(config); + when(mSettings.getUidTagConfig()).thenReturn(config); - expect(mSettings.getGlobalAlertBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes(); - expect(mSettings.getDevPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes(); - expect(mSettings.getXtPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes(); - expect(mSettings.getUidPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes(); - expect(mSettings.getUidTagPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes(); + when(mSettings.getGlobalAlertBytes(anyLong())).thenReturn(MB_IN_BYTES); + when(mSettings.getDevPersistBytes(anyLong())).thenReturn(MB_IN_BYTES); + when(mSettings.getXtPersistBytes(anyLong())).thenReturn(MB_IN_BYTES); + when(mSettings.getUidPersistBytes(anyLong())).thenReturn(MB_IN_BYTES); + when(mSettings.getUidTagPersistBytes(anyLong())).thenReturn(MB_IN_BYTES); } private void expectCurrentTime() throws Exception { - expect(mTime.forceRefresh()).andReturn(false).anyTimes(); - expect(mTime.hasCache()).andReturn(true).anyTimes(); - expect(mTime.currentTimeMillis()).andReturn(currentTimeMillis()).anyTimes(); - expect(mTime.getCacheAge()).andReturn(0L).anyTimes(); - expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes(); - } - - private void expectNetworkStatsPoll() throws Exception { - mNetManager.setGlobalAlert(anyLong()); - expectLastCall().anyTimes(); + when(mTime.forceRefresh()).thenReturn(false); + when(mTime.hasCache()).thenReturn(true); + when(mTime.currentTimeMillis()).thenReturn(currentTimeMillis()); + when(mTime.getCacheAge()).thenReturn(0L); + when(mTime.getCacheCertainty()).thenReturn(0L); } private void expectBandwidthControlCheck() throws Exception { - expect(mNetManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce(); + when(mNetManager.isBandwidthControlEnabled()).thenReturn(true); } private void assertStatsFilesExist(boolean exist) { @@ -1269,15 +1132,6 @@ public class NetworkStatsServiceTest { mElapsedRealtime += duration; } - private void replay() { - EasyMock.replay(mNetManager, mTime, mSettings, mConnManager); - } - - private void verifyAndReset() { - EasyMock.verify(mNetManager, mTime, mSettings, mConnManager); - EasyMock.reset(mNetManager, mTime, mSettings, mConnManager); - } - private void forcePollAndWaitForIdle() { mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); // Send dummy message to make sure that any previous message has been handled From 94eab5c5264db631923fe0ef1f87641a3aaf3f7d Mon Sep 17 00:00:00 2001 From: Stephen Chen Date: Tue, 18 Oct 2016 16:41:47 -0700 Subject: [PATCH 29/45] Define API for metering network stats buckets. This is a continuation of b/26545374, since now we can also set the metered bit with NetworkScorer. The tracking of metered state changes will be implemented in a seperate CL. Bug: 31015360 Bug: 26545374 Test: N/A (cherry picked from commit 9ac251d1169639c7b955d63b21e80cbc5c394090) Change-Id: I6a2fcc8577d62daa8823dff9e0128a5cf39ede7b --- api/current.txt | 4 ++ api/system-current.txt | 4 ++ api/test-current.txt | 4 ++ core/java/android/app/usage/NetworkStats.java | 42 +++++++++++++++++++ 4 files changed, 54 insertions(+) diff --git a/api/current.txt b/api/current.txt index 28ea20964fc43..10a5d92638272 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6448,6 +6448,7 @@ package android.app.usage { public static class NetworkStats.Bucket { ctor public NetworkStats.Bucket(); method public long getEndTimeStamp(); + method public int getMetered(); method public int getRoaming(); method public long getRxBytes(); method public long getRxPackets(); @@ -6457,6 +6458,9 @@ package android.app.usage { method public long getTxBytes(); method public long getTxPackets(); method public int getUid(); + field public static final int METERED_ALL = -1; // 0xffffffff + field public static final int METERED_NO = 1; // 0x1 + field public static final int METERED_YES = 2; // 0x2 field public static final int ROAMING_ALL = -1; // 0xffffffff field public static final int ROAMING_NO = 1; // 0x1 field public static final int ROAMING_YES = 2; // 0x2 diff --git a/api/system-current.txt b/api/system-current.txt index e4f593421f703..1c04a969c6302 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -6743,6 +6743,7 @@ package android.app.usage { public static class NetworkStats.Bucket { ctor public NetworkStats.Bucket(); method public long getEndTimeStamp(); + method public int getMetered(); method public int getRoaming(); method public long getRxBytes(); method public long getRxPackets(); @@ -6752,6 +6753,9 @@ package android.app.usage { method public long getTxBytes(); method public long getTxPackets(); method public int getUid(); + field public static final int METERED_ALL = -1; // 0xffffffff + field public static final int METERED_NO = 1; // 0x1 + field public static final int METERED_YES = 2; // 0x2 field public static final int ROAMING_ALL = -1; // 0xffffffff field public static final int ROAMING_NO = 1; // 0x1 field public static final int ROAMING_YES = 2; // 0x2 diff --git a/api/test-current.txt b/api/test-current.txt index 8a07387ca3653..4b088e10e7e3a 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -6457,6 +6457,7 @@ package android.app.usage { public static class NetworkStats.Bucket { ctor public NetworkStats.Bucket(); method public long getEndTimeStamp(); + method public int getMetered(); method public int getRoaming(); method public long getRxBytes(); method public long getRxPackets(); @@ -6466,6 +6467,9 @@ package android.app.usage { method public long getTxBytes(); method public long getTxPackets(); method public int getUid(); + field public static final int METERED_ALL = -1; // 0xffffffff + field public static final int METERED_NO = 1; // 0x1 + field public static final int METERED_YES = 2; // 0x2 field public static final int ROAMING_ALL = -1; // 0xffffffff field public static final int ROAMING_NO = 1; // 0x1 field public static final int ROAMING_YES = 2; // 0x2 diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 226aa8f2706da..f64bec73e4c8f 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -163,6 +163,29 @@ public final class NetworkStats implements AutoCloseable { */ public static final int UID_TETHERING = TrafficStats.UID_TETHERING; + /** @hide */ + @IntDef({METERED_ALL, METERED_NO, METERED_YES}) + @Retention(RetentionPolicy.SOURCE) + public @interface Metered {} + + /** + * Combined usage across all metered states. Covers metered and unmetered usage. + */ + public static final int METERED_ALL = -1; + + /** + * Usage that occurs on an unmetered network. + */ + public static final int METERED_NO = 0x1; + + /** + * Usage that occurs on a metered network. + * + *

A network is classified as metered when the user is sensitive to heavy data usage on + * that connection. + */ + public static final int METERED_YES = 0x2; + /** @hide */ @IntDef({ROAMING_ALL, ROAMING_NO, ROAMING_YES}) @Retention(RetentionPolicy.SOURCE) @@ -200,6 +223,7 @@ public final class NetworkStats implements AutoCloseable { private int mUid; private int mTag; private int mState; + private int mMetered; private int mRoaming; private long mBeginTimeStamp; private long mEndTimeStamp; @@ -278,6 +302,21 @@ public final class NetworkStats implements AutoCloseable { return mState; } + /** + * Metered state. One of the following values:

+ *

    + *
  • {@link #METERED_ALL}
  • + *
  • {@link #METERED_NO}
  • + *
  • {@link #METERED_YES}
  • + *
+ *

A network is classified as metered when the user is sensitive to heavy data usage on + * that connection. Apps may warn before using these networks for large downloads. The + * metered state can be set by the user within data usage network restrictions. + */ + public @Metered int getMetered() { + return mMetered; + } + /** * Roaming state. One of the following values:

*

    @@ -491,6 +530,8 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); + // TODO: Implement metered tracking. + bucketOut.mMetered = Bucket.METERED_ALL; bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; bucketOut.mEndTimeStamp = mEndTimeStamp; @@ -539,6 +580,7 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(getUid()); bucketOut.mTag = Bucket.convertTag(mTag); bucketOut.mState = Bucket.STATE_ALL; + bucketOut.mMetered = Bucket.METERED_ALL; bucketOut.mRoaming = Bucket.ROAMING_ALL; bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart; bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart + From 06124cc892091a4f251112c39aba43e05345ac7b Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 2 Dec 2016 12:17:21 -0700 Subject: [PATCH 30/45] Switch over to new "time.android.com" NTP pool. Also add logging to measure success/failure details. Test: builds, boots, and NTP fix obtained Bug: 32969463 (cherry picked from commit d3f689bf14a05de735b5cc92dcf20e7226c78690) Change-Id: I7da416099ae903fd92beb516251ef4e51673eecf --- Android.mk | 1 + core/java/android/net/EventLogTags.logtags | 6 ++++++ core/java/android/net/SntpClient.java | 6 ++++-- core/res/res/values/config.xml | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 core/java/android/net/EventLogTags.logtags diff --git a/Android.mk b/Android.mk index c405440cfbd75..a798a311e0411 100644 --- a/Android.mk +++ b/Android.mk @@ -45,6 +45,7 @@ LOCAL_SRC_FILES += \ core/java/android/app/admin/SecurityLogTags.logtags \ core/java/android/content/EventLogTags.logtags \ core/java/android/speech/tts/EventLogTags.logtags \ + core/java/android/net/EventLogTags.logtags \ core/java/android/webkit/EventLogTags.logtags \ core/java/com/android/internal/logging/EventLogTags.logtags \ diff --git a/core/java/android/net/EventLogTags.logtags b/core/java/android/net/EventLogTags.logtags new file mode 100644 index 0000000000000..d5ed01496eba6 --- /dev/null +++ b/core/java/android/net/EventLogTags.logtags @@ -0,0 +1,6 @@ +# See system/core/logcat/event.logtags for a description of the format of this file. + +option java_package android.net + +50080 ntp_success (server|3),(rtt|2),(offset|2) +50081 ntp_failure (server|3),(msg|3) diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java index cf9243f7e7a31..cea56b53d7637 100644 --- a/core/java/android/net/SntpClient.java +++ b/core/java/android/net/SntpClient.java @@ -36,8 +36,7 @@ import java.util.Arrays; * } * */ -public class SntpClient -{ +public class SntpClient { private static final String TAG = "SntpClient"; private static final boolean DBG = true; @@ -88,6 +87,7 @@ public class SntpClient try { address = InetAddress.getByName(host); } catch (Exception e) { + EventLogTags.writeNtpFailure(host, e.toString()); if (DBG) Log.d(TAG, "request time failed: " + e); return false; } @@ -142,6 +142,7 @@ public class SntpClient // = (transit + skew - transit + skew)/2 // = (2 * skew)/2 = skew long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2; + EventLogTags.writeNtpSuccess(address.toString(), roundTripTime, clockOffset); if (DBG) { Log.d(TAG, "round trip: " + roundTripTime + "ms, " + "clock offset: " + clockOffset + "ms"); @@ -153,6 +154,7 @@ public class SntpClient mNtpTimeReference = responseTicks; mRoundTripTime = roundTripTime; } catch (Exception e) { + EventLogTags.writeNtpFailure(address.toString(), e.toString()); if (DBG) Log.d(TAG, "request time failed: " + e); return false; } finally { diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 42cb55bd8d91d..dbc4324ec92ac 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1681,7 +1681,7 @@ true - 2.android.pool.ntp.org + time.android.com 86400000 From b038044758b2699f22b1215fe3a7ac4ed9a7a15a Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Tue, 15 Nov 2016 11:25:52 +0900 Subject: [PATCH 31/45] Fix ConnectivityServiceTest testRequestBenchmark This patch fixes flakyness of testRequestBenchmark by adjusting time limit for callback registration from 100ms to 180ms, and time limits for onAvailable and onLost triggers from 30ms to 40ms. With these timeouts the test succeeds 100% over 5000 iterations. When using 150ms for registration timeout, running the test 5000 times fails 2 times. When using 30ms for onLost timeout, running the test 5000 times fails 1 times. In addition, this patch also cleans testRequestBenchmark and uses the more stable SystemClock.elapsedRealtime() for duration measurements. Test: $ runtest frameworks-net Bug: 32561414 (cherry picked from commit 38be57b438a0c1754091f045317db2049304e16f) Change-Id: I196ab9ef7f5abe456a783eed65db09279d2ecb8c --- .../server/ConnectivityServiceTest.java | 88 ++++++++++++------- 1 file changed, 54 insertions(+), 34 deletions(-) diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index a06577e6dab91..bc685f27bfdbe 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -2012,6 +2012,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { @SmallTest public void testRequestBenchmark() throws Exception { + // TODO: turn this unit test into a real benchmarking test. // Benchmarks connecting and switching performance in the presence of a large number of // NetworkRequests. // 1. File NUM_REQUESTS requests. @@ -2025,61 +2026,80 @@ public class ConnectivityServiceTest extends AndroidTestCase { final CountDownLatch availableLatch = new CountDownLatch(NUM_REQUESTS); final CountDownLatch losingLatch = new CountDownLatch(NUM_REQUESTS); - final int REGISTER_TIME_LIMIT_MS = 100; - long startTime = System.currentTimeMillis(); for (int i = 0; i < NUM_REQUESTS; i++) { callbacks[i] = new NetworkCallback() { @Override public void onAvailable(Network n) { availableLatch.countDown(); } @Override public void onLosing(Network n, int t) { losingLatch.countDown(); } }; - mCm.registerNetworkCallback(request, callbacks[i]); } - long timeTaken = System.currentTimeMillis() - startTime; - String msg = String.format("Register %d callbacks: %dms, acceptable %dms", - NUM_REQUESTS, timeTaken, REGISTER_TIME_LIMIT_MS); - Log.d(TAG, msg); - assertTrue(msg, timeTaken < REGISTER_TIME_LIMIT_MS); - final int CONNECT_TIME_LIMIT_MS = 30; + final int REGISTER_TIME_LIMIT_MS = 180; + assertTimeLimit("Registering callbacks", REGISTER_TIME_LIMIT_MS, () -> { + for (NetworkCallback cb : callbacks) { + mCm.registerNetworkCallback(request, cb); + } + }); + + final int CONNECT_TIME_LIMIT_MS = 40; mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); // Don't request that the network validate, because otherwise connect() will block until // the network gets NET_CAPABILITY_VALIDATED, after all the callbacks below have fired, // and we won't actually measure anything. mCellNetworkAgent.connect(false); - startTime = System.currentTimeMillis(); - if (!availableLatch.await(CONNECT_TIME_LIMIT_MS, TimeUnit.MILLISECONDS)) { - fail(String.format("Only dispatched %d/%d onAvailable callbacks in %dms", - NUM_REQUESTS - availableLatch.getCount(), NUM_REQUESTS, - CONNECT_TIME_LIMIT_MS)); - } - timeTaken = System.currentTimeMillis() - startTime; - Log.d(TAG, String.format("Connect, %d callbacks: %dms, acceptable %dms", - NUM_REQUESTS, timeTaken, CONNECT_TIME_LIMIT_MS)); - final int SWITCH_TIME_LIMIT_MS = 30; + long onAvailableDispatchingDuration = durationOf(() -> { + if (!awaitLatch(availableLatch, CONNECT_TIME_LIMIT_MS)) { + fail(String.format("Only dispatched %d/%d onAvailable callbacks in %dms", + NUM_REQUESTS - availableLatch.getCount(), NUM_REQUESTS, + CONNECT_TIME_LIMIT_MS)); + } + }); + Log.d(TAG, String.format("Connect, %d callbacks: %dms, acceptable %dms", + NUM_REQUESTS, onAvailableDispatchingDuration, CONNECT_TIME_LIMIT_MS)); + + final int SWITCH_TIME_LIMIT_MS = 40; mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); // Give wifi a high enough score that we'll linger cell when wifi comes up. mWiFiNetworkAgent.adjustScore(40); mWiFiNetworkAgent.connect(false); - startTime = System.currentTimeMillis(); - if (!losingLatch.await(SWITCH_TIME_LIMIT_MS, TimeUnit.MILLISECONDS)) { - fail(String.format("Only dispatched %d/%d onLosing callbacks in %dms", - NUM_REQUESTS - losingLatch.getCount(), NUM_REQUESTS, SWITCH_TIME_LIMIT_MS)); - } - timeTaken = System.currentTimeMillis() - startTime; + + long onLostDispatchingDuration = durationOf(() -> { + if (!awaitLatch(losingLatch, SWITCH_TIME_LIMIT_MS)) { + fail(String.format("Only dispatched %d/%d onLosing callbacks in %dms", + NUM_REQUESTS - losingLatch.getCount(), NUM_REQUESTS, SWITCH_TIME_LIMIT_MS)); + } + }); Log.d(TAG, String.format("Linger, %d callbacks: %dms, acceptable %dms", - NUM_REQUESTS, timeTaken, SWITCH_TIME_LIMIT_MS)); + NUM_REQUESTS, onLostDispatchingDuration, SWITCH_TIME_LIMIT_MS)); final int UNREGISTER_TIME_LIMIT_MS = 10; - startTime = System.currentTimeMillis(); - for (int i = 0; i < NUM_REQUESTS; i++) { - mCm.unregisterNetworkCallback(callbacks[i]); - } - timeTaken = System.currentTimeMillis() - startTime; - msg = String.format("Unregister %d callbacks: %dms, acceptable %dms", - NUM_REQUESTS, timeTaken, UNREGISTER_TIME_LIMIT_MS); + assertTimeLimit("Unregistering callbacks", UNREGISTER_TIME_LIMIT_MS, () -> { + for (NetworkCallback cb : callbacks) { + mCm.unregisterNetworkCallback(cb); + } + }); + } + + private long durationOf(Runnable fn) { + long startTime = SystemClock.elapsedRealtime(); + fn.run(); + return SystemClock.elapsedRealtime() - startTime; + } + + private void assertTimeLimit(String descr, long timeLimit, Runnable fn) { + long timeTaken = durationOf(fn); + String msg = String.format("%s: took %dms, limit was %dms", descr, timeTaken, timeLimit); Log.d(TAG, msg); - assertTrue(msg, timeTaken < UNREGISTER_TIME_LIMIT_MS); + assertTrue(msg, timeTaken <= timeLimit); + } + + private boolean awaitLatch(CountDownLatch l, long timeoutMs) { + try { + if (l.await(timeoutMs, TimeUnit.MILLISECONDS)) { + return true; + } + } catch (InterruptedException e) {} + return false; } @SmallTest From d49596f479d19b1f2decd1c71fb7abbc85682d55 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Tue, 15 Nov 2016 13:42:34 +0900 Subject: [PATCH 32/45] ConnectivityServiceTest: fix testAvoidBadWifiSettings This patch introduces an assertEventuallyThat helper function in ConnectivityServiceTest which given a boolean function retries until the function returns true or until a maximum retry time is reached. This function is used to fix flakyness of testAvoidBadWifiSetting where the Message posted by reevaluate() could reach the Handler's MessageQueue after waitForIdle takes effect, resulting in the test to fail. Instead of fixing the flakyness by introdcing hard sleep times, assertEventuallyThat is used to reduce the overall test time. With this change the test has been observed to pass with 100% success rate over 50000 invocations. Test: $ runtest frameworks-net Bug: 32561414 (cherry picked from commit 99c8294ef0c7a720364abb5884063e0a9d1bb5fe) Change-Id: If41a24989d5f65aeb439f68741f511b5eb53b18d --- .../server/ConnectivityServiceTest.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index bc685f27bfdbe..4b3f99277e80e 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -91,6 +91,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.BooleanSupplier; /** * Tests for {@link ConnectivityService}. @@ -622,7 +623,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { } private class WrappedAvoidBadWifiTracker extends AvoidBadWifiTracker { - public boolean configRestrictsAvoidBadWifi; + public volatile boolean configRestrictsAvoidBadWifi; public WrappedAvoidBadWifiTracker(Context c, Handler h, Runnable r) { super(c, h, r); @@ -2180,7 +2181,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { tracker.reevaluate(); mService.waitForIdle(); String msg = String.format("config=false, setting=%s", values[i]); - assertTrue(msg, mService.avoidBadWifi()); + assertEventuallyTrue(() -> mService.avoidBadWifi(), 50); assertFalse(msg, tracker.shouldNotifyWifiUnvalidated()); } @@ -2189,19 +2190,19 @@ public class ConnectivityServiceTest extends AndroidTestCase { Settings.Global.putInt(cr, settingName, 0); tracker.reevaluate(); mService.waitForIdle(); - assertFalse(mService.avoidBadWifi()); + assertEventuallyTrue(() -> !mService.avoidBadWifi(), 50); assertFalse(tracker.shouldNotifyWifiUnvalidated()); Settings.Global.putInt(cr, settingName, 1); tracker.reevaluate(); mService.waitForIdle(); - assertTrue(mService.avoidBadWifi()); + assertEventuallyTrue(() -> mService.avoidBadWifi(), 50); assertFalse(tracker.shouldNotifyWifiUnvalidated()); Settings.Global.putString(cr, settingName, null); tracker.reevaluate(); mService.waitForIdle(); - assertFalse(mService.avoidBadWifi()); + assertEventuallyTrue(() -> !mService.avoidBadWifi(), 50); assertTrue(tracker.shouldNotifyWifiUnvalidated()); } @@ -2418,6 +2419,17 @@ public class ConnectivityServiceTest extends AndroidTestCase { networkCallback.assertNoCallback(); } + public void assertEventuallyTrue(BooleanSupplier fn, long maxWaitingTimeMs) throws Exception { + long start = SystemClock.elapsedRealtime(); + while (SystemClock.elapsedRealtime() <= start + maxWaitingTimeMs) { + if (fn.getAsBoolean()) { + return; + } + Thread.sleep(10); + } + assertTrue(fn.getAsBoolean()); + } + private static class TestKeepaliveCallback extends PacketKeepaliveCallback { public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR }; From 5c2111bc3aa72470e5a88b523389d4be8fc517bf Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Sat, 3 Dec 2016 02:41:05 +0900 Subject: [PATCH 33/45] APF: also drop any ICMPv6 RSs Test: new unit test + $ runtest franeworks-net Bug: 32833400 (cherry picked from commit f98182ef5e80ede5de7f2c2a5f40fc92a46c9704) Change-Id: Ifaf6e778c811c7d865c790a293b1fce3f43cad1c --- services/net/java/android/net/apf/ApfFilter.java | 13 ++++++++++--- tests/net/java/android/net/apf/ApfTest.java | 10 ++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java index a8356dc4658e7..83001df580233 100644 --- a/services/net/java/android/net/apf/ApfFilter.java +++ b/services/net/java/android/net/apf/ApfFilter.java @@ -194,8 +194,10 @@ public class ApfFilter { { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN; - private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136; + private static final int ICMP6_ROUTER_SOLICITATION = 133; private static final int ICMP6_ROUTER_ADVERTISEMENT = 134; + private static final int ICMP6_NEIGHBOR_SOLICITATION = 135; + private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136; // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2; @@ -805,6 +807,8 @@ public class ApfFilter { // if it's multicast and we're dropping multicast: // drop // pass + // if it's ICMPv6 RS to any: + // drop // if it's ICMPv6 NA to ff02::1: // drop @@ -829,10 +833,12 @@ public class ApfFilter { // Add unsolicited multicast neighbor announcements filter String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA"; - // If not neighbor announcements, skip unsolicited multicast NA filter gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET); + // Drop all router solicitations (b/32833400) + gen.addJumpIfR0Equals(ICMP6_ROUTER_SOLICITATION, gen.DROP_LABEL); + // If not neighbor announcements, skip filter. gen.addJumpIfR0NotEquals(ICMP6_NEIGHBOR_ANNOUNCEMENT, skipUnsolicitedMulticastNALabel); - // If to ff02::1, drop + // If to ff02::1, drop. // TODO: Drop only if they don't contain the address of on-link neighbours. gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET); gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS, @@ -852,6 +858,7 @@ public class ApfFilter { *
  • Pass all non-ICMPv6 IPv6 packets, *
  • Pass all non-IPv4 and non-IPv6 packets, *
  • Drop IPv6 ICMPv6 NAs to ff02::1. + *
  • Drop IPv6 ICMPv6 RSs. *
  • Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows * insertion of RA filters here, or if there aren't any, just passes the packets. *
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java index 81f66a5bc95af..f41ea922305b4 100644 --- a/tests/net/java/android/net/apf/ApfTest.java +++ b/tests/net/java/android/net/apf/ApfTest.java @@ -662,9 +662,13 @@ public class ApfTest extends AndroidTestCase { // The IPv6 all nodes address ff02::1 private static final byte[] IPV6_ALL_NODES_ADDRESS = { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + private static final byte[] IPV6_ALL_ROUTERS_ADDRESS = + { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }; private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN; + private static final int ICMP6_ROUTER_SOLICITATION = 133; private static final int ICMP6_ROUTER_ADVERTISEMENT = 134; + private static final int ICMP6_NEIGHBOR_SOLICITATION = 135; private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136; private static final int ICMP6_RA_HEADER_LEN = 16; @@ -799,6 +803,12 @@ public class ApfTest extends AndroidTestCase { put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS); assertDrop(program, packet.array()); + // Verify ICMPv6 RS to any is dropped + packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_SOLICITATION); + assertDrop(program, packet.array()); + put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS); + assertDrop(program, packet.array()); + apfFilter.shutdown(); } From c328248cdc5e6a89a1742775f1de855f04a71913 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Tue, 15 Nov 2016 23:23:24 +0900 Subject: [PATCH 34/45] NetworkMonitor metrics: add first validation information This patch adds first validation information to: - ValidationProbeEvent, by extending the probe_type int field of to also include a bit indicating if the probe was part of a first validation attempt or not. - NetworkMonitorEvent, by defining new contants for the event_type field. Test: $ runtest frameworks-net + manually generating events and inspecting the output of $ adb shell dumpsys connmetrics list Bug: b/32198726 (cherry picked from commit 147aa6d53bc1e9f8a3632553abcf936023806e1d) Change-Id: Ie7a62c4f62a13ce52806d3adaa9e627cb246073c --- ] | 12 +++++ .../android/net/metrics/NetworkEvent.java | 13 +++++ .../net/metrics/ValidationProbeEvent.java | 34 +++++++++---- .../server/connectivity/NetworkMonitor.java | 50 ++++++++++++++++++- 4 files changed, 97 insertions(+), 12 deletions(-) create mode 100644 ] diff --git a/] b/] new file mode 100644 index 0000000000000..5619151c7ee3e --- /dev/null +++ b/] @@ -0,0 +1,12 @@ +NetworkNotificationManager: logging improvements + +TODO: squash me +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# On branch notification_tagging +# Your branch is ahead of 'goog/master' by 2 commits. +# (use "git push" to publish your local commits) +# +# Changes to be committed: +# modified: services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +# diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java index 3b3fa6976fc98..06674950a044d 100644 --- a/core/java/android/net/metrics/NetworkEvent.java +++ b/core/java/android/net/metrics/NetworkEvent.java @@ -41,6 +41,15 @@ public final class NetworkEvent implements Parcelable { public static final int NETWORK_UNLINGER = 6; public static final int NETWORK_DISCONNECTED = 7; + /** {@hide} */ + public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8; + /** {@hide} */ + public static final int NETWORK_REVALIDATION_SUCCESS = 9; + /** {@hide} */ + public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; + /** {@hide} */ + public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; + /** {@hide} */ @IntDef(value = { NETWORK_CONNECTED, @@ -50,6 +59,10 @@ public final class NetworkEvent implements Parcelable { NETWORK_LINGER, NETWORK_UNLINGER, NETWORK_DISCONNECTED, + NETWORK_FIRST_VALIDATION_SUCCESS, + NETWORK_REVALIDATION_SUCCESS, + NETWORK_FIRST_VALIDATION_PORTAL_FOUND, + NETWORK_REVALIDATION_PORTAL_FOUND, }) @Retention(RetentionPolicy.SOURCE) public @interface EventType {} diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java index 1a31b56f1ffb6..a724ec12ed324 100644 --- a/core/java/android/net/metrics/ValidationProbeEvent.java +++ b/core/java/android/net/metrics/ValidationProbeEvent.java @@ -44,10 +44,8 @@ public final class ValidationProbeEvent implements Parcelable { public static final int DNS_FAILURE = 0; public static final int DNS_SUCCESS = 1; - /** {@hide} */ - @IntDef(value = {PROBE_DNS, PROBE_HTTP, PROBE_HTTPS, PROBE_PAC}) - @Retention(RetentionPolicy.SOURCE) - public @interface ProbeType {} + private static final int FIRST_VALIDATION = 1 << 8; + private static final int REVALIDATION = 2 << 8; /** {@hide} */ @IntDef(value = {DNS_FAILURE, DNS_SUCCESS}) @@ -56,12 +54,17 @@ public final class ValidationProbeEvent implements Parcelable { public final int netId; public final long durationMs; - public final @ProbeType int probeType; + // probeType byte format (MSB to LSB): + // byte 0: unused + // byte 1: unused + // byte 2: 0 = UNKNOWN, 1 = FIRST_VALIDATION, 2 = REVALIDATION + // byte 3: PROBE_* constant + public final int probeType; public final @ReturnCode int returnCode; /** {@hide} */ public ValidationProbeEvent( - int netId, long durationMs, @ProbeType int probeType, @ReturnCode int returnCode) { + int netId, long durationMs, int probeType, @ReturnCode int returnCode) { this.netId = netId; this.durationMs = durationMs; this.probeType = probeType; @@ -99,9 +102,19 @@ public final class ValidationProbeEvent implements Parcelable { } }; + /** @hide */ + public static int makeProbeType(int probeType, boolean firstValidation) { + return (probeType & 0xff) | (firstValidation ? FIRST_VALIDATION : REVALIDATION); + } + /** @hide */ public static String getProbeName(int probeType) { - return Decoder.constants.get(probeType, "PROBE_???"); + return Decoder.constants.get(probeType & 0xff, "PROBE_???"); + } + + /** @hide */ + public static String getValidationStage(int probeType) { + return Decoder.constants.get(probeType & 0xff00, "UNKNOWN"); } public static void logEvent(int netId, long durationMs, int probeType, int returnCode) { @@ -109,12 +122,13 @@ public final class ValidationProbeEvent implements Parcelable { @Override public String toString() { - return String.format("ValidationProbeEvent(%d, %s:%d, %dms)", - netId, getProbeName(probeType), returnCode, durationMs); + return String.format("ValidationProbeEvent(%d, %s:%d %s, %dms)", netId, + getProbeName(probeType), returnCode, getValidationStage(probeType), durationMs); } final static class Decoder { static final SparseArray constants = MessageUtils.findMessageNames( - new Class[]{ValidationProbeEvent.class}, new String[]{"PROBE_"}); + new Class[]{ValidationProbeEvent.class}, + new String[]{"PROBE_", "FIRST_", "REVALIDATION"}); } } diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index c73d1dd954375..d6173cb9a3122 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -96,6 +96,24 @@ public class NetworkMonitor extends StateMachine { private static final int SOCKET_TIMEOUT_MS = 10000; private static final int PROBE_TIMEOUT_MS = 3000; + static enum EvaluationResult { + VALIDATED(true), + CAPTIVE_PORTAL(false); + final boolean isValidated; + EvaluationResult(boolean isValidated) { + this.isValidated = isValidated; + } + } + + static enum ValidationStage { + FIRST_VALIDATION(true), + REVALIDATION(false); + final boolean isFirstValidation; + ValidationStage(boolean isFirstValidation) { + this.isFirstValidation = isFirstValidation; + } + } + public static final String ACTION_NETWORK_CONDITIONS_MEASURED = "android.net.conn.NETWORK_CONDITIONS_MEASURED"; public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type"; @@ -215,6 +233,8 @@ public class NetworkMonitor extends StateMachine { protected boolean mIsCaptivePortalCheckEnabled; private boolean mUseHttps; + // The total number of captive portal detection attempts for this NetworkMonitor instance. + private int mValidations = 0; // Set if the user explicitly selected "Do not use this network" in captive portal sign-in app. private boolean mUserDoesNotWant = false; @@ -289,6 +309,10 @@ public class NetworkMonitor extends StateMachine { return validationLogs.readOnlyLocalLog(); } + private ValidationStage validationStage() { + return 0 == mValidations ? ValidationStage.FIRST_VALIDATION : ValidationStage.REVALIDATION; + } + // DefaultState is the parent of all States. It exists only to handle CMD_* messages but // does not entail any real state (hence no enter() or exit() routines). private class DefaultState extends State { @@ -365,9 +389,11 @@ public class NetworkMonitor extends StateMachine { private class ValidatedState extends State { @Override public void enter() { - maybeLogEvaluationResult(NetworkEvent.NETWORK_VALIDATED); + maybeLogEvaluationResult( + networkEventType(validationStage(), EvaluationResult.VALIDATED)); mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_VALID, mNetworkAgentInfo.network.netId, null)); + mValidations++; } @Override @@ -583,7 +609,8 @@ public class NetworkMonitor extends StateMachine { @Override public void enter() { - maybeLogEvaluationResult(NetworkEvent.NETWORK_CAPTIVE_PORTAL_FOUND); + maybeLogEvaluationResult( + networkEventType(validationStage(), EvaluationResult.CAPTIVE_PORTAL)); // Don't annoy user with sign-in notifications. if (mDontDisplaySigninNotification) return; // Create a CustomIntentReceiver that sends us a @@ -603,6 +630,7 @@ public class NetworkMonitor extends StateMachine { // Retest for captive portal occasionally. sendMessageDelayed(CMD_CAPTIVE_PORTAL_RECHECK, 0 /* no UID */, CAPTIVE_PORTAL_REEVALUATE_DELAY_MS); + mValidations++; } @Override @@ -973,6 +1001,22 @@ public class NetworkMonitor extends StateMachine { mMetricsLog.log(new NetworkEvent(mNetId, evtype)); } + private int networkEventType(ValidationStage s, EvaluationResult r) { + if (s.isFirstValidation) { + if (r.isValidated) { + return NetworkEvent.NETWORK_FIRST_VALIDATION_SUCCESS; + } else { + return NetworkEvent.NETWORK_FIRST_VALIDATION_PORTAL_FOUND; + } + } else { + if (r.isValidated) { + return NetworkEvent.NETWORK_REVALIDATION_SUCCESS; + } else { + return NetworkEvent.NETWORK_REVALIDATION_PORTAL_FOUND; + } + } + } + private void maybeLogEvaluationResult(int evtype) { if (mEvaluationTimer.isRunning()) { mMetricsLog.log(new NetworkEvent(mNetId, evtype, mEvaluationTimer.stop())); @@ -981,6 +1025,8 @@ public class NetworkMonitor extends StateMachine { } private void logValidationProbe(long durationMs, int probeType, int probeResult) { + probeType = + ValidationProbeEvent.makeProbeType(probeType, validationStage().isFirstValidation); mMetricsLog.log(new ValidationProbeEvent(mNetId, durationMs, probeType, probeResult)); } } From a19056c35d16ddb5a6c1d3343729701b8939f1e1 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Wed, 16 Nov 2016 18:18:08 +0900 Subject: [PATCH 35/45] NetworkMonitor: send one DNS probe per web probe This patch changes sligthly the two web probes mechanism for captive portal detection and network validation so that DNS resolution is always done for both probes. In general the target web servers of the two parallel HTTP and HTTPS probes are now different. This introduces a bias in the latency measurement of th HTTPS probe since this latency will also include DNS resolution in general. Test: manual verification + $ runtest frameworks-net Bug: 32198726 (cherry picked from commit ab61e7c324b24e46829495bc2597e42ea907c53d) Change-Id: I3b32ae451f2241849fffe24956758a9f571b1ef1 --- .../server/connectivity/NetworkMonitor.java | 96 ++++++++++--------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index d6173cb9a3122..ea2cf5fb4a7ef 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -706,48 +706,13 @@ public class NetworkMonitor extends StateMachine { long startTime = SystemClock.elapsedRealtime(); - // Pre-resolve the captive portal server host so we can log it. - // Only do this if HttpURLConnection is about to, to avoid any potentially - // unnecessary resolution. - String hostToResolve = null; + final CaptivePortalProbeResult result; if (pacUrl != null) { - hostToResolve = pacUrl.getHost(); - } else if (proxyInfo != null) { - hostToResolve = proxyInfo.getHost(); - } else { - hostToResolve = httpUrl.getHost(); - } - - if (!TextUtils.isEmpty(hostToResolve)) { - String probeName = ValidationProbeEvent.getProbeName(ValidationProbeEvent.PROBE_DNS); - final Stopwatch dnsTimer = new Stopwatch().start(); - int dnsResult; - long dnsLatency; - try { - InetAddress[] addresses = mNetworkAgentInfo.network.getAllByName(hostToResolve); - dnsResult = ValidationProbeEvent.DNS_SUCCESS; - dnsLatency = dnsTimer.stop(); - final StringBuffer connectInfo = new StringBuffer(", " + hostToResolve + "="); - for (InetAddress address : addresses) { - connectInfo.append(address.getHostAddress()); - if (address != addresses[addresses.length-1]) connectInfo.append(","); - } - validationLog(probeName + " OK " + dnsLatency + "ms" + connectInfo); - } catch (UnknownHostException e) { - dnsResult = ValidationProbeEvent.DNS_FAILURE; - dnsLatency = dnsTimer.stop(); - validationLog(probeName + " FAIL " + dnsLatency + "ms, " + hostToResolve); - } - logValidationProbe(dnsLatency, ValidationProbeEvent.PROBE_DNS, dnsResult); - } - - CaptivePortalProbeResult result; - if (pacUrl != null) { - result = sendHttpProbe(pacUrl, ValidationProbeEvent.PROBE_PAC); + result = sendDnsAndHttpProbes(null, pacUrl, ValidationProbeEvent.PROBE_PAC); } else if (mUseHttps) { - result = sendParallelHttpProbes(httpsUrl, httpUrl, fallbackUrl); + result = sendParallelHttpProbes(proxyInfo, httpsUrl, httpUrl, fallbackUrl); } else { - result = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP); + result = sendDnsAndHttpProbes(proxyInfo, httpUrl, ValidationProbeEvent.PROBE_HTTP); } long endTime = SystemClock.elapsedRealtime(); @@ -760,8 +725,50 @@ public class NetworkMonitor extends StateMachine { } /** - * Do a URL fetch on a known server to see if we get the data we expect. - * Returns HTTP response code. + * Do a DNS resolution and URL fetch on a known web server to see if we get the data we expect. + * @return a CaptivePortalProbeResult inferred from the HTTP response. + */ + private CaptivePortalProbeResult sendDnsAndHttpProbes(ProxyInfo proxy, URL url, int probeType) { + // Pre-resolve the captive portal server host so we can log it. + // Only do this if HttpURLConnection is about to, to avoid any potentially + // unnecessary resolution. + final String host = (proxy != null) ? proxy.getHost() : url.getHost(); + sendDnsProbe(host); + return sendHttpProbe(url, probeType); + } + + /** Do a DNS resolution of the given server. */ + private void sendDnsProbe(String host) { + if (TextUtils.isEmpty(host)) { + return; + } + + final String name = ValidationProbeEvent.getProbeName(ValidationProbeEvent.PROBE_DNS); + final Stopwatch watch = new Stopwatch().start(); + int result; + String connectInfo; + try { + InetAddress[] addresses = mNetworkAgentInfo.network.getAllByName(host); + result = ValidationProbeEvent.DNS_SUCCESS; + StringBuffer buffer = new StringBuffer(host).append("="); + for (InetAddress address : addresses) { + buffer.append(address.getHostAddress()); + if (address != addresses[addresses.length-1]) buffer.append(","); + } + connectInfo = buffer.toString(); + } catch (UnknownHostException e) { + result = ValidationProbeEvent.DNS_FAILURE; + connectInfo = host; + } + final long latency = watch.stop(); + String resultString = (ValidationProbeEvent.DNS_SUCCESS == result) ? "OK" : "FAIL"; + validationLog(String.format("%s %s %dms, %s", name, resultString, latency, connectInfo)); + logValidationProbe(latency, ValidationProbeEvent.PROBE_DNS, result); + } + + /** + * Do a URL fetch on a known web server to see if we get the data we expect. + * @return a CaptivePortalProbeResult inferred from the HTTP response. */ @VisibleForTesting protected CaptivePortalProbeResult sendHttpProbe(URL url, int probeType) { @@ -828,7 +835,7 @@ public class NetworkMonitor extends StateMachine { } private CaptivePortalProbeResult sendParallelHttpProbes( - URL httpsUrl, URL httpUrl, URL fallbackUrl) { + ProxyInfo proxy, URL httpsUrl, URL httpUrl, URL fallbackUrl) { // Number of probes to wait for. If a probe completes with a conclusive answer // it shortcuts the latch immediately by forcing the count to 0. final CountDownLatch latch = new CountDownLatch(2); @@ -848,9 +855,10 @@ public class NetworkMonitor extends StateMachine { @Override public void run() { if (mIsHttps) { - mResult = sendHttpProbe(httpsUrl, ValidationProbeEvent.PROBE_HTTPS); + mResult = + sendDnsAndHttpProbes(proxy, httpsUrl, ValidationProbeEvent.PROBE_HTTPS); } else { - mResult = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP); + mResult = sendDnsAndHttpProbes(proxy, httpUrl, ValidationProbeEvent.PROBE_HTTP); } if ((mIsHttps && mResult.isSuccessful()) || (!mIsHttps && mResult.isPortal())) { // Stop waiting immediately if https succeeds or if http finds a portal. From 48a1136c8b3000c651e8bcd86325acd1dce6e4ec Mon Sep 17 00:00:00 2001 From: Stephen Chen Date: Fri, 21 Oct 2016 12:44:26 -0700 Subject: [PATCH 36/45] Implement metered tracking for NetworkStats summary queries. Dependent on ag/1550196 where API is defined. Bug: 31015360 Bug: 26545374 Test: runtest --path frameworks/base/core/tests/coretests/src/android/net/NetworkStatsTest.java, other test classes. (cherry picked from commit 25147878974f82f875062e99cdee85dd33f3f078) Change-Id: I46da93ba4afa968facf98f7c3d844fd0c469095a --- core/java/android/app/usage/NetworkStats.java | 12 +- .../app/usage/NetworkStatsManager.java | 43 +- core/java/android/net/NetworkIdentity.java | 6 +- core/java/android/net/NetworkStats.java | 103 +++- ...droid_internal_net_NetworkStatsFactory.cpp | 8 +- .../src/android/net/NetworkStatsTest.java | 528 ++++++++++-------- .../internal/net/NetworkStatsFactoryTest.java | 14 +- .../server/net/NetworkIdentitySet.java | 13 + .../server/net/NetworkStatsCollection.java | 3 + .../server/net/NetworkStatsObserversTest.java | 22 +- .../server/net/NetworkStatsServiceTest.java | 159 ++++-- 11 files changed, 561 insertions(+), 350 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index f64bec73e4c8f..3670b914ecf37 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -256,6 +256,15 @@ public final class NetworkStats implements AutoCloseable { return tag; } + private static @Metered int convertMetered(int metered) { + switch (metered) { + case android.net.NetworkStats.METERED_ALL : return METERED_ALL; + case android.net.NetworkStats.METERED_NO: return METERED_NO; + case android.net.NetworkStats.METERED_YES: return METERED_YES; + } + return 0; + } + private static @Roaming int convertRoaming(int roaming) { switch (roaming) { case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL; @@ -530,8 +539,7 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); - // TODO: Implement metered tracking. - bucketOut.mMetered = Bucket.METERED_ALL; + bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered); bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; bucketOut.mEndTimeStamp = mEndTimeStamp; diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 7961a72a12e44..840413a1151e8 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -51,16 +51,17 @@ import android.util.Log; * {@link #querySummaryForUser}

* {@link #querySummary}

* These queries aggregate network usage across the whole interval. Therefore there will be only one - * bucket for a particular key and state and roaming combination. In case of the user-wide and - * device-wide summaries a single bucket containing the totalised network usage is returned. + * bucket for a particular key, state, metered and roaming combination. In case of the user-wide + * and device-wide summaries a single bucket containing the totalised network usage is returned. *

* History queries *

* {@link #queryDetailsForUid}

* {@link #queryDetails}

- * These queries do not aggregate over time but do aggregate over state and roaming. Therefore there - * can be multiple buckets for a particular key but all Bucket's state is going to be - * {@link NetworkStats.Bucket#STATE_ALL} and all Bucket's roaming is going to be + * These queries do not aggregate over time but do aggregate over state, metered and roaming. + * Therefore there can be multiple buckets for a particular key but all Bucket's state is going to + * be {@link NetworkStats.Bucket#STATE_ALL}, all Bucket's metered is going to be + * {@link NetworkStats.Bucket#METERED_ALL}, and all Bucket's roaming is going to be * {@link NetworkStats.Bucket#ROAMING_ALL}. *

* NOTE: Calling {@link #querySummaryForDevice} or accessing stats for apps other than the @@ -103,10 +104,11 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result is summarised data usage for the whole - * device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This - * means the bucket's start and end timestamp are going to be the same as the 'startTime' and - * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid - * {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE} + * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and + * roaming. This means the bucket's start and end timestamp are going to be the same as the + * 'startTime' and 'endTime' parameters. State is going to be + * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL}, + * tag {@link NetworkStats.Bucket#TAG_NONE}, metered {@link NetworkStats.Bucket#METERED_ALL}, * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. @@ -142,8 +144,10 @@ public class NetworkStatsManager { * Query network usage statistics summaries. Result is summarised data usage for all uids * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. * This means the bucket's start and end timestamp are going to be the same as the 'startTime' - * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid - * {@link NetworkStats.Bucket#UID_ALL}. + * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, + * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, + * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming + * {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -177,9 +181,10 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. Not aggregated over state or uid. This means buckets' start and end - * timestamps are going to be the same as the 'startTime' and 'endTime' parameters. - * State and uid are going to vary, and tag is going to be the same. + * end timestamps. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, + * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, + * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming + * {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -262,10 +267,12 @@ public class NetworkStatsManager { /** * Query network usage statistics details. Result filtered to include only uids belonging to - * calling user. Result is aggregated over state but not aggregated over time or uid. This means - * buckets' start and end timestamps are going to be between 'startTime' and 'endTime' - * parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, - * tag {@link NetworkStats.Bucket#TAG_NONE} and roaming is going to be + * calling user. Result is aggregated over state but not aggregated over time, uid, tag, + * metered, nor roaming. This means buckets' start and end timestamps are going to be between + * 'startTime' and 'endTime' parameters. State is going to be + * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, + * tag {@link NetworkStats.Bucket#TAG_NONE}, metered is going to be + * {@link NetworkStats.Bucket#METERED_ALL}, and roaming is going to be * {@link NetworkStats.Bucket#ROAMING_ALL}. *

Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index d570e66a24357..c704ef0c9ca7c 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -171,7 +171,8 @@ public class NetworkIdentity implements Comparable { String subscriberId = null; String networkId = null; boolean roaming = false; - boolean metered = false; + boolean metered = !state.networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_METERED); if (isNetworkTypeMobile(type)) { if (state.subscriberId == null) { @@ -185,9 +186,6 @@ public class NetworkIdentity implements Comparable { subscriberId = state.subscriberId; roaming = state.networkInfo.isRoaming(); - metered = !state.networkCapabilities.hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - } else if (type == TYPE_WIFI) { if (state.networkId != null) { networkId = state.networkId; diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index f65a50f02df32..77ce65b0815a5 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -68,11 +68,18 @@ public class NetworkStats implements Parcelable { // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; - /** {@link #set} value for all roaming values. */ + /** {@link #metered} value to account for all metered states. */ + public static final int METERED_ALL = -1; + /** {@link #metered} value where native, unmetered data is accounted. */ + public static final int METERED_NO = 0; + /** {@link #metered} value where metered data is accounted. */ + public static final int METERED_YES = 1; + + /** {@link #roaming} value to account for all roaming states. */ public static final int ROAMING_ALL = -1; - /** {@link #set} value where native, non-roaming data is accounted. */ + /** {@link #roaming} value where native, non-roaming data is accounted. */ public static final int ROAMING_NO = 0; - /** {@link #set} value where roaming data is accounted. */ + /** {@link #roaming} value where roaming data is accounted. */ public static final int ROAMING_YES = 1; // TODO: move fields to "mVariable" notation @@ -88,6 +95,7 @@ public class NetworkStats implements Parcelable { private int[] uid; private int[] set; private int[] tag; + private int[] metered; private int[] roaming; private long[] rxBytes; private long[] rxPackets; @@ -100,6 +108,12 @@ public class NetworkStats implements Parcelable { public int uid; public int set; public int tag; + /** + * Note that this is only populated w/ the default value when read from /proc or written + * to disk. We merge in the correct value when reporting this value to clients of + * getSummary(). + */ + public int metered; /** * Note that this is only populated w/ the default value when read from /proc or written * to disk. We merge in the correct value when reporting this value to clients of @@ -123,16 +137,17 @@ public class NetworkStats implements Parcelable { public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - this(iface, uid, set, tag, ROAMING_NO, rxBytes, rxPackets, txBytes, txPackets, - operations); + this(iface, uid, set, tag, METERED_NO, ROAMING_NO, rxBytes, rxPackets, txBytes, + txPackets, operations); } - public Entry(String iface, int uid, int set, int tag, int roaming, long rxBytes, - long rxPackets, long txBytes, long txPackets, long operations) { + public Entry(String iface, int uid, int set, int tag, int metered, int roaming, + long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { this.iface = iface; this.uid = uid; this.set = set; this.tag = tag; + this.metered = metered; this.roaming = roaming; this.rxBytes = rxBytes; this.rxPackets = rxPackets; @@ -165,6 +180,7 @@ public class NetworkStats implements Parcelable { builder.append(" uid=").append(uid); builder.append(" set=").append(setToString(set)); builder.append(" tag=").append(tagToString(tag)); + builder.append(" metered=").append(meteredToString(metered)); builder.append(" roaming=").append(roamingToString(roaming)); builder.append(" rxBytes=").append(rxBytes); builder.append(" rxPackets=").append(rxPackets); @@ -178,13 +194,18 @@ public class NetworkStats implements Parcelable { public boolean equals(Object o) { if (o instanceof Entry) { final Entry e = (Entry) o; - return uid == e.uid && set == e.set && tag == e.tag && roaming == e.roaming - && rxBytes == e.rxBytes && rxPackets == e.rxPackets && txBytes == e.txBytes - && txPackets == e.txPackets && operations == e.operations - && iface.equals(e.iface); + return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered + && roaming == e.roaming && rxBytes == e.rxBytes && rxPackets == e.rxPackets + && txBytes == e.txBytes && txPackets == e.txPackets + && operations == e.operations && iface.equals(e.iface); } return false; } + + @Override + public int hashCode() { + return Objects.hash(uid, set, tag, metered, roaming, iface); + } } public NetworkStats(long elapsedRealtime, int initialSize) { @@ -196,6 +217,7 @@ public class NetworkStats implements Parcelable { this.uid = new int[initialSize]; this.set = new int[initialSize]; this.tag = new int[initialSize]; + this.metered = new int[initialSize]; this.roaming = new int[initialSize]; this.rxBytes = new long[initialSize]; this.rxPackets = new long[initialSize]; @@ -209,6 +231,7 @@ public class NetworkStats implements Parcelable { this.uid = EmptyArray.INT; this.set = EmptyArray.INT; this.tag = EmptyArray.INT; + this.metered = EmptyArray.INT; this.roaming = EmptyArray.INT; this.rxBytes = EmptyArray.LONG; this.rxPackets = EmptyArray.LONG; @@ -226,6 +249,7 @@ public class NetworkStats implements Parcelable { uid = parcel.createIntArray(); set = parcel.createIntArray(); tag = parcel.createIntArray(); + metered = parcel.createIntArray(); roaming = parcel.createIntArray(); rxBytes = parcel.createLongArray(); rxPackets = parcel.createLongArray(); @@ -243,6 +267,7 @@ public class NetworkStats implements Parcelable { dest.writeIntArray(uid); dest.writeIntArray(set); dest.writeIntArray(tag); + dest.writeIntArray(metered); dest.writeIntArray(roaming); dest.writeLongArray(rxBytes); dest.writeLongArray(rxPackets); @@ -277,10 +302,11 @@ public class NetworkStats implements Parcelable { } @VisibleForTesting - public NetworkStats addValues(String iface, int uid, int set, int tag, int roaming, + public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { return addValues(new Entry( - iface, uid, set, tag, roaming, rxBytes, rxPackets, txBytes, txPackets, operations)); + iface, uid, set, tag, metered, roaming, rxBytes, rxPackets, txBytes, txPackets, + operations)); } /** @@ -294,6 +320,7 @@ public class NetworkStats implements Parcelable { uid = Arrays.copyOf(uid, newLength); set = Arrays.copyOf(set, newLength); tag = Arrays.copyOf(tag, newLength); + metered = Arrays.copyOf(metered, newLength); roaming = Arrays.copyOf(roaming, newLength); rxBytes = Arrays.copyOf(rxBytes, newLength); rxPackets = Arrays.copyOf(rxPackets, newLength); @@ -307,6 +334,7 @@ public class NetworkStats implements Parcelable { uid[size] = entry.uid; set[size] = entry.set; tag[size] = entry.tag; + metered[size] = entry.metered; roaming[size] = entry.roaming; rxBytes[size] = entry.rxBytes; rxPackets[size] = entry.rxPackets; @@ -327,6 +355,7 @@ public class NetworkStats implements Parcelable { entry.uid = uid[i]; entry.set = set[i]; entry.tag = tag[i]; + entry.metered = metered[i]; entry.roaming = roaming[i]; entry.rxBytes = rxBytes[i]; entry.rxPackets = rxPackets[i]; @@ -381,7 +410,8 @@ public class NetworkStats implements Parcelable { * also be used to subtract values from existing rows. */ public NetworkStats combineValues(Entry entry) { - final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.roaming); + final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, + entry.roaming); if (i == -1) { // only create new entry when positive contribution addValues(entry); @@ -409,10 +439,11 @@ public class NetworkStats implements Parcelable { /** * Find first stats index that matches the requested parameters. */ - public int findIndex(String iface, int uid, int set, int tag, int roaming) { + public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming) { for (int i = 0; i < size; i++) { if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { + && metered == this.metered[i] && roaming == this.roaming[i] + && Objects.equals(iface, this.iface[i])) { return i; } } @@ -424,7 +455,7 @@ public class NetworkStats implements Parcelable { * search around the hinted index as an optimization. */ @VisibleForTesting - public int findIndexHinted(String iface, int uid, int set, int tag, int roaming, + public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming, int hintIndex) { for (int offset = 0; offset < size; offset++) { final int halfOffset = offset / 2; @@ -438,7 +469,8 @@ public class NetworkStats implements Parcelable { } if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { + && metered == this.metered[i] && roaming == this.roaming[i] + && Objects.equals(iface, this.iface[i])) { return i; } } @@ -452,7 +484,7 @@ public class NetworkStats implements Parcelable { */ public void spliceOperationsFrom(NetworkStats stats) { for (int i = 0; i < size; i++) { - final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], roaming[i]); + final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i]); if (j == -1) { operations[i] = 0; } else { @@ -542,6 +574,7 @@ public class NetworkStats implements Parcelable { entry.uid = limitUid; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; entry.rxBytes = 0; entry.rxPackets = 0; @@ -637,11 +670,12 @@ public class NetworkStats implements Parcelable { entry.uid = left.uid[i]; entry.set = left.set[i]; entry.tag = left.tag[i]; + entry.metered = left.metered[i]; entry.roaming = left.roaming[i]; // find remote row that matches, and subtract final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, - entry.roaming, i); + entry.metered, entry.roaming, i); if (j == -1) { // newly appearing row, return entire value entry.rxBytes = left.rxBytes[i]; @@ -687,6 +721,7 @@ public class NetworkStats implements Parcelable { entry.uid = UID_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; entry.operations = 0L; @@ -716,6 +751,7 @@ public class NetworkStats implements Parcelable { entry.iface = IFACE_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; for (int i = 0; i < size; i++) { @@ -762,6 +798,7 @@ public class NetworkStats implements Parcelable { pw.print(" uid="); pw.print(uid[i]); pw.print(" set="); pw.print(setToString(set[i])); pw.print(" tag="); pw.print(tagToString(tag[i])); + pw.print(" metered="); pw.print(meteredToString(metered[i])); pw.print(" roaming="); pw.print(roamingToString(roaming[i])); pw.print(" rxBytes="); pw.print(rxBytes[i]); pw.print(" rxPackets="); pw.print(rxPackets[i]); @@ -829,6 +866,22 @@ public class NetworkStats implements Parcelable { return "0x" + Integer.toHexString(tag); } + /** + * Return text description of {@link #metered} value. + */ + public static String meteredToString(int metered) { + switch (metered) { + case METERED_ALL: + return "ALL"; + case METERED_NO: + return "NO"; + case METERED_YES: + return "YES"; + default: + return "UNKNOWN"; + } + } + /** * Return text description of {@link #roaming} value. */ @@ -998,6 +1051,7 @@ public class NetworkStats implements Parcelable { tmpEntry.uid = uid[i]; tmpEntry.tag = tag[i]; tmpEntry.set = set[i]; + tmpEntry.metered = metered[i]; tmpEntry.roaming = roaming[i]; combineValues(tmpEntry); if (tag[i] == TAG_NONE) { @@ -1017,24 +1071,25 @@ public class NetworkStats implements Parcelable { moved.set = SET_DBG_VPN_OUT; moved.tag = TAG_NONE; moved.iface = underlyingIface; + moved.metered = METERED_ALL; moved.roaming = ROAMING_ALL; combineValues(moved); // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than // the TAG_NONE traffic. // - // Relies on the fact that the underlying traffic only has state ROAMING_NO, which - // should be the case as it comes directly from the /proc file. We only blend in the + // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO, + // which should be the case as it comes directly from the /proc file. We only blend in the // roaming data after applying these adjustments, by checking the NetworkIdentity of the // underlying iface. int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, - ROAMING_NO); + METERED_NO, ROAMING_NO); if (idxVpnBackground != -1) { tunSubtract(idxVpnBackground, this, moved); } int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, - ROAMING_NO); + METERED_NO, ROAMING_NO); if (idxVpnForeground != -1) { tunSubtract(idxVpnForeground, this, moved); } diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 9fa90acc02a43..4a2b88142e788 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -43,6 +43,7 @@ static struct { jfieldID uid; jfieldID set; jfieldID tag; + jfieldID metered; jfieldID roaming; jfieldID rxBytes; jfieldID rxPackets; @@ -239,6 +240,9 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, ScopedIntArrayRW tag(env, get_int_array(env, stats, gNetworkStatsClassInfo.tag, size, grow)); if (tag.get() == NULL) return -1; + ScopedIntArrayRW metered(env, get_int_array(env, stats, + gNetworkStatsClassInfo.metered, size, grow)); + if (metered.get() == NULL) return -1; ScopedIntArrayRW roaming(env, get_int_array(env, stats, gNetworkStatsClassInfo.roaming, size, grow)); if (roaming.get() == NULL) return -1; @@ -265,7 +269,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, uid[i] = lines[i].uid; set[i] = lines[i].set; tag[i] = lines[i].tag; - // Roaming is populated in Java-land by inspecting the iface properties. + // Metered and Roaming are populated in Java-land by inspecting the iface properties. rxBytes[i] = lines[i].rxBytes; rxPackets[i] = lines[i].rxPackets; txBytes[i] = lines[i].txBytes; @@ -279,6 +283,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.metered, metered.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.roaming, roaming.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray()); @@ -311,6 +316,7 @@ int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) { gNetworkStatsClassInfo.uid = GetFieldIDOrDie(env, clazz, "uid", "[I"); gNetworkStatsClassInfo.set = GetFieldIDOrDie(env, clazz, "set", "[I"); gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I"); + gNetworkStatsClassInfo.metered = GetFieldIDOrDie(env, clazz, "metered", "[I"); gNetworkStatsClassInfo.roaming = GetFieldIDOrDie(env, clazz, "roaming", "[I"); gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J"); gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J"); diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java index d48a67a4c72f7..eb85eb445cbcd 100644 --- a/core/tests/coretests/src/android/net/NetworkStatsTest.java +++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java @@ -16,6 +16,9 @@ package android.net; +import static android.net.NetworkStats.METERED_ALL; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_ALL; import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; @@ -45,103 +48,124 @@ public class NetworkStatsTest extends TestCase { private static final long TEST_START = 1194220800000L; public void testFindIndex() throws Exception { - final NetworkStats stats = new NetworkStats(TEST_START, 4) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L, 0L, - 0L, 10) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 1024L, - 8L, 11) - .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L, - 1024L, 8L, 12) - .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_YES, 1024L, 8L, - 1024L, 8L, 12); + final NetworkStats stats = new NetworkStats(TEST_START, 5) + .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L, + 8L, 0L, 0L, 10) + .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L, + 1024L, 8L, 11) + .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 0L, 0L, + 1024L, 8L, 11) + .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L, + 8L, 1024L, 8L, 12) + .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 1024L, + 8L, 1024L, 8L, 12); - assertEquals(3, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_YES)); - assertEquals(2, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO)); - assertEquals(1, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO)); - assertEquals(0, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO)); - assertEquals(-1, stats.findIndex(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE, ROAMING_NO)); + assertEquals(4, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, + ROAMING_YES)); + assertEquals(3, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO)); + assertEquals(2, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, + ROAMING_NO)); + assertEquals(1, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO)); + assertEquals(0, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO)); + assertEquals(-1, stats.findIndex(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO)); } public void testFindIndexHinted() { final NetworkStats stats = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L, 0L, - 0L, 10) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 1024L, - 8L, 11) - .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L, - 1024L, 8L, 12) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 1024L, 8L, - 0L, 0L, 10) - .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 0L, 0L, 1024L, - 8L, 11) - .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L, - 1024L, 8L, 12) - .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, ROAMING_YES, 1024L, 8L, - 1024L, 8L, 12); + .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L, + 8L, 0L, 0L, 10) + .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L, + 1024L, 8L, 11) + .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L, + 8L, 1024L, 8L, 12) + .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + 1024L, 8L, 0L, 0L, 10) + .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 0L, 0L, + 1024L, 8L, 11) + .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, 0L, 0L, + 1024L, 8L, 11) + .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L, + 8L, 1024L, 8L, 12) + .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 1024L, + 8L, 1024L, 8L, 12); // verify that we correctly find across regardless of hinting for (int hint = 0; hint < stats.size(); hint++) { assertEquals(0, stats.findIndexHinted(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, - ROAMING_NO, hint)); + METERED_NO, ROAMING_NO, hint)); assertEquals(1, stats.findIndexHinted(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, - ROAMING_NO, hint)); + METERED_NO, ROAMING_NO, hint)); assertEquals(2, stats.findIndexHinted(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, - ROAMING_NO, hint)); + METERED_NO, ROAMING_NO, hint)); assertEquals(3, stats.findIndexHinted(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, - ROAMING_NO, hint)); + METERED_NO, ROAMING_NO, hint)); assertEquals(4, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, - ROAMING_NO, hint)); - assertEquals(5, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, - ROAMING_NO, hint)); + METERED_NO, ROAMING_NO, hint)); + assertEquals(5, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, + METERED_YES, ROAMING_NO, hint)); assertEquals(6, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, - ROAMING_YES, hint)); + METERED_NO, ROAMING_NO, hint)); + assertEquals(7, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, + METERED_YES, ROAMING_YES, hint)); assertEquals(-1, stats.findIndexHinted(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE, - ROAMING_NO, hint)); + METERED_NO, ROAMING_NO, hint)); } } public void testAddEntryGrow() throws Exception { - final NetworkStats stats = new NetworkStats(TEST_START, 3); + final NetworkStats stats = new NetworkStats(TEST_START, 4); assertEquals(0, stats.size()); - assertEquals(3, stats.internalSize()); + assertEquals(4, stats.internalSize()); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L, 1L, 2L, - 2L, 3); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 2L, 2L, 2L, - 2L, 4); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 3L, 3L, 2L, - 2L, 5); - - assertEquals(3, stats.size()); - assertEquals(3, stats.internalSize()); - - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 4L, 40L, 4L, - 40L, 7); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 5L, 50L, 4L, - 40L, 8); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 6L, 60L, 5L, - 50L, 10); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 7L, 70L, 5L, - 50L, 11); - - assertEquals(7, stats.size()); - assertTrue(stats.internalSize() >= 7); - - assertValues(stats, 0, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L, 1L, + stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1L, 1L, 2L, 2L, 3); - assertValues(stats, 1, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 2L, 2L, + stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 2L, 2L, 2L, 2L, 4); - assertValues(stats, 2, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 3L, 3L, - 2L, 2L, 5); - assertValues(stats, 3, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 4L, + stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 3L, + 3L, 2L, 2L, 5); + stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 3L, + 3L, 2L, 2L, 5); + + assertEquals(4, stats.size()); + assertEquals(4, stats.internalSize()); + + stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 4L, 40L, 4L, 40L, 7); - assertValues(stats, 4, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 5L, + stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 5L, 50L, 4L, 40L, 8); - assertValues(stats, 5, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 6L, + stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 6L, 60L, 5L, 50L, 10); - assertValues(stats, 6, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 7L, + stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 7L, 70L, 5L, 50L, 11); + stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 7L, + 70L, 5L, 50L, 11); + + assertEquals(9, stats.size()); + assertTrue(stats.internalSize() >= 9); + + assertValues(stats, 0, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + 1L, 1L, 2L, 2L, 3); + assertValues(stats, 1, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + 2L, 2L, 2L, 2L, 4); + assertValues(stats, 2, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + 3L, 3L, 2L, 2L, 5); + assertValues(stats, 3, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, + ROAMING_YES, 3L, 3L, 2L, 2L, 5); + assertValues(stats, 4, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + 4L, 40L, 4L, 40L, 7); + assertValues(stats, 5, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + 5L, 50L, 4L, 40L, 8); + assertValues(stats, 6, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + 6L, 60L, 5L, 50L, 10); + assertValues(stats, 7, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + 7L, 70L, 5L, 50L, 11); + assertValues(stats, 8, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, + ROAMING_YES, 7L, 70L, 5L, 50L, 11); } public void testCombineExisting() throws Exception { @@ -152,20 +176,18 @@ public class NetworkStatsTest extends TestCase { stats.combineValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, -128L, -1L, -128L, -1L, -1); - assertValues(stats, 0, TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, ROAMING_NO, 384L, 3L, - 128L, 1L, 9); - assertValues(stats, 1, TEST_IFACE, 1001, SET_DEFAULT, 0xff, ROAMING_NO, 128L, 1L, 128L, - 1L, 2); + assertValues(stats, 0, TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + 384L, 3L, 128L, 1L, 9); + assertValues(stats, 1, TEST_IFACE, 1001, SET_DEFAULT, 0xff, METERED_NO, ROAMING_NO, 128L, + 1L, 128L, 1L, 2); // now try combining that should create row - stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, - 128L, 1L, 3); - assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 1L, - 128L, 1L, 3); - stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, - 128L, 1L, 3); - assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, ROAMING_NO, 256L, 2L, - 256L, 2L, 6); + stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 3); + assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + 128L, 1L, 128L, 1L, 3); + stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 3); + assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + 256L, 2L, 256L, 2L, 6); } public void testSubtractIdenticalData() throws Exception { @@ -180,10 +202,10 @@ public class NetworkStatsTest extends TestCase { final NetworkStats result = after.subtract(before); // identical data should result in zero delta - assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L, - 0L, 0); - assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L, - 0L, 0); + assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L, + 0L, 0L, 0L, 0); + assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L, + 0L, 0L, 0L, 0); } public void testSubtractIdenticalRows() throws Exception { @@ -198,10 +220,10 @@ public class NetworkStatsTest extends TestCase { final NetworkStats result = after.subtract(before); // expect delta between measurements - assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L, 1L, 2L, - 1L, 4); - assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 3L, 1L, 4L, - 1L, 8); + assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1L, + 1L, 2L, 1L, 4); + assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 3L, + 1L, 4L, 1L, 8); } public void testSubtractNewRows() throws Exception { @@ -217,12 +239,12 @@ public class NetworkStatsTest extends TestCase { final NetworkStats result = after.subtract(before); // its okay to have new rows - assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L, - 0L, 0); - assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L, - 0L, 0); - assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L, - 1024L, 8L, 20); + assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L, + 0L, 0L, 0L, 0); + assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L, + 0L, 0L, 0L, 0); + assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + 1024L, 8L, 1024L, 8L, 20); } public void testSubtractMissingRows() throws Exception { @@ -237,8 +259,8 @@ public class NetworkStatsTest extends TestCase { // should silently drop omitted rows assertEquals(1, result.size()); - assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L, - 2L, 3L, 4L, 0); + assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, 1L, 2L, 3L, 4L, 0); assertEquals(4L, result.getTotalBytes()); } @@ -263,13 +285,22 @@ public class NetworkStatsTest extends TestCase { .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L); assertEquals(64L, uidTag.getTotalBytes()); + final NetworkStats uidMetered = new NetworkStats(TEST_START, 3) + .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 32L, 0L, + 0L, 0L, 0L) + .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L, + 0L, 0L, 0L) + .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L, + 0L, 0L, 0L); + assertEquals(96L, uidMetered.getTotalBytes()); + final NetworkStats uidRoaming = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L, - 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L, - 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_YES, 32L, 0L, 0L, 0L, - 0L); + .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 32L, 0L, + 0L, 0L, 0L) + .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L, + 0L, 0L, 0L) + .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 32L, 0L, + 0L, 0L, 0L); assertEquals(96L, uidRoaming.getTotalBytes()); } @@ -283,95 +314,95 @@ public class NetworkStatsTest extends TestCase { public void testGroupedByIfaceAll() throws Exception { final NetworkStats uidStats = new NetworkStats(TEST_START, 3) - .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, ROAMING_NO, 128L, 8L, 0L, 2L, - 20L) - .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 128L, 8L, 0L, + .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L, 0L, 2L, 20L) - .addValues(IFACE_ALL, 101, SET_ALL, TAG_NONE, ROAMING_YES, 128L, 8L, 0L, 2L, - 20L); + .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO, 128L, + 8L, 0L, 2L, 20L) + .addValues(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES, 128L, 8L, 0L, + 2L, 20L); final NetworkStats grouped = uidStats.groupedByIface(); assertEquals(3, uidStats.size()); assertEquals(1, grouped.size()); - assertValues(grouped, 0, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, ROAMING_ALL, 384L, 24L, 0L, - 6L, 0L); + assertValues(grouped, 0, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + 384L, 24L, 0L, 6L, 0L); } public void testGroupedByIface() throws Exception { final NetworkStats uidStats = new NetworkStats(TEST_START, 7) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L, - 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 512L, 32L, 0L, - 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 4L, 0L, 0L, - 0L) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 512L, 32L, + .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L, + 0L, 2L, 20L) + .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 512L, + 32L, 0L, 0L, 0L) + .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L, 4L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L, - 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 128L, 8L, 0L, 0L, - 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_YES, 128L, 8L, 0L, - 0L, 0L); + .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 512L, + 32L, 0L, 0L, 0L) + .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L, + 0L, 0L, 0L) + .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, 128L, 8L, + 0L, 0L, 0L) + .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 128L, + 8L, 0L, 0L, 0L); final NetworkStats grouped = uidStats.groupedByIface(); assertEquals(7, uidStats.size()); assertEquals(2, grouped.size()); - assertValues(grouped, 0, TEST_IFACE, UID_ALL, SET_ALL, TAG_NONE, ROAMING_ALL, 384L, 24L, 0L, - 2L, 0L); - assertValues(grouped, 1, TEST_IFACE2, UID_ALL, SET_ALL, TAG_NONE, ROAMING_ALL, 1024L, 64L, - 0L, 0L, 0L); + assertValues(grouped, 0, TEST_IFACE, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + 384L, 24L, 0L, 2L, 0L); + assertValues(grouped, 1, TEST_IFACE2, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + 1024L, 64L, 0L, 0L, 0L); } public void testAddAllValues() { final NetworkStats first = new NetworkStats(TEST_START, 5) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L, - 0L) - .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, - 0L, 0L) - .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_YES, 32L, 0L, 0L, - 0L, 0L); + .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L, + 0L, 0L, 0L) + .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 32L, + 0L, 0L, 0L, 0L) + .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, 32L, + 0L, 0L, 0L, 0L); final NetworkStats second = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L, - 0L) - .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, + .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_YES, 32L, 0L, 0L, - 0L, 0L); + .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 32L, + 0L, 0L, 0L, 0L) + .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, 32L, + 0L, 0L, 0L, 0L); first.combineAllValues(second); assertEquals(4, first.size()); - assertValues(first, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 64L, 0L, 0L, - 0L, 0L); - assertValues(first, 1, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 32L, 0L, - 0L, 0L, 0L); - assertValues(first, 2, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_YES, 64L, 0L, - 0L, 0L, 0L); - assertValues(first, 3, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, + assertValues(first, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 64L, 0L, 0L, 0L, 0L); + assertValues(first, 1, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + 32L, 0L, 0L, 0L, 0L); + assertValues(first, 2, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, + 64L, 0L, 0L, 0L, 0L); + assertValues(first, 3, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + 32L, 0L, 0L, 0L, 0L); } public void testGetTotal() { final NetworkStats stats = new NetworkStats(TEST_START, 7) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L, - 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 512L, 32L, 0L, - 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 4L, 0L, 0L, - 0L) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 512L, 32L, + .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L, + 0L, 2L, 20L) + .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 512L, + 32L, 0L, 0L, 0L) + .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L, 4L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L, - 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 128L, 8L, 0L, 0L, - 0L) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_YES, 128L, 8L, 0L, - 0L, 0L); + .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 512L, + 32L, 0L, 0L, 0L) + .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 128L, + 8L, 0L, 0L, 0L) + .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 128L, 8L, + 0L, 0L, 0L) + .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 128L, + 8L, 0L, 0L, 0L); assertValues(stats.getTotal(null), 1408L, 88L, 0L, 2L, 20L); assertValues(stats.getTotal(null, 100), 1280L, 80L, 0L, 2L, 20L); @@ -396,10 +427,10 @@ public class NetworkStatsTest extends TestCase { final NetworkStats after = before.withoutUids(new int[] { 100 }); assertEquals(6, before.size()); assertEquals(2, after.size()); - assertValues(after, 0, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, - 0L, 0L, 0L); - assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 128L, 8L, 0L, - 0L, 0L); + assertValues(after, 0, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + 128L, 8L, 0L, 0L, 0L); + assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 128L, + 8L, 0L, 0L, 0L); } public void testClone() throws Exception { @@ -434,77 +465,90 @@ public class NetworkStatsTest extends TestCase { final String underlyingIface = "wlan0"; final int testTag1 = 8888; NetworkStats delta = new NetworkStats(TEST_START, 17) - .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, 39605L, 46L, 12259L, 55L, 0L) - .addValues(tunIface, 10100, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L) - .addValues(tunIface, 10120, SET_DEFAULT, TAG_NONE, 72667L, 197L, 43909L, 241L, 0L) - .addValues(tunIface, 10120, SET_FOREGROUND, TAG_NONE, 9297L, 17L, 4128L, 21L, 0L) + .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 39605L, 46L, + 12259L, 55L, 0L) + .addValues(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L, + 0L, 0L, 0L) + .addValues(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 72667L, 197L, + 43909L, 241L, 0L) + .addValues(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 9297L, + 17L, 4128L, 21L, 0L) // VPN package also uses some traffic through unprotected network. - .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, 4983L, 10L, 1801L, 12L, 0L) - .addValues(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L) + .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 4983L, 10L, + 1801L, 12L, 0L) + .addValues(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L, + 0L, 0L, 0L) // Tag entries - .addValues(tunIface, 10120, SET_DEFAULT, testTag1, 21691L, 41L, 13820L, 51L, 0L) - .addValues(tunIface, 10120, SET_FOREGROUND, testTag1, 1281L, 2L, 665L, 2L, 0L) + .addValues(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO, 21691L, 41L, + 13820L, 51L, 0L) + .addValues(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO, 1281L, 2L, + 665L, 2L, 0L) // Irrelevant entries - .addValues(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, 1685L, 5L, 2070L, 6L, 0L) + .addValues(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1685L, 5L, + 2070L, 6L, 0L) // Underlying Iface entries - .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, 5178L, 8L, 2139L, 11L, 0L) - .addValues(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L) - .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, 149873L, 287L, - 59217L /* smaller than sum(tun0) */, 299L /* smaller than sum(tun0) */, 0L) - .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L); + .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 5178L, + 8L, 2139L, 11L, 0L) + .addValues(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 0L, + 0L, 0L, 0L, 0L) + .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + 149873L, 287L, 59217L /* smaller than sum(tun0) */, + 299L /* smaller than sum(tun0) */, 0L) + .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + 0L, 0L, 0L, 0L, 0L); assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface)); assertEquals(20, delta.size()); // tunIface and TEST_IFACE entries are not changed. - assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO, + assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 39605L, 46L, 12259L, 55L, 0L); - assertValues(delta, 1, tunIface, 10100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 0L, 0L, - 0L, 0L, 0L); - assertValues(delta, 2, tunIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_NO, + assertValues(delta, 1, tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + 0L, 0L, 0L, 0L, 0L); + assertValues(delta, 2, tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 72667L, 197L, 43909L, 241L, 0L); - assertValues(delta, 3, tunIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_NO, + assertValues(delta, 3, tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 9297L, 17L, 4128L, 21L, 0L); - assertValues(delta, 4, tunIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO, + assertValues(delta, 4, tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 4983L, 10L, 1801L, 12L, 0L); - assertValues(delta, 5, tunIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 0L, 0L, - 0L, 0L, 0L); - assertValues(delta, 6, tunIface, 10120, SET_DEFAULT, testTag1, ROAMING_NO, + assertValues(delta, 5, tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + 0L, 0L, 0L, 0L, 0L); + assertValues(delta, 6, tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO, 21691L, 41L, 13820L, 51L, 0L); - assertValues(delta, 7, tunIface, 10120, SET_FOREGROUND, testTag1, ROAMING_NO, 1281L, - 2L, 665L, 2L, 0L); - assertValues(delta, 8, TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1685L, 5L, - 2070L, 6L, 0L); + assertValues(delta, 7, tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO, + 1281L, 2L, 665L, 2L, 0L); + assertValues(delta, 8, TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + 1685L, 5L, 2070L, 6L, 0L); // Existing underlying Iface entries are updated - assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO, - 44783L, 54L, 14178L, 62L, 0L); - assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, - 0L, 0L, 0L, 0L, 0L); + assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, 44783L, 54L, 14178L, 62L, 0L); + assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, + ROAMING_NO, 0L, 0L, 0L, 0L, 0L); // VPN underlying Iface entries are updated - assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO, - 28304L, 27L, 1L, 2L, 0L); - assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_NO, - 0L, 0L, 0L, 0L, 0L); + assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, 28304L, 27L, 1L, 2L, 0L); + assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, + ROAMING_NO, 0L, 0L, 0L, 0L, 0L); // New entries are added for new application's underlying Iface traffic - assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_NO, - 72667L, 197L, 43123L, 227L, 0L); - assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_NO, - 9297L, 17L, 4054, 19L, 0L); - assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, ROAMING_NO, - 21691L, 41L, 13572L, 48L, 0L); - assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, ROAMING_NO, - 1281L, 2L, 653L, 1L, 0L); + assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, 72667L, 197L, 43123L, 227L, 0L); + assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, + ROAMING_NO, 9297L, 17L, 4054, 19L, 0L); + assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, METERED_NO, + ROAMING_NO, 21691L, 41L, 13572L, 48L, 0L); + assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, + ROAMING_NO, 1281L, 2L, 653L, 1L, 0L); // New entries are added for debug purpose - assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO, - 39605L, 46L, 12039, 51, 0); - assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO, - 81964, 214, 47177, 246, 0); - assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, ROAMING_ALL, - 121569, 260, 59216, 297, 0); + assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO, + ROAMING_NO, 39605L, 46L, 12039, 51, 0); + assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, METERED_NO, + ROAMING_NO, 81964, 214, 47177, 246, 0); + assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, METERED_ALL, + ROAMING_ALL, 121569, 260, 59216, 297, 0); } @@ -518,72 +562,78 @@ public class NetworkStatsTest extends TestCase { final String underlyingIface = "wlan0"; NetworkStats delta = new NetworkStats(TEST_START, 9) // 2 different apps sent/receive data via tun0. - .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, 50000L, 25L, 100000L, 50L, 0L) - .addValues(tunIface, 20100, SET_DEFAULT, TAG_NONE, 500L, 2L, 200L, 5L, 0L) + .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 50000L, 25L, + 100000L, 50L, 0L) + .addValues(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 500L, 2L, + 200L, 5L, 0L) // VPN package resends data through the tunnel (with exaggerated overhead) - .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, 240000, 100L, 120000L, 60L, 0L) + .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 240000, + 100L, 120000L, 60L, 0L) // 1 app already has some traffic on the underlying interface, the other doesn't yet - .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, 1000L, 10L, 2000L, 20L, 0L) + .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1000L, + 10L, 2000L, 20L, 0L) // Traffic through the underlying interface via the vpn app. // This test should redistribute this data correctly. - .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, + .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 75500L, 37L, 130000L, 70L, 0L); assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface)); assertEquals(9, delta.size()); // tunIface entries should not be changed. - assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO, + assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 50000L, 25L, 100000L, 50L, 0L); - assertValues(delta, 1, tunIface, 20100, SET_DEFAULT, TAG_NONE, ROAMING_NO, + assertValues(delta, 1, tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 500L, 2L, 200L, 5L, 0L); - assertValues(delta, 2, tunIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO, + assertValues(delta, 2, tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 240000L, 100L, 120000L, 60L, 0L); // Existing underlying Iface entries are updated - assertValues(delta, 3, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO, - 51000L, 35L, 102000L, 70L, 0L); + assertValues(delta, 3, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, 51000L, 35L, 102000L, 70L, 0L); // VPN underlying Iface entries are updated - assertValues(delta, 4, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO, - 25000L, 10L, 29800L, 15L, 0L); + assertValues(delta, 4, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, 25000L, 10L, 29800L, 15L, 0L); // New entries are added for new application's underlying Iface traffic - assertContains(delta, underlyingIface, 20100, SET_DEFAULT, TAG_NONE, ROAMING_NO, - 500L, 2L, 200L, 5L, 0L); + assertContains(delta, underlyingIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, 500L, 2L, 200L, 5L, 0L); // New entries are added for debug purpose - assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO, - 50000L, 25L, 100000L, 50L, 0L); - assertContains(delta, underlyingIface, 20100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO, - 500, 2L, 200L, 5L, 0L); - assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, ROAMING_ALL, - 50500L, 27L, 100200L, 55, 0); + assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO, + ROAMING_NO, 50000L, 25L, 100000L, 50L, 0L); + assertContains(delta, underlyingIface, 20100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO, + ROAMING_NO, 500, 2L, 200L, 5L, 0L); + assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, METERED_ALL, + ROAMING_ALL, 50500L, 27L, 100200L, 55, 0); } private static void assertContains(NetworkStats stats, String iface, int uid, int set, - int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets, - long operations) { - int index = stats.findIndex(iface, uid, set, tag, roaming); + int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes, + long txPackets, long operations) { + int index = stats.findIndex(iface, uid, set, tag, metered, roaming); assertTrue(index != -1); - assertValues(stats, index, iface, uid, set, tag, roaming, + assertValues(stats, index, iface, uid, set, tag, metered, roaming, rxBytes, rxPackets, txBytes, txPackets, operations); } private static void assertValues(NetworkStats stats, int index, String iface, int uid, int set, - int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets, - long operations) { + int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes, + long txPackets, long operations) { final NetworkStats.Entry entry = stats.getValues(index, null); - assertValues(entry, iface, uid, set, tag, roaming); + assertValues(entry, iface, uid, set, tag, metered, roaming); assertValues(entry, rxBytes, rxPackets, txBytes, txPackets, operations); } private static void assertValues( - NetworkStats.Entry entry, String iface, int uid, int set, int tag, int roaming) { + NetworkStats.Entry entry, String iface, int uid, int set, int tag, int metered, + int roaming) { assertEquals(iface, entry.iface); assertEquals(uid, entry.uid); assertEquals(set, entry.set); assertEquals(tag, entry.tag); + assertEquals(metered, entry.metered); assertEquals(roaming, entry.roaming); } diff --git a/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java b/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java index 327f3fda3f340..7f13abc6d2c5c 100644 --- a/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java +++ b/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java @@ -16,6 +16,7 @@ package com.android.internal.net; +import static android.net.NetworkStats.METERED_NO; import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; @@ -101,12 +102,14 @@ public class NetworkStatsFactoryTest extends AndroidTestCase { final NetworkStats stats = mFactory.readNetworkStatsDetail(); assertEquals(70, stats.size()); - assertStatsEntry(stats, "rmnet1", 10021, SET_DEFAULT, 0x30100000, 219110L, 578L, 227423L, 676L); + assertStatsEntry(stats, "rmnet1", 10021, SET_DEFAULT, 0x30100000, 219110L, 578L, 227423L, + 676L); assertStatsEntry(stats, "rmnet1", 10021, SET_FOREGROUND, 0x30100000, 742L, 3L, 1265L, 3L); } public void testNetworkStatsSingle() throws Exception { - stageFile(R.raw.xt_qtaguid_iface_typical, new File(mTestProc, "net/xt_qtaguid/iface_stat_all")); + stageFile(R.raw.xt_qtaguid_iface_typical, + new File(mTestProc, "net/xt_qtaguid/iface_stat_all")); final NetworkStats stats = mFactory.readNetworkStatsSummaryDev(); assertEquals(6, stats.size()); @@ -122,7 +125,8 @@ public class NetworkStatsFactoryTest extends AndroidTestCase { final NetworkStats stats = mFactory.readNetworkStatsSummaryXt(); assertEquals(3, stats.size()); assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 6824L, 16L, 5692L, 10L); - assertStatsEntry(stats, "rmnet1", UID_ALL, SET_ALL, TAG_NONE, 11153922L, 8051L, 190226L, 2468L); + assertStatsEntry(stats, "rmnet1", UID_ALL, SET_ALL, TAG_NONE, 11153922L, 8051L, 190226L, + 2468L); assertStatsEntry(stats, "rmnet2", UID_ALL, SET_ALL, TAG_NONE, 4968L, 35L, 3081L, 39L); } @@ -157,7 +161,7 @@ public class NetworkStatsFactoryTest extends AndroidTestCase { private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set, int tag, long rxBytes, long txBytes) { - final int i = stats.findIndex(iface, uid, set, tag, ROAMING_NO); + final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO); final NetworkStats.Entry entry = stats.getValues(i, null); assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); assertEquals("unexpected txBytes", txBytes, entry.txBytes); @@ -165,7 +169,7 @@ public class NetworkStatsFactoryTest extends AndroidTestCase { private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets) { - final int i = stats.findIndex(iface, uid, set, tag, ROAMING_NO); + final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO); final NetworkStats.Entry entry = stats.getValues(i, null); assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets); diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index 959a823290014..c48f43058fca7 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -91,6 +91,19 @@ public class NetworkIdentitySet extends HashSet implements } } + /** @return whether any {@link NetworkIdentity} in this set is considered metered. */ + public boolean isAnyMemberMetered() { + if (isEmpty()) { + return false; + } + for (NetworkIdentity ident : this) { + if (ident.getMetered()) { + return true; + } + } + return false; + } + /** @return whether any {@link NetworkIdentity} in this set is considered roaming. */ public boolean isAnyMemberRoaming() { if (isEmpty()) { diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 673dd8fbbd664..c45b4169f575b 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -17,6 +17,8 @@ package com.android.server.net; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.NetworkStats.SET_ALL; @@ -242,6 +244,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { entry.uid = key.uid; entry.set = key.set; entry.tag = key.tag; + entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO; entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO; entry.rxBytes = historyEntry.rxBytes; entry.rxPackets = historyEntry.rxPackets; diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java index 21560acbf3bb8..5eee7b948cd0c 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java @@ -25,6 +25,7 @@ import static org.mockito.Matchers.isA; import static org.mockito.Mockito.when; import static android.net.NetworkStats.SET_DEFAULT; +import static android.net.NetworkStats.METERED_NO; import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkTemplate.buildTemplateMobileAll; @@ -336,7 +337,7 @@ public class NetworkStatsObserversTest extends TestCase { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, + .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, @@ -344,7 +345,7 @@ public class NetworkStatsObserversTest extends TestCase { // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, + .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, @@ -374,7 +375,7 @@ public class NetworkStatsObserversTest extends TestCase { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, + .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, @@ -382,7 +383,7 @@ public class NetworkStatsObserversTest extends TestCase { // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, + .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, @@ -412,7 +413,7 @@ public class NetworkStatsObserversTest extends TestCase { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, + .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, @@ -420,7 +421,7 @@ public class NetworkStatsObserversTest extends TestCase { // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, + .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, @@ -450,16 +451,17 @@ public class NetworkStatsObserversTest extends TestCase { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_NO, - BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); + .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, VPN_INFO, TEST_START); // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_NO, - BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); + .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, + 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, VPN_INFO, TEST_START); 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 f2cf90ca916f0..728eb734c52e6 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java @@ -22,6 +22,9 @@ import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.METERED_ALL; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_ALL; import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; @@ -305,9 +308,10 @@ public class NetworkStatsServiceTest { // verify service recorded history assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0); assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10); - assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, ROAMING_NO, 512L, 4L, 256L, 2L, 4); - assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_NO, 512L, 4L, 256L, 2L, - 6); + assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, METERED_NO, ROAMING_NO, 512L, 4L, 256L, + 2L, 4); + assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, METERED_NO, ROAMING_NO, 512L, 4L, + 256L, 2L, 6); assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0); @@ -329,9 +333,10 @@ public class NetworkStatsServiceTest { // after systemReady(), we should have historical stats loaded again assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0); assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10); - assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, ROAMING_NO, 512L, 4L, 256L, 2L, 4); - assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_NO, 512L, 4L, 256L, 2L, - 6); + assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, METERED_NO, ROAMING_NO, 512L, 4L, 256L, + 2L, 4); + assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, METERED_NO, ROAMING_NO, 512L, 4L, + 256L, 2L, 6); assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0); } @@ -638,20 +643,20 @@ public class NetworkStatsServiceTest { NetworkStats stats = mSession.getSummaryForAllUid( sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true); assertEquals(3, stats.size()); - assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 50L, 5L, - 50L, 5L, 1); - assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 10L, 1L, 10L, - 1L, 1); - assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_NO, 2048L, 16L, - 1024L, 8L, 0); + assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 50L, + 5L, 50L, 5L, 1); + assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 10L, + 1L, 10L, 1L, 1); + assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + 2048L, 16L, 1024L, 8L, 0); // now verify that recent history only contains one uid final long currentTime = currentTimeMillis(); stats = mSession.getSummaryForAllUid( sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true); assertEquals(1, stats.size()); - assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L, - 512L, 4L, 0); + assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + 1024L, 8L, 512L, 4L, 0); } @Test @@ -705,14 +710,56 @@ public class NetworkStatsServiceTest { final NetworkStats stats = mSession.getSummaryForAllUid( sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true); assertEquals(4, stats.size()); - assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 2L, - 128L, 2L, 1); - assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 1L, 64L, - 1L, 1); - assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 32L, 2L, - 32L, 2L, 1); - assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, ROAMING_NO, 1L, 1L, 1L, - 1L, 1); + assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, + 2L, 128L, 2L, 1); + assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L, + 1L, 64L, 1L, 1); + assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + 32L, 2L, 32L, 2L, 1); + assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, METERED_NO, ROAMING_NO, 1L, + 1L, 1L, 1L, 1); + } + + @Test + public void testMetered() throws Exception { + // pretend that network comes online + expectCurrentTime(); + expectDefaultSettings(); + expectNetworkState(buildWifiState(true /* isMetered */)); + expectNetworkStatsSummary(buildEmptyStats()); + expectNetworkStatsUidDetail(buildEmptyStats()); + expectBandwidthControlCheck(); + + mService.forceUpdateIfaces(); + + + // create some initial traffic + incrementCurrentTime(HOUR_IN_MILLIS); + expectCurrentTime(); + expectDefaultSettings(); + expectNetworkStatsSummary(buildEmptyStats()); + // Note that all traffic from NetworkManagementService is tagged as METERED_NO and + // ROAMING_NO, because metered and roaming isn't tracked at that layer. We layer it + // on top by inspecting the iface properties. + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) + .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, + 2L, 128L, 2L, 0L) + .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L, + 1L, 64L, 1L, 0L)); + mService.incrementOperationCount(UID_RED, 0xF00D, 1); + + forcePollAndWaitForIdle(); + + // verify service recorded history + assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1); + // verify entire history present + final NetworkStats stats = mSession.getSummaryForAllUid( + sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true); + assertEquals(2, stats.size()); + assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + 128L, 2L, 128L, 2L, 1); + assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, 64L, + 1L, 64L, 1L, 1); } @Test @@ -733,14 +780,14 @@ public class NetworkStatsServiceTest { expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); - // Note that all traffic from NetworkManagementService is tagged as ROAMING_NO, because - // roaming isn't tracked at that layer. We layer it on top by inspecting the iface - // properties. + // Note that all traffic from NetworkManagementService is tagged as METERED_NO and + // ROAMING_NO, because metered and roaming isn't tracked at that layer. We layer it + // on top by inspecting the iface properties. expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 2L, - 128L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 1L, 64L, - 1L, 0L)); + .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO, + 128L, 2L, 128L, 2L, 0L) + .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO, 64L, + 1L, 64L, 1L, 0L)); forcePollAndWaitForIdle(); // verify service recorded history @@ -750,10 +797,10 @@ public class NetworkStatsServiceTest { final NetworkStats stats = mSession.getSummaryForAllUid( sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true); assertEquals(2, stats.size()); - assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_YES, 128L, 2L, - 128L, 2L, 0); - assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_YES, 64L, 1L, 64L, - 1L, 0); + assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_YES, + 128L, 2L, 128L, 2L, 0); + assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_YES, 64L, + 1L, 64L, 1L, 0); } @Test @@ -780,7 +827,8 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L); final String[] tetherIfacePairs = new String[] { TEST_IFACE, "wlan0" }; final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, 0L); + .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, + 0L); expectNetworkStatsUidDetail(uidStats, tetherIfacePairs, tetherStats); forcePollAndWaitForIdle(); @@ -923,18 +971,18 @@ public class NetworkStatsServiceTest { // verify summary API final NetworkStats stats = mSession.getSummaryForNetwork(template, start, end); - assertValues(stats, IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, rxBytes, - rxPackets, txBytes, txPackets, operations); + assertValues(stats, IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO, + rxBytes, rxPackets, txBytes, txPackets, operations); } private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long rxPackets, long txBytes, long txPackets, int operations) throws Exception { - assertUidTotal(template, uid, SET_ALL, ROAMING_ALL, rxBytes, rxPackets, txBytes, txPackets, - operations); + assertUidTotal(template, uid, SET_ALL, METERED_ALL, ROAMING_ALL, rxBytes, rxPackets, + txBytes, txPackets, operations); } - private void assertUidTotal(NetworkTemplate template, int uid, int set, int roaming, - long rxBytes, long rxPackets, long txBytes, long txPackets, int operations) + private void assertUidTotal(NetworkTemplate template, int uid, int set, int metered, + int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets, int operations) throws Exception { // verify history API final NetworkStatsHistory history = mSession.getHistoryForUid( @@ -945,8 +993,8 @@ public class NetworkStatsServiceTest { // verify summary API final NetworkStats stats = mSession.getSummaryForAllUid( template, Long.MIN_VALUE, Long.MAX_VALUE, false); - assertValues(stats, IFACE_ALL, uid, set, TAG_NONE, roaming, rxBytes, rxPackets, txBytes, - txPackets, operations); + assertValues(stats, IFACE_ALL, uid, set, TAG_NONE, metered, roaming, rxBytes, rxPackets, + txBytes, txPackets, operations); } private void expectSystemReady() throws Exception { @@ -1034,8 +1082,8 @@ public class NetworkStatsServiceTest { } private static void assertValues(NetworkStats stats, String iface, int uid, int set, - int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets, - int operations) { + int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes, + long txPackets, int operations) { final NetworkStats.Entry entry = new NetworkStats.Entry(); List sets = new ArrayList<>(); if (set == SET_DEFAULT || set == SET_ALL) { @@ -1053,11 +1101,21 @@ public class NetworkStatsServiceTest { roamings.add(ROAMING_YES); } + List meterings = new ArrayList<>(); + if (metered == METERED_NO || metered == METERED_ALL) { + meterings.add(METERED_NO); + } + if (metered == METERED_YES || metered == METERED_ALL) { + meterings.add(METERED_YES); + } + for (int s : sets) { for (int r : roamings) { - final int i = stats.findIndex(iface, uid, s, tag, r); - if (i != -1) { - entry.add(stats.getValues(i, null)); + for (int m : meterings) { + final int i = stats.findIndex(iface, uid, s, tag, m, r); + if (i != -1) { + entry.add(stats.getValues(i, null)); + } } } } @@ -1080,11 +1138,18 @@ public class NetworkStatsServiceTest { } private static NetworkState buildWifiState() { + return buildWifiState(false); + } + + private static NetworkState buildWifiState(boolean isMetered) { final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null); info.setDetailedState(DetailedState.CONNECTED, null, null); final LinkProperties prop = new LinkProperties(); prop.setInterfaceName(TEST_IFACE); final NetworkCapabilities capabilities = new NetworkCapabilities(); + if (!isMetered) { + capabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + } return new NetworkState(info, prop, capabilities, null, null, TEST_SSID); } From 094fbe671927b730a30f4914ddc08f997ffc0114 Mon Sep 17 00:00:00 2001 From: Tony Mak Date: Thu, 30 Jun 2016 11:19:20 +0100 Subject: [PATCH 37/45] Show notification for always-on app VPN This is the same notification as the one shown during legacy lockdown mode, sans the 'reset' button. The notification is only shown during times when VPN has not yet established or has failed, for example during boot or after a crash. Bug: 29123115 (cherry picked from commit 1a405fe300950d6ceae2166fd074b596d8110dbe) Change-Id: I929a05c24df01e21415535a333bb14ac4b790a9d --- .../com/android/server/connectivity/Vpn.java | 64 ++++++++++--- .../android/server/connectivity/VpnTest.java | 91 +++++++++++++------ 2 files changed, 117 insertions(+), 38 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 610a2ab5b53bd..a5876ddda745c 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -27,6 +27,8 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.AppGlobals; import android.app.AppOpsManager; +import android.app.Notification; +import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -76,6 +78,7 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; +import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.net.LegacyVpnInfo; @@ -241,12 +244,14 @@ public class Vpn { /** * Update current state, dispaching event to listeners. */ - private void updateState(DetailedState detailedState, String reason) { + @VisibleForTesting + protected void updateState(DetailedState detailedState, String reason) { if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason); mNetworkInfo.setDetailedState(detailedState, reason, null); if (mNetworkAgent != null) { mNetworkAgent.sendNetworkInfo(mNetworkInfo); } + updateAlwaysOnNotification(detailedState); } /** @@ -280,7 +285,10 @@ public class Vpn { } mLockdown = (mAlwaysOn && lockdown); - if (!isCurrentPreparedPackage(packageName)) { + if (isCurrentPreparedPackage(packageName)) { + updateAlwaysOnNotification(mNetworkInfo.getDetailedState()); + } else { + // Prepare this app. The notification will update as a side-effect of updateState(). prepareInternal(packageName); } maybeRegisterPackageChangeReceiverLocked(packageName); @@ -682,22 +690,19 @@ public class Vpn { } } - private void agentDisconnect(NetworkInfo networkInfo, NetworkAgent networkAgent) { - networkInfo.setIsAvailable(false); - networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null); + private void agentDisconnect(NetworkAgent networkAgent) { if (networkAgent != null) { + NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo); + networkInfo.setIsAvailable(false); + networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null); networkAgent.sendNetworkInfo(networkInfo); } } - private void agentDisconnect(NetworkAgent networkAgent) { - NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo); - agentDisconnect(networkInfo, networkAgent); - } - private void agentDisconnect() { if (mNetworkInfo.isConnected()) { - agentDisconnect(mNetworkInfo, mNetworkAgent); + mNetworkInfo.setIsAvailable(false); + updateState(DetailedState.DISCONNECTED, "agentDisconnect"); mNetworkAgent = null; } } @@ -1250,6 +1255,43 @@ public class Vpn { } } + private void updateAlwaysOnNotification(DetailedState networkState) { + final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED); + updateAlwaysOnNotificationInternal(visible); + } + + @VisibleForTesting + protected void updateAlwaysOnNotificationInternal(boolean visible) { + final UserHandle user = UserHandle.of(mUserHandle); + final long token = Binder.clearCallingIdentity(); + try { + final NotificationManager notificationManager = NotificationManager.from(mContext); + if (!visible) { + notificationManager.cancelAsUser(TAG, 0, user); + return; + } + final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS); + final PendingIntent configIntent = PendingIntent.getActivityAsUser( + mContext, /* request */ 0, intent, + PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, + null, user); + final Notification.Builder builder = new Notification.Builder(mContext) + .setDefaults(0) + .setSmallIcon(R.drawable.vpn_connected) + .setContentTitle(mContext.getString(R.string.vpn_lockdown_disconnected)) + .setContentText(mContext.getString(R.string.vpn_lockdown_config)) + .setContentIntent(configIntent) + .setCategory(Notification.CATEGORY_SYSTEM) + .setPriority(Notification.PRIORITY_LOW) + .setVisibility(Notification.VISIBILITY_PUBLIC) + .setOngoing(true) + .setColor(mContext.getColor(R.color.system_notification_accent_color)); + notificationManager.notifyAsUser(TAG, 0, builder.build(), user); + } finally { + Binder.restoreCallingIdentity(token); + } + } + private native int jniCreate(int mtu); private native String jniGetName(int tun); private native int jniSetAddresses(String interfaze, String addresses); diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 5d8b843bbc172..b51b2771db168 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -25,9 +25,11 @@ import static org.mockito.Mockito.*; import android.annotation.UserIdInt; import android.app.AppOpsManager; +import android.app.NotificationManager; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.UserInfo; +import android.net.NetworkInfo.DetailedState; import android.net.UidRange; import android.os.INetworkManagementService; import android.os.Looper; @@ -43,6 +45,8 @@ import java.util.Arrays; import java.util.Map; import java.util.Set; +import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -88,14 +92,18 @@ public class VpnTest extends AndroidTestCase { @Mock private PackageManager mPackageManager; @Mock private INetworkManagementService mNetService; @Mock private AppOpsManager mAppOps; + @Mock private NotificationManager mNotificationManager; @Override public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mContext.getPackageManager()).thenReturn(mPackageManager); setMockedPackages(mPackages); + when(mContext.getPackageName()).thenReturn(Vpn.class.getPackage().getName()); when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager); when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps); + when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE))) + .thenReturn(mNotificationManager); doNothing().when(mNetService).registerObserver(any()); } @@ -103,7 +111,7 @@ public class VpnTest extends AndroidTestCase { public void testRestrictedProfilesAreAddedToVpn() { setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB); - final Vpn vpn = new MockVpn(primaryUser.id); + final Vpn vpn = spyVpn(primaryUser.id); final Set ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null); @@ -117,7 +125,7 @@ public class VpnTest extends AndroidTestCase { public void testManagedProfilesAreNotAddedToVpn() { setMockedUsers(primaryUser, managedProfileA); - final Vpn vpn = new MockVpn(primaryUser.id); + final Vpn vpn = spyVpn(primaryUser.id); final Set ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null); @@ -130,7 +138,7 @@ public class VpnTest extends AndroidTestCase { public void testAddUserToVpnOnlyAddsOneUser() { setMockedUsers(primaryUser, restrictedProfileA, managedProfileA); - final Vpn vpn = new MockVpn(primaryUser.id); + final Vpn vpn = spyVpn(primaryUser.id); final Set ranges = new ArraySet<>(); vpn.addUserToRanges(ranges, primaryUser.id, null, null); @@ -141,7 +149,7 @@ public class VpnTest extends AndroidTestCase { @SmallTest public void testUidWhiteAndBlacklist() throws Exception { - final Vpn vpn = new MockVpn(primaryUser.id); + final Vpn vpn = spyVpn(primaryUser.id); final UidRange user = UidRange.createForUser(primaryUser.id); final String[] packages = {PKGS[0], PKGS[1], PKGS[2]}; @@ -166,15 +174,15 @@ public class VpnTest extends AndroidTestCase { @SmallTest public void testLockdownChangingPackage() throws Exception { - final MockVpn vpn = new MockVpn(primaryUser.id); + final Vpn vpn = spyVpn(primaryUser.id); final UidRange user = UidRange.createForUser(primaryUser.id); // Default state. - vpn.assertUnblocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); + assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); // Set always-on without lockdown. assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false)); - vpn.assertUnblocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); + assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); // Set always-on with lockdown. assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true)); @@ -182,8 +190,8 @@ public class VpnTest extends AndroidTestCase { new UidRange(user.start, user.start + PKG_UIDS[1] - 1), new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) })); - vpn.assertBlocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); - vpn.assertUnblocked(user.start + PKG_UIDS[1]); + assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); + assertUnblocked(vpn, user.start + PKG_UIDS[1]); // Switch to another app. assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true)); @@ -195,13 +203,13 @@ public class VpnTest extends AndroidTestCase { new UidRange(user.start, user.start + PKG_UIDS[3] - 1), new UidRange(user.start + PKG_UIDS[3] + 1, user.stop) })); - vpn.assertBlocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); - vpn.assertUnblocked(user.start + PKG_UIDS[3]); + assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); + assertUnblocked(vpn, user.start + PKG_UIDS[3]); } @SmallTest public void testLockdownAddingAProfile() throws Exception { - final MockVpn vpn = new MockVpn(primaryUser.id); + final Vpn vpn = spyVpn(primaryUser.id); setMockedUsers(primaryUser); // Make a copy of the restricted profile, as we're going to mark it deleted halfway through. @@ -220,7 +228,7 @@ public class VpnTest extends AndroidTestCase { })); // Verify restricted user isn't affected at first. - vpn.assertUnblocked(profile.start + PKG_UIDS[0]); + assertUnblocked(vpn, profile.start + PKG_UIDS[0]); // Add the restricted user. setMockedUsers(primaryUser, tempProfile); @@ -239,24 +247,53 @@ public class VpnTest extends AndroidTestCase { })); } + @SmallTest + public void testNotificationShownForAlwaysOnApp() { + final Vpn vpn = spyVpn(primaryUser.id); + final InOrder order = inOrder(vpn); + setMockedUsers(primaryUser); + + // Don't show a notification for regular disconnected states. + vpn.updateState(DetailedState.DISCONNECTED, TAG); + order.verify(vpn).updateAlwaysOnNotificationInternal(false); + + // Start showing a notification for disconnected once always-on. + vpn.setAlwaysOnPackage(PKGS[0], false); + order.verify(vpn).updateAlwaysOnNotificationInternal(true); + + // Stop showing the notification once connected. + vpn.updateState(DetailedState.CONNECTED, TAG); + order.verify(vpn).updateAlwaysOnNotificationInternal(false); + + // Show the notification if we disconnect again. + vpn.updateState(DetailedState.DISCONNECTED, TAG); + order.verify(vpn).updateAlwaysOnNotificationInternal(true); + + // Notification should be cleared after unsetting always-on package. + vpn.setAlwaysOnPackage(null, false); + order.verify(vpn).updateAlwaysOnNotificationInternal(false); + } + /** - * A subclass of {@link Vpn} with some of the fields pre-mocked. + * Mock some methods of vpn object. */ - private class MockVpn extends Vpn { - public MockVpn(@UserIdInt int userId) { - super(Looper.myLooper(), mContext, mNetService, userId); - } + private Vpn spyVpn(@UserIdInt int userId) { + final Vpn vpn = spy(new Vpn(Looper.myLooper(), mContext, mNetService, userId)); - public void assertBlocked(int... uids) { - for (int uid : uids) { - assertTrue("Uid " + uid + " should be blocked", isBlockingUid(uid)); - } - } + // Block calls to the NotificationManager or PendingIntent#getActivity. + doNothing().when(vpn).updateAlwaysOnNotificationInternal(anyBoolean()); + return vpn; + } - public void assertUnblocked(int... uids) { - for (int uid : uids) { - assertFalse("Uid " + uid + " should not be blocked", isBlockingUid(uid)); - } + private static void assertBlocked(Vpn vpn, int... uids) { + for (int uid : uids) { + assertTrue("Uid " + uid + " should be blocked", vpn.isBlockingUid(uid)); + } + } + + private static void assertUnblocked(Vpn vpn, int... uids) { + for (int uid : uids) { + assertFalse("Uid " + uid + " should not be blocked", vpn.isBlockingUid(uid)); } } From bea525eff8b74540cce95cf9507cff4f08c57824 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 9 Dec 2016 14:19:57 +0900 Subject: [PATCH 38/45] Add missing dependency. Change-Id: I5deb8e03eb368ab7003f9376f7b4459d2ef5e934 --- services/tests/servicestests/Android.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk index d3235d8fb086c..336351ebbef56 100644 --- a/services/tests/servicestests/Android.mk +++ b/services/tests/servicestests/Android.mk @@ -12,6 +12,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_STATIC_JAVA_LIBRARIES := \ + easymocklib \ frameworks-base-testutils \ services.core \ services.devicepolicy \ From 222ebe48ba33165caead08f19831cb593d5d4db7 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Mon, 31 Oct 2016 15:04:37 +0900 Subject: [PATCH 39/45] Netd events: record connect() success/errno Test: $ runtest frameworks-net pass Bug: 32198976 (cherry picked from commit 8b06bcdfd24100302818ae0e11ee751dd813d5cf) Change-Id: Ib3be06d2678c3fcfe4fa9d7b77f50c6e8812db3d --- .../NetdEventListenerService.java | 25 ++++++++++--------- .../NetdEventListenerServiceTest.java | 11 +++++--- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java index 4b175d7a5af80..f8638c544e8ef 100644 --- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java +++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java @@ -24,6 +24,7 @@ import android.net.NetworkRequest; import android.net.metrics.DnsEvent; import android.net.metrics.INetdEventListener; import android.net.metrics.IpConnectivityLog; +import android.os.RemoteException; import android.util.Log; import com.android.internal.annotations.GuardedBy; @@ -44,7 +45,7 @@ public class NetdEventListenerService extends INetdEventListener.Stub { public static final String SERVICE_NAME = "netd_listener"; private static final String TAG = NetdEventListenerService.class.getSimpleName(); - private static final boolean DBG = true; + private static final boolean DBG = false; private static final boolean VDBG = false; // TODO: read this constant from system property @@ -86,7 +87,7 @@ public class NetdEventListenerService extends INetdEventListener.Stub { byte[] returnCodes = Arrays.copyOf(mReturnCodes, mEventCount); int[] latenciesMs = Arrays.copyOf(mLatenciesMs, mEventCount); mMetricsLog.log(new DnsEvent(mNetId, eventTypes, returnCodes, latenciesMs)); - maybeLog(String.format("Logging %d results for netId %d", mEventCount, mNetId)); + maybeLog("Logging %d results for netId %d", mEventCount, mNetId); mEventCount = 0; } @@ -136,9 +137,9 @@ public class NetdEventListenerService extends INetdEventListener.Stub { // Called concurrently by multiple binder threads. // This method must not block or perform long-running operations. public synchronized void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, - String hostname, String[] ipAddresses, int ipAddressesCount, int uid) { - maybeVerboseLog(String.format("onDnsEvent(%d, %d, %d, %d)", - netId, eventType, returnCode, latencyMs)); + String hostname, String[] ipAddresses, int ipAddressesCount, int uid) + throws RemoteException { + maybeVerboseLog("onDnsEvent(%d, %d, %d, %dms)", netId, eventType, returnCode, latencyMs); DnsEventBatch batch = mEventBatches.get(netId); if (batch == null) { @@ -151,9 +152,9 @@ public class NetdEventListenerService extends INetdEventListener.Stub { @Override // Called concurrently by multiple binder threads. // This method must not block or perform long-running operations. - public synchronized void onConnectEvent(int netId, int latencyMs, String ipAddr, int port, - int uid) { - maybeVerboseLog(String.format("onConnectEvent(%d, %d)", netId, latencyMs)); + public synchronized void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, + int uid) throws RemoteException { + maybeVerboseLog("onConnectEvent(%d, %d, %dms)", netId, error, latencyMs); } public synchronized void dump(PrintWriter writer) { @@ -166,11 +167,11 @@ public class NetdEventListenerService extends INetdEventListener.Stub { pw.decreaseIndent(); } - private static void maybeLog(String s) { - if (DBG) Log.d(TAG, s); + private static void maybeLog(String s, Object... args) { + if (DBG) Log.d(TAG, String.format(s, args)); } - private static void maybeVerboseLog(String s) { - if (VDBG) Log.d(TAG, s); + private static void maybeVerboseLog(String s, Object... args) { + if (VDBG) Log.d(TAG, String.format(s, args)); } } diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java index 9e2fd6231ba9d..af4a374bffddf 100644 --- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java +++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java @@ -22,6 +22,7 @@ import android.net.Network; import android.net.metrics.DnsEvent; import android.net.metrics.INetdEventListener; import android.net.metrics.IpConnectivityLog; +import android.os.RemoteException; import junit.framework.TestCase; import org.junit.Before; @@ -157,9 +158,13 @@ public class NetdEventListenerServiceTest extends TestCase { } void log(int netId, int[] latencies) { - for (int l : latencies) { - mNetdEventListenerService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l, null, null, 0, - 0); + try { + for (int l : latencies) { + mNetdEventListenerService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l, null, null, + 0, 0); + } + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); } } From 352147a308e4cdc4ccf82af83d37d1505fe1b05d Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Fri, 4 Nov 2016 16:06:34 +0900 Subject: [PATCH 40/45] frameworks-test: adding missing @SmallTest This activates all frameworks-test tests in runs of the continuous platform tests. Test: $ runtest frameworks-net passes (expect Tether Bug: 32561414 (cherry picked from commit fa8a6f6220d1a0027ba7969c2d3f72690ddc6495) Change-Id: I7b0706a7e3368f971d508388e8ad4afc5de9d646 --- .../net/ConnectivityMetricsLoggerTest.java | 6 +++ tests/net/java/android/net/apf/ApfTest.java | 15 ++++---- .../java/android/net/dhcp/DhcpPacketTest.java | 2 + .../net/netlink/NetlinkErrorMessageTest.java | 2 + .../net/netlink/NetlinkSocketTest.java | 3 ++ .../netlink/RtNetlinkNeighborMessageTest.java | 7 +++- .../server/ConnectivityServiceTest.java | 38 ++++++++++--------- .../connectivity/LingerMonitorTest.java | 16 ++++++++ .../MetricsLoggerServiceTest.java | 7 ++++ .../NetdEventListenerServiceTest.java | 6 +++ 10 files changed, 75 insertions(+), 27 deletions(-) diff --git a/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java b/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java index 6d42cce2e5027..f89603052213b 100644 --- a/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java +++ b/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java @@ -18,6 +18,7 @@ package android.net; import android.os.Bundle; import android.os.Parcel; +import android.test.suitebuilder.annotation.SmallTest; import java.util.List; import junit.framework.TestCase; import org.mockito.ArgumentCaptor; @@ -49,6 +50,7 @@ public class ConnectivityMetricsLoggerTest extends TestCase { mLog = new ConnectivityMetricsLogger(mService); } + @SmallTest public void testLogEvents() throws Exception { mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV); mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV); @@ -60,6 +62,7 @@ public class ConnectivityMetricsLoggerTest extends TestCase { assertEventsEqual(expectedEvent(3), gotEvents.get(2)); } + @SmallTest public void testLogEventTriggerThrottling() throws Exception { when(mService.logEvent(any())).thenReturn(1234L); @@ -70,6 +73,7 @@ public class ConnectivityMetricsLoggerTest extends TestCase { assertEventsEqual(expectedEvent(1), gotEvents.get(0)); } + @SmallTest public void testLogEventFails() throws Exception { when(mService.logEvent(any())).thenReturn(-1L); // Error. @@ -80,6 +84,7 @@ public class ConnectivityMetricsLoggerTest extends TestCase { assertEventsEqual(expectedEvent(1), gotEvents.get(0)); } + @SmallTest public void testLogEventWhenThrottling() throws Exception { when(mService.logEvent(any())).thenReturn(Long.MAX_VALUE); // Throttled @@ -92,6 +97,7 @@ public class ConnectivityMetricsLoggerTest extends TestCase { assertEventsEqual(expectedEvent(1), gotEvents.get(0)); } + @SmallTest public void testLogEventRecoverFromThrottling() throws Exception { final long throttleTimeout = System.currentTimeMillis() + 10; when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L); diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java index f41ea922305b4..ff6175427ce71 100644 --- a/tests/net/java/android/net/apf/ApfTest.java +++ b/tests/net/java/android/net/apf/ApfTest.java @@ -33,7 +33,6 @@ import android.system.ErrnoException; import android.system.Os; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; -import android.test.suitebuilder.annotation.MediumTest; import static android.system.OsConstants.*; import com.android.frameworks.tests.net.R; @@ -155,7 +154,7 @@ public class ApfTest extends AndroidTestCase { * generating bytecode for that program and running it through the * interpreter to verify it functions correctly. */ - @MediumTest + @SmallTest 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 @@ -563,7 +562,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. */ - @MediumTest + @SmallTest 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", @@ -725,7 +724,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}; - @MediumTest + @SmallTest public void testApfFilterIPv4() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19); @@ -780,7 +779,7 @@ public class ApfTest extends AndroidTestCase { apfFilter.shutdown(); } - @MediumTest + @SmallTest public void testApfFilterIPv6() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog); @@ -812,7 +811,7 @@ public class ApfTest extends AndroidTestCase { apfFilter.shutdown(); } - @MediumTest + @SmallTest public void testApfFilterMulticast() throws Exception { final byte[] unicastIpv4Addr = {(byte)192,0,2,63}; final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255}; @@ -922,7 +921,7 @@ public class ApfTest extends AndroidTestCase { assertDrop(program, garpReply()); } - @MediumTest + @SmallTest public void testApfFilterArp() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog); @@ -1041,7 +1040,7 @@ public class ApfTest extends AndroidTestCase { ipManagerCallback.assertNoProgramUpdate(); } - @MediumTest + @SmallTest public void testApfFilterRa() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog); diff --git a/tests/net/java/android/net/dhcp/DhcpPacketTest.java b/tests/net/java/android/net/dhcp/DhcpPacketTest.java index bc8baa12a45b4..d79c312a9edd5 100644 --- a/tests/net/java/android/net/dhcp/DhcpPacketTest.java +++ b/tests/net/java/android/net/dhcp/DhcpPacketTest.java @@ -473,6 +473,7 @@ public class DhcpPacketTest extends TestCase { assertEquals(Integer.toHexString(expected), Integer.toHexString(got)); } + @SmallTest public void testTruncatedOfferPackets() throws Exception { final byte[] packet = HexDump.hexStringToByteArray( // IP header. @@ -506,6 +507,7 @@ public class DhcpPacketTest extends TestCase { } } + @SmallTest public void testRandomPackets() throws Exception { final int maxRandomPacketSize = 512; final Random r = new Random(); diff --git a/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java b/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java index e677475f5907b..5deba27d80dcd 100644 --- a/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java +++ b/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java @@ -24,6 +24,7 @@ import android.net.netlink.NetlinkConstants; import android.net.netlink.NetlinkErrorMessage; import android.net.netlink.NetlinkMessage; import android.net.netlink.StructNlMsgErr; +import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -53,6 +54,7 @@ public class NetlinkErrorMessageTest extends TestCase { public static final byte[] NLM_ERROR_OK = HexEncoding.decode(NLM_ERROR_OK_HEX.toCharArray(), false); + @SmallTest public void testParseNlmErrorOk() { final ByteBuffer byteBuffer = ByteBuffer.wrap(NLM_ERROR_OK); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. diff --git a/tests/net/java/android/net/netlink/NetlinkSocketTest.java b/tests/net/java/android/net/netlink/NetlinkSocketTest.java index c599fe3e5b762..78b3b704e7868 100644 --- a/tests/net/java/android/net/netlink/NetlinkSocketTest.java +++ b/tests/net/java/android/net/netlink/NetlinkSocketTest.java @@ -20,6 +20,7 @@ import android.net.netlink.NetlinkSocket; import android.net.netlink.RtNetlinkNeighborMessage; import android.net.netlink.StructNdMsg; import android.net.netlink.StructNlMsgHdr; +import android.test.suitebuilder.annotation.SmallTest; import android.system.ErrnoException; import android.system.NetlinkSocketAddress; import android.system.OsConstants; @@ -33,6 +34,7 @@ import junit.framework.TestCase; public class NetlinkSocketTest extends TestCase { private final String TAG = "NetlinkSocketTest"; + @SmallTest public void testBasicWorkingGetNeighborsQuery() throws Exception { NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE); assertNotNull(s); @@ -91,6 +93,7 @@ public class NetlinkSocketTest extends TestCase { s.close(); } + @SmallTest public void testRepeatedCloseCallsAreQuiet() throws Exception { // Create a working NetlinkSocket. NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE); diff --git a/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java b/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java index 19ee00036b612..029758eb6e5b6 100644 --- a/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java +++ b/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java @@ -21,12 +21,13 @@ import android.net.netlink.NetlinkMessage; import android.net.netlink.RtNetlinkNeighborMessage; import android.net.netlink.StructNdMsg; import android.net.netlink.StructNlMsgHdr; +import android.test.suitebuilder.annotation.SmallTest; import android.system.OsConstants; import android.util.Log; import libcore.util.HexEncoding; -import java.net.InetAddress; import java.net.Inet4Address; +import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -135,6 +136,7 @@ public class RtNetlinkNeighborMessageTest extends TestCase { public static final byte[] RTM_GETNEIGH_RESPONSE = HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false); + @SmallTest public void testParseRtmDelNeigh() { final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. @@ -161,6 +163,7 @@ public class RtNetlinkNeighborMessageTest extends TestCase { assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination); } + @SmallTest public void testParseRtmNewNeigh() { final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. @@ -187,6 +190,7 @@ public class RtNetlinkNeighborMessageTest extends TestCase { assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination); } + @SmallTest public void testParseRtmGetNeighResponse() { final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. @@ -211,6 +215,7 @@ public class RtNetlinkNeighborMessageTest extends TestCase { assertEquals(14, messageCount); } + @SmallTest public void testCreateRtmNewNeighMessage() { final int seqNo = 2635; final int ifIndex = 14; diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 4b3f99277e80e..46b64031ee8ac 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -70,7 +70,6 @@ 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; import android.util.Log; import android.util.LogPrinter; @@ -196,6 +195,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { } // Tests that IdleableHandlerThread works as expected. + @SmallTest public void testIdleableHandlerThread() { final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng. @@ -220,6 +220,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { } } + @SmallTest @FlakyTest(tolerance = 3) public void testNotWaitingForIdleCausesRaceConditions() { // Bring up a network that we can use to send messages to ConnectivityService. @@ -840,7 +841,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { return cv; } - @LargeTest + @SmallTest public void testLingering() throws Exception { verifyNoNetwork(); mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); @@ -880,7 +881,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { verifyNoNetwork(); } - @LargeTest + @SmallTest public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception { // Test bringing up unvalidated WiFi mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); @@ -915,7 +916,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { verifyNoNetwork(); } - @LargeTest + @SmallTest public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception { // Test bringing up unvalidated cellular. mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); @@ -941,7 +942,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { verifyNoNetwork(); } - @LargeTest + @SmallTest public void testUnlingeringDoesNotValidate() throws Exception { // Test bringing up unvalidated WiFi. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); @@ -969,7 +970,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { NET_CAPABILITY_VALIDATED)); } - @LargeTest + @SmallTest public void testCellularOutscoresWeakWifi() throws Exception { // Test bringing up validated cellular. mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); @@ -995,7 +996,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { verifyActiveNetwork(TRANSPORT_WIFI); } - @LargeTest + @SmallTest public void testReapingNetwork() throws Exception { // Test bringing up WiFi without NET_CAPABILITY_INTERNET. // Expect it to be torn down immediately because it satisfies no requests. @@ -1028,7 +1029,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { waitFor(cv); } - @LargeTest + @SmallTest public void testCellularFallback() throws Exception { // Test bringing up validated cellular. mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); @@ -1066,7 +1067,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { verifyActiveNetwork(TRANSPORT_WIFI); } - @LargeTest + @SmallTest public void testWiFiFallback() throws Exception { // Test bringing up unvalidated WiFi. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); @@ -1208,7 +1209,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { } } - @LargeTest + @SmallTest public void testStateChangeNetworkCallbacks() throws Exception { final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback(); final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback(); @@ -1591,7 +1592,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { handlerThread.quit(); } - @LargeTest + @SmallTest public void testNetworkFactoryRequests() throws Exception { tryNetworkFactoryRequests(NET_CAPABILITY_MMS); tryNetworkFactoryRequests(NET_CAPABILITY_SUPL); @@ -1611,7 +1612,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { // Skipping VALIDATED and CAPTIVE_PORTAL as they're disallowed. } - @LargeTest + @SmallTest public void testNoMutableNetworkRequests() throws Exception { PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("a"), 0); NetworkRequest.Builder builder = new NetworkRequest.Builder(); @@ -1636,7 +1637,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { } catch (IllegalArgumentException expected) {} } - @LargeTest + @SmallTest public void testMMSonWiFi() throws Exception { // Test bringing up cellular without MMS NetworkRequest gets reaped mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); @@ -1671,7 +1672,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { verifyActiveNetwork(TRANSPORT_WIFI); } - @LargeTest + @SmallTest public void testMMSonCell() throws Exception { // Test bringing up cellular without MMS mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); @@ -1697,7 +1698,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { verifyActiveNetwork(TRANSPORT_CELLULAR); } - @LargeTest + @SmallTest public void testCaptivePortal() { final TestNetworkCallback captivePortalCallback = new TestNetworkCallback(); final NetworkRequest captivePortalRequest = new NetworkRequest.Builder() @@ -1746,7 +1747,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); } - @LargeTest + @SmallTest public void testAvoidOrIgnoreCaptivePortals() { final TestNetworkCallback captivePortalCallback = new TestNetworkCallback(); final NetworkRequest captivePortalRequest = new NetworkRequest.Builder() @@ -1817,7 +1818,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { execptionCalled); } - @LargeTest + @SmallTest public void testRegisterDefaultNetworkCallback() throws Exception { final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultNetworkCallback); @@ -1878,7 +1879,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { } } - @LargeTest + @SmallTest public void testRequestCallbackUpdates() throws Exception { // File a network request for mobile. final TestNetworkCallback cellNetworkCallback = new TestRequestUpdateCallback(); @@ -2519,6 +2520,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { return mWiFiNetworkAgent.getNetwork(); } + @SmallTest public void testPacketKeepalives() throws Exception { InetAddress myIPv4 = InetAddress.getByName("192.0.2.129"); InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35"); diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index bce5787ed9a5f..77956be66c9e8 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -24,6 +24,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkMisc; +import android.test.suitebuilder.annotation.SmallTest; import android.text.format.DateUtils; import com.android.internal.R; import com.android.server.ConnectivityService; @@ -70,6 +71,7 @@ public class LingerMonitorTest extends TestCase { mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT); } + @SmallTest public void testTransitions() { setNotificationSwitch(transition(WIFI, CELLULAR)); NetworkAgentInfo nai1 = wifiNai(100); @@ -79,6 +81,7 @@ public class LingerMonitorTest extends TestCase { assertFalse(mMonitor.isNotificationEnabled(nai2, nai1)); } + @SmallTest public void testNotificationOnLinger() { setNotificationSwitch(transition(WIFI, CELLULAR)); setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); @@ -89,6 +92,7 @@ public class LingerMonitorTest extends TestCase { verifyNotification(from, to); } + @SmallTest public void testToastOnLinger() { setNotificationSwitch(transition(WIFI, CELLULAR)); setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); @@ -99,6 +103,7 @@ public class LingerMonitorTest extends TestCase { verifyToast(from, to); } + @SmallTest public void testNotificationClearedAfterDisconnect() { setNotificationSwitch(transition(WIFI, CELLULAR)); setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); @@ -112,6 +117,7 @@ public class LingerMonitorTest extends TestCase { verify(mNotifier, times(1)).clearNotification(100); } + @SmallTest public void testNotificationClearedAfterSwitchingBack() { setNotificationSwitch(transition(WIFI, CELLULAR)); setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); @@ -125,6 +131,7 @@ public class LingerMonitorTest extends TestCase { verify(mNotifier, times(1)).clearNotification(100); } + @SmallTest public void testUniqueToast() { setNotificationSwitch(transition(WIFI, CELLULAR)); setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); @@ -142,6 +149,7 @@ public class LingerMonitorTest extends TestCase { verifyNoNotifications(); } + @SmallTest public void testMultipleNotifications() { setNotificationSwitch(transition(WIFI, CELLULAR)); setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); @@ -160,6 +168,7 @@ public class LingerMonitorTest extends TestCase { verifyNotification(wifi2, cell); } + @SmallTest public void testRateLimiting() throws InterruptedException { mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, LOW_RATE_LIMIT); @@ -185,6 +194,7 @@ public class LingerMonitorTest extends TestCase { verifyNoNotifications(); } + @SmallTest public void testDailyLimiting() throws InterruptedException { mMonitor = new TestableLingerMonitor(mCtx, mNotifier, LOW_DAILY_LIMIT, HIGH_RATE_LIMIT); @@ -211,6 +221,7 @@ public class LingerMonitorTest extends TestCase { verifyNoNotifications(); } + @SmallTest public void testUniqueNotification() { setNotificationSwitch(transition(WIFI, CELLULAR)); setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); @@ -227,6 +238,7 @@ public class LingerMonitorTest extends TestCase { verifyNotification(from, to); } + @SmallTest public void testIgnoreNeverValidatedNetworks() { setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); setNotificationSwitch(transition(WIFI, CELLULAR)); @@ -238,6 +250,7 @@ public class LingerMonitorTest extends TestCase { verifyNoNotifications(); } + @SmallTest public void testIgnoreCurrentlyValidatedNetworks() { setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); setNotificationSwitch(transition(WIFI, CELLULAR)); @@ -249,6 +262,7 @@ public class LingerMonitorTest extends TestCase { verifyNoNotifications(); } + @SmallTest public void testNoNotificationType() { setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); setNotificationSwitch(); @@ -259,6 +273,7 @@ public class LingerMonitorTest extends TestCase { verifyNoNotifications(); } + @SmallTest public void testNoTransitionToNotify() { setNotificationType(LingerMonitor.NOTIFY_TYPE_NONE); setNotificationSwitch(transition(WIFI, CELLULAR)); @@ -269,6 +284,7 @@ public class LingerMonitorTest extends TestCase { verifyNoNotifications(); } + @SmallTest public void testDifferentTransitionToNotify() { setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); setNotificationSwitch(transition(CELLULAR, WIFI)); diff --git a/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java b/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java index 5f84ea1bfd96b..5981f48e7ccd1 100644 --- a/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java +++ b/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java @@ -20,6 +20,7 @@ import android.content.Context; import android.net.ConnectivityMetricsEvent; import android.os.Bundle; import android.os.RemoteException; +import android.test.suitebuilder.annotation.SmallTest; import static android.net.ConnectivityMetricsEvent.Reference; import junit.framework.TestCase; @@ -67,12 +68,14 @@ public class MetricsLoggerServiceTest extends TestCase { mService.onStart(); } + @SmallTest public void testGetNoEvents() throws Exception { Reference r = new Reference(0); assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r)); assertEquals(0, r.getValue()); } + @SmallTest public void testLogAndGetEvents() throws Exception { mService.mBinder.logEvents(EVENTS); @@ -85,6 +88,7 @@ public class MetricsLoggerServiceTest extends TestCase { assertEquals(N_EVENTS, r.getValue()); } + @SmallTest public void testLogOneByOne() throws Exception { for (ConnectivityMetricsEvent ev : EVENTS) { mService.mBinder.logEvent(ev); @@ -99,6 +103,7 @@ public class MetricsLoggerServiceTest extends TestCase { assertEquals(N_EVENTS, r.getValue()); } + @SmallTest public void testInterleavedLogAndGet() throws Exception { mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 0, 3)); @@ -117,6 +122,7 @@ public class MetricsLoggerServiceTest extends TestCase { assertEquals(N_EVENTS, r.getValue()); } + @SmallTest public void testMultipleGetAll() throws Exception { mService.mBinder.logEvents(Arrays.copyOf(EVENTS, 3)); @@ -131,6 +137,7 @@ public class MetricsLoggerServiceTest extends TestCase { assertEquals(N_EVENTS, r2.getValue()); } + @SmallTest public void testLogAndDumpConcurrently() throws Exception { for (int i = 0; i < 50; i++) { mContext = null; diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java index af4a374bffddf..2bb62bbdcf595 100644 --- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java +++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java @@ -23,6 +23,7 @@ import android.net.metrics.DnsEvent; import android.net.metrics.INetdEventListener; import android.net.metrics.IpConnectivityLog; import android.os.RemoteException; +import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; import org.junit.Before; @@ -83,6 +84,7 @@ public class NetdEventListenerServiceTest extends TestCase { verify(mCm, times(1)).registerNetworkCallback(any(), mCallbackCaptor.capture()); } + @SmallTest public void testOneBatch() throws Exception { log(105, LATENCIES); log(106, Arrays.copyOf(LATENCIES, BATCH_SIZE - 1)); // one lookup short of a batch event @@ -97,6 +99,7 @@ public class NetdEventListenerServiceTest extends TestCase { new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES)); } + @SmallTest public void testSeveralBatches() throws Exception { log(105, LATENCIES); log(106, LATENCIES); @@ -110,6 +113,7 @@ public class NetdEventListenerServiceTest extends TestCase { new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES)); } + @SmallTest public void testBatchAndNetworkLost() throws Exception { byte[] eventTypes = Arrays.copyOf(EVENT_TYPES, 20); byte[] returnCodes = Arrays.copyOf(RETURN_CODES, 20); @@ -126,6 +130,7 @@ public class NetdEventListenerServiceTest extends TestCase { new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES)); } + @SmallTest public void testConcurrentBatchesAndDumps() throws Exception { final long stop = System.currentTimeMillis() + 100; final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null")); @@ -147,6 +152,7 @@ public class NetdEventListenerServiceTest extends TestCase { new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES)); } + @SmallTest public void testConcurrentBatchesAndNetworkLoss() throws Exception { logAsync(105, LATENCIES); Thread.sleep(10L); From 612f058d48bb57a2f375b2bf34a1e5049571f1d2 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Wed, 7 Dec 2016 14:39:05 +0900 Subject: [PATCH 41/45] Removing bogus file added by mistake This patch deletes a bogus file added by mistake in the change with commit hash 147aa6d53bc1e9f8a3632553abcf936023806e1d. Test: no code change. Bug: 32198726 Change-Id: Iffc6b3a5ebd854dc81d537576a4405955abacba7 --- ] | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 ] diff --git a/] b/] deleted file mode 100644 index 5619151c7ee3e..0000000000000 --- a/] +++ /dev/null @@ -1,12 +0,0 @@ -NetworkNotificationManager: logging improvements - -TODO: squash me -# Please enter the commit message for your changes. Lines starting -# with '#' will be ignored, and an empty message aborts the commit. -# On branch notification_tagging -# Your branch is ahead of 'goog/master' by 2 commits. -# (use "git push" to publish your local commits) -# -# Changes to be committed: -# modified: services/core/java/com/android/server/connectivity/NetworkNotificationManager.java -# From 3daf708e3cdc07bb2c98346c90589212ddff3479 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Thu, 10 Nov 2016 22:45:56 +0900 Subject: [PATCH 42/45] Fix flaky IpPrefixTest. Test: IpPrefixTest passes Bug: 32561414 (cherry picked from commit 32c687040301cb3601fd110281a742159a963aa9) Change-Id: I42928da87f7f336900b3a95ebbf28563864da8d4 --- .../src/android/net/IpPrefixTest.java | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/core/tests/coretests/src/android/net/IpPrefixTest.java b/core/tests/coretests/src/android/net/IpPrefixTest.java index fcc638960bb8a..4f2387dcf5c13 100644 --- a/core/tests/coretests/src/android/net/IpPrefixTest.java +++ b/core/tests/coretests/src/android/net/IpPrefixTest.java @@ -18,14 +18,14 @@ package android.net; import android.net.IpPrefix; import android.os.Parcel; -import static android.test.MoreAsserts.assertNotEqual; import android.test.suitebuilder.annotation.SmallTest; - -import static org.junit.Assert.assertArrayEquals; import java.net.InetAddress; import java.util.Random; import junit.framework.TestCase; +import static android.test.MoreAsserts.assertNotEqual; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; public class IpPrefixTest extends TestCase { @@ -242,25 +242,42 @@ public class IpPrefixTest extends TestCase { @SmallTest public void testHashCode() { - IpPrefix p; - int oldCode = -1; + IpPrefix p = new IpPrefix(new byte[4], 0); Random random = new Random(); for (int i = 0; i < 100; i++) { + final IpPrefix oldP = p; if (random.nextBoolean()) { // IPv4. byte[] b = new byte[4]; random.nextBytes(b); p = new IpPrefix(b, random.nextInt(33)); - assertNotEqual(oldCode, p.hashCode()); - oldCode = p.hashCode(); } else { // IPv6. byte[] b = new byte[16]; random.nextBytes(b); p = new IpPrefix(b, random.nextInt(129)); - assertNotEqual(oldCode, p.hashCode()); - oldCode = p.hashCode(); } + if (p.equals(oldP)) { + assertEquals(p.hashCode(), oldP.hashCode()); + } + if (p.hashCode() != oldP.hashCode()) { + assertNotEqual(p, oldP); + } + } + } + + @SmallTest + public void testHashCodeIsNotConstant() { + IpPrefix[] prefixes = { + new IpPrefix("2001:db8:f00::ace:d00d/127"), + new IpPrefix("192.0.2.0/23"), + new IpPrefix("::/0"), + new IpPrefix("0.0.0.0/0"), + }; + for (int i = 0; i < prefixes.length; i++) { + for (int j = i + 1; j < prefixes.length; j++) { + assertNotEqual(prefixes[i].hashCode(), prefixes[j].hashCode()); + } } } From 6814bd1afe39d13aad948b283fac64ca88bbc9d2 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Mon, 21 Nov 2016 13:50:05 +0900 Subject: [PATCH 43/45] Captive portal systel log improvements This patch improves system logging around captive portal detection to make inspection of bug reports sligthly easier: - NetworkMonitor now logs by default CMD_CAPTIVE_PORTAL_RECHECK and CMD_CAPTIVE_PORTAL_APP_FINISHED. Other system logs are kept off with a new VDBG boolean contant, - NetworkNotificationManager now prints the notification id at notification time. This allows to easily correlate show and clear. - errors in NetworkNotificationManager are logged as Throwable instead of through their implicit toString() method. Test: $ runtest frameworks-net Bug: 32198726 (cherry picked from commit 8b025bf108c729156b40159038befa0e6c5bebce) Change-Id: I1eaab5ea702063dde3e23324d3a1b3dc172c5ac5 --- .../android/server/connectivity/NetworkMonitor.java | 11 ++++++----- .../connectivity/NetworkNotificationManager.java | 6 +++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index ea2cf5fb4a7ef..5e98859141697 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -80,7 +80,8 @@ import java.util.concurrent.TimeUnit; */ public class NetworkMonitor extends StateMachine { private static final String TAG = NetworkMonitor.class.getSimpleName(); - private static final boolean DBG = false; + private static final boolean DBG = true; + private static final boolean VDBG = false; // Default configuration values for captive portal detection probes. // TODO: append a random length parameter to the default HTTPS url. @@ -954,7 +955,7 @@ public class NetworkMonitor extends StateMachine { latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID()); latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID()); } else { - if (DBG) logw("network info is TYPE_WIFI but no ConnectionInfo found"); + if (VDBG) logw("network info is TYPE_WIFI but no ConnectionInfo found"); return; } break; @@ -967,8 +968,8 @@ public class NetworkMonitor extends StateMachine { if (cellInfo.isRegistered()) { numRegisteredCellInfo++; if (numRegisteredCellInfo > 1) { - log("more than one registered CellInfo. Can't " + - "tell which is active. Bailing."); + if (VDBG) logw("more than one registered CellInfo." + + " Can't tell which is active. Bailing."); return; } if (cellInfo instanceof CellInfoCdma) { @@ -984,7 +985,7 @@ public class NetworkMonitor extends StateMachine { CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity(); latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); } else { - if (DBG) logw("Registered cellinfo is unrecognized"); + if (VDBG) logw("Registered cellinfo is unrecognized"); return; } } diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java index f7b01be48d887..c6bf4c5fcd6a4 100644 --- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java @@ -114,7 +114,7 @@ public class NetworkNotificationManager { } if (DBG) { - Slog.d(TAG, "showNotification " + notifyType + Slog.d(TAG, "showNotification id=" + id + " " + notifyType + " transportType=" + getTransportName(transportType) + " extraInfo=" + extraInfo + " highPriority=" + highPriority); } @@ -187,7 +187,7 @@ public class NetworkNotificationManager { try { mNotificationManager.notifyAsUser(NOTIFICATION_ID, id, notification, UserHandle.ALL); } catch (NullPointerException npe) { - Slog.d(TAG, "setNotificationVisible: visible notificationManager npe=" + npe); + Slog.d(TAG, "setNotificationVisible: visible notificationManager error", npe); } } @@ -198,7 +198,7 @@ public class NetworkNotificationManager { try { mNotificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL); } catch (NullPointerException npe) { - Slog.d(TAG, "setNotificationVisible: cancel notificationManager npe=" + npe); + Slog.d(TAG, "setNotificationVisible: cancel notificationManager error", npe); } } From ef78d27703a3ad6c8b13061e3dbeeeeaf0ade6e0 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Tue, 6 Dec 2016 15:36:30 +0900 Subject: [PATCH 44/45] Logging improvements in CaptivePortalLoginActivity Logging improvements to help debugging captive portal issues. Test: manually tested Bug: 33126342 (cherry picked from commit 87de0c206709d3a170649b535a973de8f9c0fb0c) Change-Id: I52425b849412f6bd5c5ca1f0be7a49cc772497eb --- .../CaptivePortalLoginActivity.java | 78 +++++++++++++------ 1 file changed, 55 insertions(+), 23 deletions(-) diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java index bb8eb2cd07977..03f0b4d5d5da6 100644 --- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java +++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java @@ -55,12 +55,14 @@ import java.lang.reflect.Method; import java.util.Random; public class CaptivePortalLoginActivity extends Activity { - private static final String TAG = "CaptivePortalLogin"; + private static final String TAG = CaptivePortalLoginActivity.class.getSimpleName(); + private static final boolean DBG = true; + private static final int SOCKET_TIMEOUT_MS = 10000; private enum Result { DISMISSED, UNWANTED, WANTED_AS_IS }; - private URL mURL; + private URL mUrl; private Network mNetwork; private CaptivePortal mCaptivePortal; private NetworkCallback mNetworkCallback; @@ -72,17 +74,18 @@ public class CaptivePortalLoginActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCm = ConnectivityManager.from(this); - String url = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL); - if (url == null) url = mCm.getCaptivePortalServerUrl(); - try { - mURL = new URL(url); - } catch (MalformedURLException e) { - // System misconfigured, bail out in a way that at least provides network access. - Log.e(TAG, "Invalid captive portal URL, url=" + url); - done(Result.WANTED_AS_IS); - } mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK); mCaptivePortal = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL); + mUrl = getUrl(); + if (mUrl == null) { + // getUrl() failed to parse the url provided in the intent: bail out in a way that + // at least provides network access. + done(Result.WANTED_AS_IS); + return; + } + if (DBG) { + Log.d(TAG, String.format("onCreate for %s", mUrl.toString())); + } // Also initializes proxy system properties. mCm.bindProcessToNetwork(mNetwork); @@ -149,6 +152,9 @@ public class CaptivePortalLoginActivity extends Activity { } private void done(Result result) { + if (DBG) { + Log.d(TAG, String.format("Result %s for %s", result.name(), mUrl.toString())); + } if (mNetworkCallback != null) { mCm.unregisterNetworkCallback(mNetworkCallback); mNetworkCallback = null; @@ -185,22 +191,31 @@ public class CaptivePortalLoginActivity extends Activity { @Override public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - if (id == R.id.action_use_network) { - done(Result.WANTED_AS_IS); - return true; + final Result result; + final String action; + final int id = item.getItemId(); + switch (id) { + case R.id.action_use_network: + result = Result.WANTED_AS_IS; + action = "USE_NETWORK"; + break; + case R.id.action_do_not_use_network: + result = Result.UNWANTED; + action = "DO_NOT_USE_NETWORK"; + break; + default: + return super.onOptionsItemSelected(item); } - if (id == R.id.action_do_not_use_network) { - done(Result.UNWANTED); - return true; + if (DBG) { + Log.d(TAG, String.format("onOptionsItemSelect %s for %s", action, mUrl.toString())); } - return super.onOptionsItemSelected(item); + done(result); + return true; } @Override public void onDestroy() { super.onDestroy(); - if (mNetworkCallback != null) { mCm.unregisterNetworkCallback(mNetworkCallback); mNetworkCallback = null; @@ -215,10 +230,27 @@ public class CaptivePortalLoginActivity extends Activity { } catch (InterruptedException e) { } } - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(mURL.toString()))); + final String url = mUrl.toString(); + if (DBG) { + Log.d(TAG, "starting activity with intent ACTION_VIEW for " + url); + } + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); } } + private URL getUrl() { + String url = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL); + if (url == null) { + url = mCm.getCaptivePortalServerUrl(); + } + try { + return new URL(url); + } catch (MalformedURLException e) { + Log.e(TAG, "Invalid captive portal URL " + url); + } + return null; + } + private void testForCaptivePortal() { new Thread(new Runnable() { public void run() { @@ -230,7 +262,7 @@ public class CaptivePortalLoginActivity extends Activity { HttpURLConnection urlConnection = null; int httpResponseCode = 500; try { - urlConnection = (HttpURLConnection) mURL.openConnection(); + urlConnection = (HttpURLConnection) mUrl.openConnection(); urlConnection.setInstanceFollowRedirects(false); urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); @@ -292,7 +324,7 @@ public class CaptivePortalLoginActivity extends Activity { // settings. Now prompt the WebView read the Network-specific proxy settings. setWebViewProxy(); // Load the real page. - view.loadUrl(mURL.toString()); + view.loadUrl(mUrl.toString()); return; } else if (mPagesLoaded == 2) { // Prevent going back to empty first page. From 88932754ffdcbffb3cb43e03991e5eb598c10458 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Wed, 14 Dec 2016 08:23:40 +0900 Subject: [PATCH 45/45] Captive portals: login activity probes like NetworkMonitor This patch changes CaptivePortalLoginActivity captive portal test to be consistent with NetworkMonitor by: - using Network.java to open the http connection. - adding a UserAgent property to the request header. Test: manually tested. Bug: 32369183 (cherry picked from commit cdf3ba48ccef0f9c6ca8724c1c106df0dd725ad0) Change-Id: I559eb0497475daad758ba3b3395225dcd0a27a57 --- core/java/android/net/ConnectivityManager.java | 7 +++++++ .../captiveportallogin/CaptivePortalLoginActivity.java | 9 ++++++++- .../com/android/server/connectivity/NetworkMonitor.java | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 51431ebfaf146..042481f1727ee 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -222,6 +222,13 @@ public class ConnectivityManager { */ public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL"; + /** + * Key for passing a user agent string to the captive portal login activity. + * {@hide} + */ + public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = + "android.net.extra.CAPTIVE_PORTAL_USER_AGENT"; + /** * Broadcast action to indicate the change of data activity status * (idle or active) on a network in a recent period. diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java index 03f0b4d5d5da6..23a8655a3bb68 100644 --- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java +++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java @@ -63,6 +63,7 @@ public class CaptivePortalLoginActivity extends Activity { private enum Result { DISMISSED, UNWANTED, WANTED_AS_IS }; private URL mUrl; + private String mUserAgent; private Network mNetwork; private CaptivePortal mCaptivePortal; private NetworkCallback mNetworkCallback; @@ -76,6 +77,8 @@ public class CaptivePortalLoginActivity extends Activity { mCm = ConnectivityManager.from(this); mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK); mCaptivePortal = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL); + mUserAgent = getIntent().getParcelableExtra( + ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT); mUrl = getUrl(); if (mUrl == null) { // getUrl() failed to parse the url provided in the intent: bail out in a way that @@ -252,6 +255,7 @@ public class CaptivePortalLoginActivity extends Activity { } private void testForCaptivePortal() { + // TODO: reuse NetworkMonitor facilities for consistent captive portal detection. new Thread(new Runnable() { public void run() { // Give time for captive portal to open. @@ -262,11 +266,14 @@ public class CaptivePortalLoginActivity extends Activity { HttpURLConnection urlConnection = null; int httpResponseCode = 500; try { - urlConnection = (HttpURLConnection) mUrl.openConnection(); + urlConnection = (HttpURLConnection) mNetwork.openConnection(mUrl); urlConnection.setInstanceFollowRedirects(false); urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); urlConnection.setUseCaches(false); + if (mUserAgent != null) { + urlConnection.setRequestProperty("User-Agent", mUserAgent); + } urlConnection.getInputStream(); httpResponseCode = urlConnection.getResponseCode(); } catch (IOException e) { diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index 5e98859141697..9ffe2b78a0957 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -433,6 +433,8 @@ public class NetworkMonitor extends StateMachine { })); intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL, mLastPortalProbeResult.detectUrl); + intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT, + getCaptivePortalUserAgent(mContext)); intent.setFlags( Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivityAsUser(intent, UserHandle.CURRENT);