am f50ac2e7
: am cfedbc43
: am 7f9e3274
: am bbce221e
: Merge "Fallback to Cellular if WiFi fails to validate" into mnc-dev
* commit 'f50ac2e7bb0842bbb30f69c898a95f894b5d506c': Fallback to Cellular if WiFi fails to validate
This commit is contained in:
@ -2064,12 +2064,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// if it's awaiting captive portal login, or if validation failed), this
|
// if it's awaiting captive portal login, or if validation failed), this
|
||||||
// may trigger a re-evaluation of the network.
|
// may trigger a re-evaluation of the network.
|
||||||
private void unlinger(NetworkAgentInfo nai) {
|
private void unlinger(NetworkAgentInfo nai) {
|
||||||
|
nai.networkLingered.clear();
|
||||||
|
if (!nai.lingering) return;
|
||||||
nai.lingering = false;
|
nai.lingering = false;
|
||||||
if (VDBG) log("Canceling linger of " + nai.name());
|
if (VDBG) log("Canceling linger of " + nai.name());
|
||||||
// If network has never been validated, it cannot have been lingered, so don't bother
|
|
||||||
// needlessly triggering a re-evaluation.
|
|
||||||
if (!nai.everValidated) return;
|
|
||||||
nai.networkLingered.clear();
|
|
||||||
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
|
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2224,23 +2222,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Is nai unneeded by all NetworkRequests (and should be disconnected)?
|
// Is nai unneeded by all NetworkRequests (and should be disconnected)?
|
||||||
// For validated Networks this is simply whether it is satsifying any NetworkRequests.
|
// This is whether it is satisfying any NetworkRequests or were it to become validated,
|
||||||
// For unvalidated Networks this is whether it is satsifying any NetworkRequests or
|
// would it have a chance of satisfying any NetworkRequests.
|
||||||
// were it to become validated, would it have a chance of satisfying any NetworkRequests.
|
|
||||||
private boolean unneeded(NetworkAgentInfo nai) {
|
private boolean unneeded(NetworkAgentInfo nai) {
|
||||||
if (!nai.created || nai.isVPN() || nai.lingering) return false;
|
if (!nai.created || nai.isVPN() || nai.lingering) return false;
|
||||||
boolean unneeded = true;
|
|
||||||
if (nai.everValidated) {
|
|
||||||
for (int i = 0; i < nai.networkRequests.size() && unneeded; i++) {
|
|
||||||
final NetworkRequest nr = nai.networkRequests.valueAt(i);
|
|
||||||
try {
|
|
||||||
if (isRequest(nr)) unneeded = false;
|
|
||||||
} catch (Exception e) {
|
|
||||||
loge("Request " + nr + " not found in mNetworkRequests.");
|
|
||||||
loge(" it came from request list of " + nai.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
|
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
|
||||||
// If this Network is already the highest scoring Network for a request, or if
|
// If this Network is already the highest scoring Network for a request, or if
|
||||||
// there is hope for it to become one if it validated, then it is needed.
|
// there is hope for it to become one if it validated, then it is needed.
|
||||||
@ -2255,12 +2240,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// WiFi ends up validating and out scoring cellular.
|
// WiFi ends up validating and out scoring cellular.
|
||||||
mNetworkForRequestId.get(nri.request.requestId).getCurrentScore() <
|
mNetworkForRequestId.get(nri.request.requestId).getCurrentScore() <
|
||||||
nai.getCurrentScoreAsValidated())) {
|
nai.getCurrentScoreAsValidated())) {
|
||||||
unneeded = false;
|
return false;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
return unneeded;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
|
private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
|
||||||
@ -4004,29 +3987,29 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
* augmented with any stateful capabilities implied from {@code networkAgent}
|
* augmented with any stateful capabilities implied from {@code networkAgent}
|
||||||
* (e.g., validated status and captive portal status).
|
* (e.g., validated status and captive portal status).
|
||||||
*
|
*
|
||||||
* @param networkAgent the network having its capabilities updated.
|
* @param nai the network having its capabilities updated.
|
||||||
* @param networkCapabilities the new network capabilities.
|
* @param networkCapabilities the new network capabilities.
|
||||||
*/
|
*/
|
||||||
private void updateCapabilities(NetworkAgentInfo networkAgent,
|
private void updateCapabilities(NetworkAgentInfo nai, NetworkCapabilities networkCapabilities) {
|
||||||
NetworkCapabilities networkCapabilities) {
|
|
||||||
// Don't modify caller's NetworkCapabilities.
|
// Don't modify caller's NetworkCapabilities.
|
||||||
networkCapabilities = new NetworkCapabilities(networkCapabilities);
|
networkCapabilities = new NetworkCapabilities(networkCapabilities);
|
||||||
if (networkAgent.lastValidated) {
|
if (nai.lastValidated) {
|
||||||
networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
|
networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
|
||||||
} else {
|
} else {
|
||||||
networkCapabilities.removeCapability(NET_CAPABILITY_VALIDATED);
|
networkCapabilities.removeCapability(NET_CAPABILITY_VALIDATED);
|
||||||
}
|
}
|
||||||
if (networkAgent.lastCaptivePortalDetected) {
|
if (nai.lastCaptivePortalDetected) {
|
||||||
networkCapabilities.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
|
networkCapabilities.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
|
||||||
} else {
|
} else {
|
||||||
networkCapabilities.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
|
networkCapabilities.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
|
||||||
}
|
}
|
||||||
if (!Objects.equals(networkAgent.networkCapabilities, networkCapabilities)) {
|
if (!Objects.equals(nai.networkCapabilities, networkCapabilities)) {
|
||||||
synchronized (networkAgent) {
|
final int oldScore = nai.getCurrentScore();
|
||||||
networkAgent.networkCapabilities = networkCapabilities;
|
synchronized (nai) {
|
||||||
|
nai.networkCapabilities = networkCapabilities;
|
||||||
}
|
}
|
||||||
rematchAllNetworksAndRequests(networkAgent, networkAgent.getCurrentScore());
|
rematchAllNetworksAndRequests(nai, oldScore);
|
||||||
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_CAP_CHANGED);
|
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4256,9 +4239,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
// Linger any networks that are no longer needed.
|
// Linger any networks that are no longer needed.
|
||||||
for (NetworkAgentInfo nai : affectedNetworks) {
|
for (NetworkAgentInfo nai : affectedNetworks) {
|
||||||
if (nai.everValidated && unneeded(nai)) {
|
if (nai.lingering) {
|
||||||
|
// Already lingered. Nothing to do. This can only happen if "nai" is in
|
||||||
|
// "affectedNetworks" twice. The reasoning being that to get added to
|
||||||
|
// "affectedNetworks", "nai" must have been satisfying a NetworkRequest
|
||||||
|
// (i.e. not lingered) so it could have only been lingered by this loop.
|
||||||
|
// unneeded(nai) will be false and we'll call unlinger() below which would
|
||||||
|
// be bad, so handle it here.
|
||||||
|
} else if (unneeded(nai)) {
|
||||||
linger(nai);
|
linger(nai);
|
||||||
} else {
|
} else {
|
||||||
|
// Clear nai.networkLingered we might have added above.
|
||||||
unlinger(nai);
|
unlinger(nai);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4292,7 +4283,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
|
mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
|
||||||
oldDefaultNetwork, true);
|
oldDefaultNetwork, true);
|
||||||
}
|
}
|
||||||
mDefaultInetConditionPublished = newNetwork.everValidated ? 100 : 0;
|
mDefaultInetConditionPublished = newNetwork.lastValidated ? 100 : 0;
|
||||||
mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
|
mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
|
||||||
notifyLockdownVpn(newNetwork);
|
notifyLockdownVpn(newNetwork);
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.server.connectivity;
|
package com.android.server.connectivity;
|
||||||
|
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
import android.net.Network;
|
import android.net.Network;
|
||||||
@ -39,6 +41,62 @@ import java.util.Comparator;
|
|||||||
* AsyncChannel/messenger for reaching that NetworkAgent and lists of NetworkRequests
|
* AsyncChannel/messenger for reaching that NetworkAgent and lists of NetworkRequests
|
||||||
* interested in using it. Default sort order is descending by score.
|
* interested in using it. Default sort order is descending by score.
|
||||||
*/
|
*/
|
||||||
|
// States of a network:
|
||||||
|
// --------------------
|
||||||
|
// 1. registered, uncreated, disconnected, unvalidated
|
||||||
|
// This state is entered when a NetworkFactory registers a NetworkAgent in any state except
|
||||||
|
// the CONNECTED state.
|
||||||
|
// 2. registered, uncreated, connected, unvalidated
|
||||||
|
// This state is entered when a registered NetworkAgent transitions to the CONNECTED state
|
||||||
|
// ConnectivityService will tell netd to create the network and immediately transition to
|
||||||
|
// state #3.
|
||||||
|
// 3. registered, created, connected, unvalidated
|
||||||
|
// If this network can satsify the default NetworkRequest, then NetworkMonitor will
|
||||||
|
// probe for Internet connectivity.
|
||||||
|
// If this network cannot satisfy the default NetworkRequest, it will immediately be
|
||||||
|
// transitioned to state #4.
|
||||||
|
// A network may remain in this state if NetworkMonitor fails to find Internet connectivity,
|
||||||
|
// for example:
|
||||||
|
// a. a captive portal is present, or
|
||||||
|
// b. a WiFi router whose Internet backhaul is down, or
|
||||||
|
// c. a wireless connection stops transfering packets temporarily (e.g. device is in elevator
|
||||||
|
// or tunnel) but does not disconnect from the AP/cell tower, or
|
||||||
|
// d. a stand-alone device offering a WiFi AP without an uplink for configuration purposes.
|
||||||
|
// 4. registered, created, connected, validated
|
||||||
|
//
|
||||||
|
// The device's default network connection:
|
||||||
|
// ----------------------------------------
|
||||||
|
// Networks in states #3 and #4 may be used as a device's default network connection if they
|
||||||
|
// satisfy the default NetworkRequest.
|
||||||
|
// A network, that satisfies the default NetworkRequest, in state #4 should always be chosen
|
||||||
|
// in favor of a network, that satisfies the default NetworkRequest, in state #3.
|
||||||
|
// When deciding between two networks, that both satisfy the default NetworkRequest, to select
|
||||||
|
// for the default network connection, the one with the higher score should be chosen.
|
||||||
|
//
|
||||||
|
// When a network disconnects:
|
||||||
|
// ---------------------------
|
||||||
|
// If a network's transport disappears, for example:
|
||||||
|
// a. WiFi turned off, or
|
||||||
|
// b. cellular data turned off, or
|
||||||
|
// c. airplane mode is turned on, or
|
||||||
|
// d. a wireless connection disconnects from AP/cell tower entirely (e.g. device is out of range
|
||||||
|
// of AP for an extended period of time, or switches to another AP without roaming)
|
||||||
|
// then that network can transition from any state (#1-#4) to unregistered. This happens by
|
||||||
|
// the transport disconnecting their NetworkAgent's AsyncChannel with ConnectivityManager.
|
||||||
|
// ConnectivityService also tells netd to destroy the network.
|
||||||
|
//
|
||||||
|
// When ConnectivityService disconnects a network:
|
||||||
|
// -----------------------------------------------
|
||||||
|
// If a network has no chance of satisfying any requests (even if it were to become validated
|
||||||
|
// and enter state #4), ConnectivityService will disconnect the NetworkAgent's AsyncChannel.
|
||||||
|
// If the network ever for any period of time had satisfied a NetworkRequest (i.e. had been
|
||||||
|
// the highest scoring that satisfied the NetworkRequest's constraints), but is no longer the
|
||||||
|
// highest scoring network for any NetworkRequest, then there will be a 30s pause before
|
||||||
|
// ConnectivityService disconnects the NetworkAgent's AsyncChannel. During this pause the
|
||||||
|
// network is considered "lingering". This pause exists to allow network communication to be
|
||||||
|
// wrapped up rather than abruptly terminated. During this pause if the network begins satisfying
|
||||||
|
// a NetworkRequest, ConnectivityService will cancel the future disconnection of the NetworkAgent's
|
||||||
|
// AsyncChannel, and the network is no longer considered "lingering".
|
||||||
public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
||||||
public NetworkInfo networkInfo;
|
public NetworkInfo networkInfo;
|
||||||
// This Network object should always be used if possible, so as to encourage reuse of the
|
// This Network object should always be used if possible, so as to encourage reuse of the
|
||||||
@ -156,7 +214,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int score = currentScore;
|
int score = currentScore;
|
||||||
if (!everValidated && !pretendValidated) score -= UNVALIDATED_SCORE_PENALTY;
|
// Use NET_CAPABILITY_VALIDATED here instead of lastValidated, this allows
|
||||||
|
// ConnectivityService.updateCapabilities() to compute the old score prior to updating
|
||||||
|
// networkCapabilities (with a potentially different validated state).
|
||||||
|
if (!networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED) && !pretendValidated) {
|
||||||
|
score -= UNVALIDATED_SCORE_PENALTY;
|
||||||
|
}
|
||||||
if (score < 0) score = 0;
|
if (score < 0) score = 0;
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
@ -585,9 +585,12 @@ public class NetworkMonitor extends StateMachine {
|
|||||||
switch (message.what) {
|
switch (message.what) {
|
||||||
case CMD_NETWORK_CONNECTED:
|
case CMD_NETWORK_CONNECTED:
|
||||||
log("Unlingered");
|
log("Unlingered");
|
||||||
// Go straight to active as we've already evaluated.
|
// If already validated, go straight to validated state.
|
||||||
|
if (mNetworkAgentInfo.lastValidated) {
|
||||||
transitionTo(mValidatedState);
|
transitionTo(mValidatedState);
|
||||||
return HANDLED;
|
return HANDLED;
|
||||||
|
}
|
||||||
|
return NOT_HANDLED;
|
||||||
case CMD_LINGER_EXPIRED:
|
case CMD_LINGER_EXPIRED:
|
||||||
if (message.arg1 != mLingerToken)
|
if (message.arg1 != mLingerToken)
|
||||||
return HANDLED;
|
return HANDLED;
|
||||||
|
@ -151,6 +151,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
private final NetworkInfo mNetworkInfo;
|
private final NetworkInfo mNetworkInfo;
|
||||||
private final NetworkCapabilities mNetworkCapabilities;
|
private final NetworkCapabilities mNetworkCapabilities;
|
||||||
private final Thread mThread;
|
private final Thread mThread;
|
||||||
|
private final ConditionVariable mDisconnected = new ConditionVariable();
|
||||||
private int mScore;
|
private int mScore;
|
||||||
private NetworkAgent mNetworkAgent;
|
private NetworkAgent mNetworkAgent;
|
||||||
|
|
||||||
@ -177,7 +178,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
mNetworkAgent = new NetworkAgent(Looper.myLooper(), mServiceContext,
|
mNetworkAgent = new NetworkAgent(Looper.myLooper(), mServiceContext,
|
||||||
"Mock" + typeName, mNetworkInfo, mNetworkCapabilities,
|
"Mock" + typeName, mNetworkInfo, mNetworkCapabilities,
|
||||||
new LinkProperties(), mScore, new NetworkMisc()) {
|
new LinkProperties(), mScore, new NetworkMisc()) {
|
||||||
public void unwanted() {}
|
public void unwanted() { mDisconnected.open(); }
|
||||||
};
|
};
|
||||||
initComplete.open();
|
initComplete.open();
|
||||||
Looper.loop();
|
Looper.loop();
|
||||||
@ -197,8 +198,13 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
|
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void connectWithoutInternet() {
|
||||||
|
mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
|
||||||
|
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transition this NetworkAgent to CONNECTED state.
|
* Transition this NetworkAgent to CONNECTED state with NET_CAPABILITY_INTERNET.
|
||||||
* @param validated Indicate if network should pretend to be validated.
|
* @param validated Indicate if network should pretend to be validated.
|
||||||
*/
|
*/
|
||||||
public void connect(boolean validated) {
|
public void connect(boolean validated) {
|
||||||
@ -231,8 +237,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
|
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
|
connectWithoutInternet();
|
||||||
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
|
|
||||||
|
|
||||||
if (validated) {
|
if (validated) {
|
||||||
// Wait for network to validate.
|
// Wait for network to validate.
|
||||||
@ -252,6 +257,10 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
public Network getNetwork() {
|
public Network getNetwork() {
|
||||||
return new Network(mNetworkAgent.netId);
|
return new Network(mNetworkAgent.netId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConditionVariable getDisconnectedCV() {
|
||||||
|
return mDisconnected;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MockNetworkFactory extends NetworkFactory {
|
private static class MockNetworkFactory extends NetworkFactory {
|
||||||
@ -575,6 +584,34 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
verifyNoNetwork();
|
verifyNoNetwork();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@LargeTest
|
||||||
|
public void testUnlingeringDoesNotValidate() throws Exception {
|
||||||
|
// Test bringing up unvalidated cellular.
|
||||||
|
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
||||||
|
ConditionVariable cv = waitForConnectivityBroadcasts(1);
|
||||||
|
mCellNetworkAgent.connect(false);
|
||||||
|
waitFor(cv);
|
||||||
|
verifyActiveNetwork(TRANSPORT_CELLULAR);
|
||||||
|
assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
|
||||||
|
NET_CAPABILITY_VALIDATED));
|
||||||
|
// Test bringing up validated WiFi.
|
||||||
|
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||||
|
cv = waitForConnectivityBroadcasts(2);
|
||||||
|
mWiFiNetworkAgent.connect(true);
|
||||||
|
waitFor(cv);
|
||||||
|
verifyActiveNetwork(TRANSPORT_WIFI);
|
||||||
|
assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
|
||||||
|
NET_CAPABILITY_VALIDATED));
|
||||||
|
// Test WiFi disconnect.
|
||||||
|
cv = waitForConnectivityBroadcasts(2);
|
||||||
|
mWiFiNetworkAgent.disconnect();
|
||||||
|
waitFor(cv);
|
||||||
|
verifyActiveNetwork(TRANSPORT_CELLULAR);
|
||||||
|
// Unlingering a network should not cause it to be marked as validated.
|
||||||
|
assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
|
||||||
|
NET_CAPABILITY_VALIDATED));
|
||||||
|
}
|
||||||
|
|
||||||
@LargeTest
|
@LargeTest
|
||||||
public void testCellularOutscoresWeakWifi() throws Exception {
|
public void testCellularOutscoresWeakWifi() throws Exception {
|
||||||
// Test bringing up validated cellular.
|
// Test bringing up validated cellular.
|
||||||
@ -603,6 +640,107 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
mWiFiNetworkAgent.disconnect();
|
mWiFiNetworkAgent.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@LargeTest
|
||||||
|
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.
|
||||||
|
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||||
|
ConditionVariable cv = mWiFiNetworkAgent.getDisconnectedCV();
|
||||||
|
mWiFiNetworkAgent.connectWithoutInternet();
|
||||||
|
waitFor(cv);
|
||||||
|
// Test bringing up cellular without NET_CAPABILITY_INTERNET.
|
||||||
|
// Expect it to be torn down immediately because it satisfies no requests.
|
||||||
|
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||||
|
cv = mCellNetworkAgent.getDisconnectedCV();
|
||||||
|
mCellNetworkAgent.connectWithoutInternet();
|
||||||
|
waitFor(cv);
|
||||||
|
// Test bringing up validated WiFi.
|
||||||
|
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||||
|
cv = waitForConnectivityBroadcasts(1);
|
||||||
|
mWiFiNetworkAgent.connect(true);
|
||||||
|
waitFor(cv);
|
||||||
|
verifyActiveNetwork(TRANSPORT_WIFI);
|
||||||
|
// Test bringing up unvalidated cellular.
|
||||||
|
// Expect it to be torn down because it could never be the highest scoring network
|
||||||
|
// satisfying the default request even if it validated.
|
||||||
|
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
||||||
|
cv = mCellNetworkAgent.getDisconnectedCV();
|
||||||
|
mCellNetworkAgent.connect(false);
|
||||||
|
waitFor(cv);
|
||||||
|
verifyActiveNetwork(TRANSPORT_WIFI);
|
||||||
|
cv = mWiFiNetworkAgent.getDisconnectedCV();
|
||||||
|
mWiFiNetworkAgent.disconnect();
|
||||||
|
waitFor(cv);
|
||||||
|
}
|
||||||
|
|
||||||
|
@LargeTest
|
||||||
|
public void testCellularFallback() throws Exception {
|
||||||
|
// Test bringing up validated cellular.
|
||||||
|
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
||||||
|
ConditionVariable cv = waitForConnectivityBroadcasts(1);
|
||||||
|
mCellNetworkAgent.connect(true);
|
||||||
|
waitFor(cv);
|
||||||
|
verifyActiveNetwork(TRANSPORT_CELLULAR);
|
||||||
|
// Test bringing up validated WiFi.
|
||||||
|
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||||
|
cv = waitForConnectivityBroadcasts(2);
|
||||||
|
mWiFiNetworkAgent.connect(true);
|
||||||
|
waitFor(cv);
|
||||||
|
verifyActiveNetwork(TRANSPORT_WIFI);
|
||||||
|
// Reevaluate WiFi (it'll instantly fail DNS).
|
||||||
|
cv = waitForConnectivityBroadcasts(2);
|
||||||
|
assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
|
||||||
|
NET_CAPABILITY_VALIDATED));
|
||||||
|
mCm.reportBadNetwork(mWiFiNetworkAgent.getNetwork());
|
||||||
|
// Should quickly fall back to Cellular.
|
||||||
|
waitFor(cv);
|
||||||
|
assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
|
||||||
|
NET_CAPABILITY_VALIDATED));
|
||||||
|
verifyActiveNetwork(TRANSPORT_CELLULAR);
|
||||||
|
// Reevaluate cellular (it'll instantly fail DNS).
|
||||||
|
cv = waitForConnectivityBroadcasts(2);
|
||||||
|
assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
|
||||||
|
NET_CAPABILITY_VALIDATED));
|
||||||
|
mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
|
||||||
|
// Should quickly fall back to WiFi.
|
||||||
|
waitFor(cv);
|
||||||
|
assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
|
||||||
|
NET_CAPABILITY_VALIDATED));
|
||||||
|
assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
|
||||||
|
NET_CAPABILITY_VALIDATED));
|
||||||
|
verifyActiveNetwork(TRANSPORT_WIFI);
|
||||||
|
mCellNetworkAgent.disconnect();
|
||||||
|
mWiFiNetworkAgent.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@LargeTest
|
||||||
|
public void testWiFiFallback() throws Exception {
|
||||||
|
// Test bringing up unvalidated WiFi.
|
||||||
|
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||||
|
ConditionVariable cv = waitForConnectivityBroadcasts(1);
|
||||||
|
mWiFiNetworkAgent.connect(false);
|
||||||
|
waitFor(cv);
|
||||||
|
verifyActiveNetwork(TRANSPORT_WIFI);
|
||||||
|
// Test bringing up validated cellular.
|
||||||
|
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
||||||
|
cv = waitForConnectivityBroadcasts(2);
|
||||||
|
mCellNetworkAgent.connect(true);
|
||||||
|
waitFor(cv);
|
||||||
|
verifyActiveNetwork(TRANSPORT_CELLULAR);
|
||||||
|
// Reevaluate cellular (it'll instantly fail DNS).
|
||||||
|
cv = waitForConnectivityBroadcasts(2);
|
||||||
|
assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
|
||||||
|
NET_CAPABILITY_VALIDATED));
|
||||||
|
mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
|
||||||
|
// Should quickly fall back to WiFi.
|
||||||
|
waitFor(cv);
|
||||||
|
assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
|
||||||
|
NET_CAPABILITY_VALIDATED));
|
||||||
|
verifyActiveNetwork(TRANSPORT_WIFI);
|
||||||
|
mCellNetworkAgent.disconnect();
|
||||||
|
mWiFiNetworkAgent.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
enum CallbackState {
|
enum CallbackState {
|
||||||
NONE,
|
NONE,
|
||||||
AVAILABLE,
|
AVAILABLE,
|
||||||
@ -872,6 +1010,71 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
} catch (IllegalArgumentException expected) {}
|
} catch (IllegalArgumentException expected) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@LargeTest
|
||||||
|
public void testMMSonWiFi() throws Exception {
|
||||||
|
// Test bringing up cellular without MMS NetworkRequest gets reaped
|
||||||
|
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
||||||
|
mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
|
||||||
|
ConditionVariable cv = mCellNetworkAgent.getDisconnectedCV();
|
||||||
|
mCellNetworkAgent.connectWithoutInternet();
|
||||||
|
waitFor(cv);
|
||||||
|
waitFor(new Criteria() {
|
||||||
|
public boolean get() { return mCm.getAllNetworks().length == 0; } });
|
||||||
|
verifyNoNetwork();
|
||||||
|
// Test bringing up validated WiFi.
|
||||||
|
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||||
|
cv = waitForConnectivityBroadcasts(1);
|
||||||
|
mWiFiNetworkAgent.connect(true);
|
||||||
|
waitFor(cv);
|
||||||
|
verifyActiveNetwork(TRANSPORT_WIFI);
|
||||||
|
// Register MMS NetworkRequest
|
||||||
|
NetworkRequest.Builder builder = new NetworkRequest.Builder();
|
||||||
|
builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
|
||||||
|
final TestNetworkCallback networkCallback = new TestNetworkCallback();
|
||||||
|
mCm.requestNetwork(builder.build(), networkCallback);
|
||||||
|
// Test bringing up unvalidated cellular with MMS
|
||||||
|
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
||||||
|
mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
|
||||||
|
cv = networkCallback.getConditionVariable();
|
||||||
|
mCellNetworkAgent.connectWithoutInternet();
|
||||||
|
waitFor(cv);
|
||||||
|
assertEquals(CallbackState.AVAILABLE, networkCallback.getLastCallback());
|
||||||
|
verifyActiveNetwork(TRANSPORT_WIFI);
|
||||||
|
// Test releasing NetworkRequest disconnects cellular with MMS
|
||||||
|
cv = mCellNetworkAgent.getDisconnectedCV();
|
||||||
|
mCm.unregisterNetworkCallback(networkCallback);
|
||||||
|
waitFor(cv);
|
||||||
|
verifyActiveNetwork(TRANSPORT_WIFI);
|
||||||
|
}
|
||||||
|
|
||||||
|
@LargeTest
|
||||||
|
public void testMMSonCell() throws Exception {
|
||||||
|
// Test bringing up cellular without MMS
|
||||||
|
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
||||||
|
ConditionVariable cv = waitForConnectivityBroadcasts(1);
|
||||||
|
mCellNetworkAgent.connect(false);
|
||||||
|
waitFor(cv);
|
||||||
|
verifyActiveNetwork(TRANSPORT_CELLULAR);
|
||||||
|
// Register MMS NetworkRequest
|
||||||
|
NetworkRequest.Builder builder = new NetworkRequest.Builder();
|
||||||
|
builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
|
||||||
|
final TestNetworkCallback networkCallback = new TestNetworkCallback();
|
||||||
|
mCm.requestNetwork(builder.build(), networkCallback);
|
||||||
|
// Test bringing up MMS cellular network
|
||||||
|
cv = networkCallback.getConditionVariable();
|
||||||
|
MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
||||||
|
mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
|
||||||
|
mmsNetworkAgent.connectWithoutInternet();
|
||||||
|
waitFor(cv);
|
||||||
|
assertEquals(CallbackState.AVAILABLE, networkCallback.getLastCallback());
|
||||||
|
verifyActiveNetwork(TRANSPORT_CELLULAR);
|
||||||
|
// Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
|
||||||
|
cv = mmsNetworkAgent.getDisconnectedCV();
|
||||||
|
mCm.unregisterNetworkCallback(networkCallback);
|
||||||
|
waitFor(cv);
|
||||||
|
verifyActiveNetwork(TRANSPORT_CELLULAR);
|
||||||
|
}
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
// public void tearDown() throws Exception {
|
// public void tearDown() throws Exception {
|
||||||
// super.tearDown();
|
// super.tearDown();
|
||||||
|
Reference in New Issue
Block a user