Merge changes from topic 'framework-net-aosp'
* changes:
DO NOT MERGE: [CS] Remove timeout event after first available
DO NOT MERGE: ApfTest: tag tests with @SmallTest or @MediumTest
DO NOT MERGE: Unbreak TetherInterfaceStateMachineTest.
DO NOT MERGE: Move the connectivity tests to frameworks/base/tests/net.
DO NOT MERGE: De-guava BroadcastInterceptingContext and move it to testutils.
DO NOT MERGE: Move FakeSettingsProvider to a common location.
DO NOT MERGE: ConnectivityServiceTest: mark flaky test as such
DO NOT MERGE: Add option to skip and avoid captive portals.
DO NOT MERGE: ApfFilter: use elapsedRealTime for RA lifetime
DO NOT MERGE: Do not synchronize boolean reads/writes
DO NOT MERGE: ApfFilter: systematically use u8, u16, u32 getters
DO NOT MERGE: Add fuzzing tests to ApfFilter RA processing
DO NOT MERGE: Support timeouts for requestNetwork() invocations.
DO NOT MERGE: Silence the obnoxious MTU 0 error message that occur when no MTU is specified for a given network.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 0afb546..43c8c81 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2592,7 +2592,8 @@
/**
* 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 @@
/** @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 HashMap<NetworkRequest, NetworkCallback>mCallbackMap;
private final AtomicInteger mRefCount;
@@ -2831,7 +2852,7 @@
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 @@
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/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1350bfa..db7baac 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8028,11 +8028,45 @@
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/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk
index 6d1ebb4..981be11 100644
--- a/core/tests/utiltests/Android.mk
+++ b/core/tests/utiltests/Android.mk
@@ -14,6 +14,7 @@
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 97%
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 05de0a5..f2be109 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/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 30edd9f..090c744 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1813,11 +1813,14 @@
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;
@@ -2263,11 +2266,19 @@
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) {
@@ -2288,6 +2299,12 @@
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:
@@ -2597,14 +2614,28 @@
"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) {
@@ -2698,7 +2729,7 @@
}
}
}
- callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED, 0);
+ callCallbackForRequest(nri, null, whichCallback, 0);
}
@Override
@@ -2935,6 +2966,11 @@
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;
@@ -5315,6 +5351,7 @@
// 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/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 6eb89fa..c73d1dd 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 @@
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 @@
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 @@
@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/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 0beb227..6d96a10 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -71,6 +71,7 @@
import com.android.internal.util.StateMachine;
import com.android.server.connectivity.tethering.IControlsTethering;
import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
+import com.android.server.connectivity.tethering.IPv6TetheringInterfaceServices;
import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
import com.android.server.net.BaseNetworkObserver;
@@ -1939,7 +1940,8 @@
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 c2c1a8c..dec2f77 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 @@
/**
* @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 @@
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 6ca4e27..37221a9 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 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/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 4c75452..a8356dc 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -283,14 +283,20 @@
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 {
+ 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 +368,7 @@
} 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 "???";
}
@@ -372,16 +378,16 @@
// 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++) {
@@ -395,7 +401,7 @@
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);
}
@@ -403,7 +409,7 @@
rdnssOptionToString(sb, i);
}
return sb.toString();
- } catch (BufferUnderflowException | IndexOutOfBoundsException e) {
+ } catch (BufferUnderflowException|IndexOutOfBoundsException e) {
return "<Malformed RA>";
}
}
@@ -436,16 +442,20 @@
// 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();
// 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) {
- throw new IllegalArgumentException("Not an 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");
}
@@ -466,8 +476,8 @@
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:
@@ -511,7 +521,7 @@
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);
@@ -552,10 +562,10 @@
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);
@@ -925,8 +935,8 @@
// 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 +982,8 @@
* 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 +1022,7 @@
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.
@@ -1150,7 +1161,11 @@
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));
}
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index a6bb40c..a883e28 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.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 @@
private Map<InetAddress, Short> 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 void stop() {
- synchronized (mLock) { mRunning = false; }
+ mRunning = false;
clearLinkProperties();
mNetlinkSocketObserver.clearNetlinkSocket();
}
@@ -281,12 +280,6 @@
}
}
- private boolean stillRunning() {
- synchronized (mLock) {
- return mRunning;
- }
- }
-
private static boolean isOnLink(List<RouteInfo> routes, InetAddress ip) {
for (RouteInfo route : routes) {
if (!route.hasGateway() && route.matches(ip)) {
@@ -390,12 +383,12 @@
}
public void probeAll() {
- Set<InetAddress> ipProbeList = new HashSet<InetAddress>();
+ final List<InetAddress> 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 @@
}
for (InetAddress target : ipProbeList) {
- if (!stillRunning()) {
+ if (!mRunning) {
break;
}
final int returnValue = probeNeighbor(mInterfaceIndex, target);
@@ -451,21 +444,21 @@
@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 @@
clearNetlinkSocket();
- synchronized (mLock) { mRunning = false; }
+ mRunning = false; // Not a no-op when ErrnoException happened.
if (VDBG) { Log.d(TAG, "Finishing observing thread."); }
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
index 0d5daa5..f841bf9 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.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 541be3d..8d36ac9 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.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 94c6711..4b69eb3 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.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/tests/net/Android.mk b/tests/net/Android.mk
new file mode 100644
index 0000000..8aa27a9
--- /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 0000000..e069dd0
--- /dev/null
+++ b/tests/net/AndroidManifest.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.tests.net">
+
+ <uses-permission android:name="android.permission.READ_LOGS" />
+ <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
+ <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+ <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
+ <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+ <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
+ <uses-permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.MANAGE_USERS" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
+ <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
+ <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
+ <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
+ <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.tests.net"
+ android:label="Frameworks Networking Tests" />
+</manifest>
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 221fe0f..0a56e1b 100644
--- a/services/tests/servicestests/src/android/net/UidRangeTest.java
+++ b/tests/net/java/android/net/UidRangeTest.java
@@ -26,7 +26,7 @@
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 96%
rename from services/tests/servicestests/src/android/net/apf/ApfTest.java
rename to tests/net/java/android/net/apf/ApfTest.java
index f7c61d1..81f66a5 100644
--- a/services/tests/servicestests/src/android/net/apf/ApfTest.java
+++ b/tests/net/java/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;
@@ -36,7 +32,12 @@
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;
+import com.android.internal.util.HexDump;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -54,6 +55,7 @@
import java.net.NetworkInterface;
import java.nio.ByteBuffer;
import java.util.List;
+import java.util.Random;
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -74,7 +76,7 @@
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.
@@ -153,7 +155,7 @@
* 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
@@ -561,7 +563,7 @@
* 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",
@@ -719,7 +721,7 @@
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);
@@ -774,7 +776,7 @@
apfFilter.shutdown();
}
- @LargeTest
+ @MediumTest
public void testApfFilterIPv6() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
@@ -800,7 +802,7 @@
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};
@@ -910,7 +912,7 @@
assertDrop(program, garpReply());
}
- @LargeTest
+ @MediumTest
public void testApfFilterArp() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
@@ -1029,7 +1031,7 @@
ipManagerCallback.assertNoProgramUpdate();
}
- @LargeTest
+ @MediumTest
public void testApfFilterRa() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
@@ -1146,6 +1148,41 @@
buffer.position(original);
}
+ @SmallTest
+ 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);
+ }
+ }
+ }
+
+ @SmallTest
+ 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.
@@ -1167,6 +1204,7 @@
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));
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 93%
rename from services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
rename to tests/net/java/com/android/server/ConnectivityServiceTest.java
index 4af1cf1..fc8cc81 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -68,14 +68,16 @@
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;
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.BroadcastInterceptingContext;
+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;
@@ -215,8 +217,20 @@
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()) {
@@ -236,6 +250,7 @@
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 +306,11 @@
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 +395,6 @@
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 +406,10 @@
return new Network(mNetworkAgent.netId);
}
+ public ConditionVariable getPreventReconnectReceived() {
+ return mPreventReconnectReceived;
+ }
+
public ConditionVariable getDisconnectedCV() {
return mDisconnected;
}
@@ -597,6 +616,7 @@
@Override
protected CaptivePortalProbeResult isCaptivePortal() {
+ if (!mIsCaptivePortalCheckEnabled) { return new CaptivePortalProbeResult(204); }
return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl, null);
}
}
@@ -707,10 +727,7 @@
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();
}
}
@@ -743,6 +760,9 @@
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 {
@@ -1077,7 +1097,8 @@
NETWORK_CAPABILITIES,
LINK_PROPERTIES,
LOSING,
- LOST
+ LOST,
+ UNAVAILABLE
}
/**
@@ -1118,6 +1139,11 @@
}
@Override
+ public void onUnavailable() {
+ setLastCallback(CallbackState.UNAVAILABLE, null, null);
+ }
+
+ @Override
public void onLosing(Network network, int maxMsToLive) {
setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
}
@@ -1704,6 +1730,47 @@
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;
@@ -1844,6 +1911,11 @@
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);
@@ -2221,6 +2293,96 @@
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
+ 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();
+ }
+
+ /**
+ * 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!
+ sleepFor(15);
+ 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 };
@@ -2625,4 +2787,13 @@
mCm.unregisterNetworkCallback(pendingIntent);
}
}
+
+ /* test utilities */
+ static private void sleepFor(int ms) {
+ try {
+ Thread.sleep(ms);
+ } catch (InterruptedException e) {
+ }
+
+ }
}
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 97%
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
index a30b362..9f7261d 100644
--- a/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -59,13 +59,14 @@
@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 @@
@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 @@
upstreamIface);
mLooper.dispatchAll();
}
-}
\ No newline at end of file
+}
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
Binary files differ
diff --git a/tests/utils/testutils/Android.mk b/tests/utils/testutils/Android.mk
index d53167f..acbe4bc 100644
--- a/tests/utils/testutils/Android.mk
+++ b/tests/utils/testutils/Android.mk
@@ -27,4 +27,6 @@
android-support-test \
mockito-target
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/tests/servicestests/src/com/android/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 13657ab..27b7419 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.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 @@
public class BroadcastInterceptingContext extends ContextWrapper {
private static final String TAG = "WatchingContext";
- private final List<BroadcastInterceptor> mInterceptors = Lists.newArrayList();
+ private final List<BroadcastInterceptor> mInterceptors = new ArrayList<>();
- public class BroadcastInterceptor extends AbstractFuture<Intent> {
+ public abstract class FutureIntent extends FutureTask<Intent> {
+ 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 @@
super(base);
}
- public Future<Intent> nextBroadcastIntent(String action) {
+ public FutureIntent nextBroadcastIntent(String action) {
return nextBroadcastIntent(new IntentFilter(action));
}
- public Future<Intent> nextBroadcastIntent(IntentFilter filter) {
+ public FutureIntent nextBroadcastIntent(IntentFilter filter) {
final BroadcastInterceptor interceptor = new BroadcastInterceptor(null, filter);
synchronized (mInterceptors) {
mInterceptors.add(interceptor);
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 98%
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 808f4dd..8ca849b 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;