Fix an infinite loop with network offers
When the avoidBadWifi configuration is false and not overridden, a WiFi network that was validated in the past but becomes unvalidated needs to outscore a cell network that is validated. This is happening correctly when the stack compares two networks. However, when the stack compares an existing network to an offer for a cellular network, the offer was automatically considered not to yield. This would mean the stack would be requesting cell out of the telephony factory, only for that network to lose to WiFi and be discarded immediately, then recreated again etc. When there is some other reason cell should be up (such as the "mobile always on" setting being active), this would not be visible because the cell network would have another reason not to be torn down. Have offers correctly account for the current value of the configuration and setting. This has the ranking of the offer lose against WiFi like the actual network loses, meaning the offer is not needed. This also requires updating the offers whenever the value of the setting changes. Test: new test for this, also ConnectivityServiceTest Bug: 195441367 Change-Id: I4fe5de98bc15bcf9bbbe25c6c7c8a7ba382f8db7
This commit is contained in:
@@ -4622,9 +4622,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateAvoidBadWifi() {
|
private void updateAvoidBadWifi() {
|
||||||
|
ensureRunningOnConnectivityServiceThread();
|
||||||
|
// Agent info scores and offer scores depend on whether cells yields to bad wifi.
|
||||||
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
|
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
|
||||||
nai.updateScoreForNetworkAgentUpdate();
|
nai.updateScoreForNetworkAgentUpdate();
|
||||||
}
|
}
|
||||||
|
// UpdateOfferScore will update mNetworkOffers inline, so make a copy first.
|
||||||
|
final ArrayList<NetworkOfferInfo> offersToUpdate = new ArrayList<>(mNetworkOffers);
|
||||||
|
for (final NetworkOfferInfo noi : offersToUpdate) {
|
||||||
|
updateOfferScore(noi.offer);
|
||||||
|
}
|
||||||
rematchAllNetworksAndRequests();
|
rematchAllNetworksAndRequests();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6413,11 +6420,23 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
Objects.requireNonNull(score);
|
Objects.requireNonNull(score);
|
||||||
Objects.requireNonNull(caps);
|
Objects.requireNonNull(caps);
|
||||||
Objects.requireNonNull(callback);
|
Objects.requireNonNull(callback);
|
||||||
|
final boolean yieldToBadWiFi = caps.hasTransport(TRANSPORT_CELLULAR) && !avoidBadWifi();
|
||||||
final NetworkOffer offer = new NetworkOffer(
|
final NetworkOffer offer = new NetworkOffer(
|
||||||
FullScore.makeProspectiveScore(score, caps), caps, callback, providerId);
|
FullScore.makeProspectiveScore(score, caps, yieldToBadWiFi),
|
||||||
|
caps, callback, providerId);
|
||||||
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_OFFER, offer));
|
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_OFFER, offer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateOfferScore(final NetworkOffer offer) {
|
||||||
|
final boolean yieldToBadWiFi =
|
||||||
|
offer.caps.hasTransport(TRANSPORT_CELLULAR) && !avoidBadWifi();
|
||||||
|
final NetworkOffer newOffer = new NetworkOffer(
|
||||||
|
offer.score.withYieldToBadWiFi(yieldToBadWiFi),
|
||||||
|
offer.caps, offer.callback, offer.providerId);
|
||||||
|
if (offer.equals(newOffer)) return;
|
||||||
|
handleRegisterNetworkOffer(newOffer);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unofferNetwork(@NonNull final INetworkOfferCallback callback) {
|
public void unofferNetwork(@NonNull final INetworkOfferCallback callback) {
|
||||||
mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_OFFER, callback));
|
mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_OFFER, callback));
|
||||||
@@ -6838,6 +6857,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
* @param newOffer The new offer. If the callback member is the same as an existing
|
* @param newOffer The new offer. If the callback member is the same as an existing
|
||||||
* offer, it is an update of that offer.
|
* offer, it is an update of that offer.
|
||||||
*/
|
*/
|
||||||
|
// TODO : rename this to handleRegisterOrUpdateNetworkOffer
|
||||||
private void handleRegisterNetworkOffer(@NonNull final NetworkOffer newOffer) {
|
private void handleRegisterNetworkOffer(@NonNull final NetworkOffer newOffer) {
|
||||||
ensureRunningOnConnectivityServiceThread();
|
ensureRunningOnConnectivityServiceThread();
|
||||||
if (!isNetworkProviderWithIdRegistered(newOffer.providerId)) {
|
if (!isNetworkProviderWithIdRegistered(newOffer.providerId)) {
|
||||||
@@ -6852,6 +6872,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
if (null != existingOffer) {
|
if (null != existingOffer) {
|
||||||
handleUnregisterNetworkOffer(existingOffer);
|
handleUnregisterNetworkOffer(existingOffer);
|
||||||
newOffer.migrateFrom(existingOffer.offer);
|
newOffer.migrateFrom(existingOffer.offer);
|
||||||
|
if (DBG) {
|
||||||
|
// handleUnregisterNetworkOffer has already logged the old offer
|
||||||
|
log("update offer from providerId " + newOffer.providerId + " new : " + newOffer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (DBG) {
|
||||||
|
log("register offer from providerId " + newOffer.providerId + " : " + newOffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
final NetworkOfferInfo noi = new NetworkOfferInfo(newOffer);
|
final NetworkOfferInfo noi = new NetworkOfferInfo(newOffer);
|
||||||
try {
|
try {
|
||||||
@@ -6866,6 +6894,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
|
|
||||||
private void handleUnregisterNetworkOffer(@NonNull final NetworkOfferInfo noi) {
|
private void handleUnregisterNetworkOffer(@NonNull final NetworkOfferInfo noi) {
|
||||||
ensureRunningOnConnectivityServiceThread();
|
ensureRunningOnConnectivityServiceThread();
|
||||||
|
if (DBG) {
|
||||||
|
log("unregister offer from providerId " + noi.offer.providerId + " : " + noi.offer);
|
||||||
|
}
|
||||||
mNetworkOffers.remove(noi);
|
mNetworkOffers.remove(noi);
|
||||||
noi.offer.callback.asBinder().unlinkToDeath(noi, 0 /* flags */);
|
noi.offer.callback.asBinder().unlinkToDeath(noi, 0 /* flags */);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ public class FullScore {
|
|||||||
* @return a FullScore appropriate for comparing to actual network's scores.
|
* @return a FullScore appropriate for comparing to actual network's scores.
|
||||||
*/
|
*/
|
||||||
public static FullScore makeProspectiveScore(@NonNull final NetworkScore score,
|
public static FullScore makeProspectiveScore(@NonNull final NetworkScore score,
|
||||||
@NonNull final NetworkCapabilities caps) {
|
@NonNull final NetworkCapabilities caps, final boolean yieldToBadWiFi) {
|
||||||
// If the network offers Internet access, it may validate.
|
// If the network offers Internet access, it may validate.
|
||||||
final boolean mayValidate = caps.hasCapability(NET_CAPABILITY_INTERNET);
|
final boolean mayValidate = caps.hasCapability(NET_CAPABILITY_INTERNET);
|
||||||
// VPN transports are known in advance.
|
// VPN transports are known in advance.
|
||||||
@@ -197,8 +197,6 @@ public class FullScore {
|
|||||||
final boolean everUserSelected = false;
|
final boolean everUserSelected = false;
|
||||||
// Don't assume the user will accept unvalidated connectivity.
|
// Don't assume the user will accept unvalidated connectivity.
|
||||||
final boolean acceptUnvalidated = false;
|
final boolean acceptUnvalidated = false;
|
||||||
// Don't assume clinging to bad wifi
|
|
||||||
final boolean yieldToBadWiFi = false;
|
|
||||||
// A prospective score is invincible if the legacy int in the filter is over the maximum
|
// A prospective score is invincible if the legacy int in the filter is over the maximum
|
||||||
// score.
|
// score.
|
||||||
final boolean invincible = score.getLegacyInt() > NetworkRanker.LEGACY_INT_MAX;
|
final boolean invincible = score.getLegacyInt() > NetworkRanker.LEGACY_INT_MAX;
|
||||||
@@ -258,6 +256,16 @@ public class FullScore {
|
|||||||
keepConnectedReason);
|
keepConnectedReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns this score but with the specified yield to bad wifi policy.
|
||||||
|
*/
|
||||||
|
public FullScore withYieldToBadWiFi(final boolean newYield) {
|
||||||
|
return new FullScore(mLegacyInt,
|
||||||
|
newYield ? mPolicies | (1L << POLICY_YIELD_TO_BAD_WIFI)
|
||||||
|
: mPolicies & ~(1L << POLICY_YIELD_TO_BAD_WIFI),
|
||||||
|
mKeepConnectedReason);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns this score but validated.
|
* Returns this score but validated.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1187,6 +1187,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
|
|||||||
? " underlying{" + Arrays.toString(declaredUnderlyingNetworks) + "}" : "")
|
? " underlying{" + Arrays.toString(declaredUnderlyingNetworks) + "}" : "")
|
||||||
+ " lp{" + linkProperties + "}"
|
+ " lp{" + linkProperties + "}"
|
||||||
+ " nc{" + networkCapabilities + "}"
|
+ " nc{" + networkCapabilities + "}"
|
||||||
|
+ " factorySerialNumber=" + factorySerialNumber
|
||||||
+ "}";
|
+ "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,12 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
|
|||||||
|
|
||||||
public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
|
public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
|
||||||
NetworkCapabilities ncTemplate, Context context) throws Exception {
|
NetworkCapabilities ncTemplate, Context context) throws Exception {
|
||||||
|
this(transport, linkProperties, ncTemplate, null /* provider */, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
|
||||||
|
NetworkCapabilities ncTemplate, NetworkProvider provider,
|
||||||
|
Context context) throws Exception {
|
||||||
final int type = transportToLegacyType(transport);
|
final int type = transportToLegacyType(transport);
|
||||||
final String typeName = ConnectivityManager.getNetworkTypeName(type);
|
final String typeName = ConnectivityManager.getNetworkTypeName(type);
|
||||||
mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
|
mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
|
||||||
@@ -124,12 +130,12 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
|
|||||||
.setLegacyTypeName(typeName)
|
.setLegacyTypeName(typeName)
|
||||||
.setLegacyExtraInfo(extraInfo)
|
.setLegacyExtraInfo(extraInfo)
|
||||||
.build();
|
.build();
|
||||||
mNetworkAgent = makeNetworkAgent(linkProperties, mNetworkAgentConfig);
|
mNetworkAgent = makeNetworkAgent(linkProperties, mNetworkAgentConfig, provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties,
|
protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties,
|
||||||
final NetworkAgentConfig nac) throws Exception {
|
final NetworkAgentConfig nac, NetworkProvider provider) throws Exception {
|
||||||
return new InstrumentedNetworkAgent(this, linkProperties, nac);
|
return new InstrumentedNetworkAgent(this, linkProperties, nac, provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class InstrumentedNetworkAgent extends NetworkAgent {
|
public static class InstrumentedNetworkAgent extends NetworkAgent {
|
||||||
@@ -138,10 +144,15 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
|
|||||||
|
|
||||||
public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp,
|
public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp,
|
||||||
NetworkAgentConfig nac) {
|
NetworkAgentConfig nac) {
|
||||||
|
this(wrapper, lp, nac, null /* provider */);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp,
|
||||||
|
NetworkAgentConfig nac, NetworkProvider provider) {
|
||||||
super(wrapper.mContext, wrapper.mHandlerThread.getLooper(), wrapper.mLogTag,
|
super(wrapper.mContext, wrapper.mHandlerThread.getLooper(), wrapper.mLogTag,
|
||||||
wrapper.mNetworkCapabilities, lp, wrapper.mScore, nac,
|
wrapper.mNetworkCapabilities, lp, wrapper.mScore, nac,
|
||||||
new NetworkProvider(wrapper.mContext, wrapper.mHandlerThread.getLooper(),
|
null != provider ? provider : new NetworkProvider(wrapper.mContext,
|
||||||
PROVIDER_NAME));
|
wrapper.mHandlerThread.getLooper(), PROVIDER_NAME));
|
||||||
mWrapper = wrapper;
|
mWrapper = wrapper;
|
||||||
register();
|
register();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,6 +241,7 @@ import android.net.NetworkInfo;
|
|||||||
import android.net.NetworkInfo.DetailedState;
|
import android.net.NetworkInfo.DetailedState;
|
||||||
import android.net.NetworkPolicyManager;
|
import android.net.NetworkPolicyManager;
|
||||||
import android.net.NetworkPolicyManager.NetworkPolicyCallback;
|
import android.net.NetworkPolicyManager.NetworkPolicyCallback;
|
||||||
|
import android.net.NetworkProvider;
|
||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
import android.net.NetworkScore;
|
import android.net.NetworkScore;
|
||||||
import android.net.NetworkSpecifier;
|
import android.net.NetworkSpecifier;
|
||||||
@@ -338,6 +339,7 @@ import com.android.testutils.ExceptionUtils;
|
|||||||
import com.android.testutils.HandlerUtils;
|
import com.android.testutils.HandlerUtils;
|
||||||
import com.android.testutils.RecorderCallback.CallbackEntry;
|
import com.android.testutils.RecorderCallback.CallbackEntry;
|
||||||
import com.android.testutils.TestableNetworkCallback;
|
import com.android.testutils.TestableNetworkCallback;
|
||||||
|
import com.android.testutils.TestableNetworkOfferCallback;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -816,17 +818,22 @@ public class ConnectivityServiceTest {
|
|||||||
private String mRedirectUrl;
|
private String mRedirectUrl;
|
||||||
|
|
||||||
TestNetworkAgentWrapper(int transport) throws Exception {
|
TestNetworkAgentWrapper(int transport) throws Exception {
|
||||||
this(transport, new LinkProperties(), null);
|
this(transport, new LinkProperties(), null /* ncTemplate */, null /* provider */);
|
||||||
}
|
}
|
||||||
|
|
||||||
TestNetworkAgentWrapper(int transport, LinkProperties linkProperties)
|
TestNetworkAgentWrapper(int transport, LinkProperties linkProperties)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
this(transport, linkProperties, null);
|
this(transport, linkProperties, null /* ncTemplate */, null /* provider */);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TestNetworkAgentWrapper(int transport, LinkProperties linkProperties,
|
private TestNetworkAgentWrapper(int transport, LinkProperties linkProperties,
|
||||||
NetworkCapabilities ncTemplate) throws Exception {
|
NetworkCapabilities ncTemplate) throws Exception {
|
||||||
super(transport, linkProperties, ncTemplate, mServiceContext);
|
this(transport, linkProperties, ncTemplate, null /* provider */);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TestNetworkAgentWrapper(int transport, LinkProperties linkProperties,
|
||||||
|
NetworkCapabilities ncTemplate, NetworkProvider provider) throws Exception {
|
||||||
|
super(transport, linkProperties, ncTemplate, provider, mServiceContext);
|
||||||
|
|
||||||
// Waits for the NetworkAgent to be registered, which includes the creation of the
|
// Waits for the NetworkAgent to be registered, which includes the creation of the
|
||||||
// NetworkMonitor.
|
// NetworkMonitor.
|
||||||
@@ -835,9 +842,40 @@ public class ConnectivityServiceTest {
|
|||||||
HandlerUtils.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS);
|
HandlerUtils.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TestInstrumentedNetworkAgent extends InstrumentedNetworkAgent {
|
||||||
|
TestInstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp,
|
||||||
|
NetworkAgentConfig nac, NetworkProvider provider) {
|
||||||
|
super(wrapper, lp, nac, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void networkStatus(int status, String redirectUrl) {
|
||||||
|
mRedirectUrl = redirectUrl;
|
||||||
|
mNetworkStatusReceived.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNetworkCreated() {
|
||||||
|
super.onNetworkCreated();
|
||||||
|
if (mCreatedCallback != null) mCreatedCallback.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNetworkUnwanted() {
|
||||||
|
super.onNetworkUnwanted();
|
||||||
|
if (mUnwantedCallback != null) mUnwantedCallback.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNetworkDestroyed() {
|
||||||
|
super.onNetworkDestroyed();
|
||||||
|
if (mDisconnectedCallback != null) mDisconnectedCallback.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties,
|
protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties,
|
||||||
NetworkAgentConfig nac) throws Exception {
|
NetworkAgentConfig nac, NetworkProvider provider) throws Exception {
|
||||||
mNetworkMonitor = mock(INetworkMonitor.class);
|
mNetworkMonitor = mock(INetworkMonitor.class);
|
||||||
|
|
||||||
final Answer validateAnswer = inv -> {
|
final Answer validateAnswer = inv -> {
|
||||||
@@ -857,31 +895,7 @@ public class ConnectivityServiceTest {
|
|||||||
nmCbCaptor.capture());
|
nmCbCaptor.capture());
|
||||||
|
|
||||||
final InstrumentedNetworkAgent na =
|
final InstrumentedNetworkAgent na =
|
||||||
new InstrumentedNetworkAgent(this, linkProperties, nac) {
|
new TestInstrumentedNetworkAgent(this, linkProperties, nac, provider);
|
||||||
@Override
|
|
||||||
public void networkStatus(int status, String redirectUrl) {
|
|
||||||
mRedirectUrl = redirectUrl;
|
|
||||||
mNetworkStatusReceived.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNetworkCreated() {
|
|
||||||
super.onNetworkCreated();
|
|
||||||
if (mCreatedCallback != null) mCreatedCallback.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNetworkUnwanted() {
|
|
||||||
super.onNetworkUnwanted();
|
|
||||||
if (mUnwantedCallback != null) mUnwantedCallback.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNetworkDestroyed() {
|
|
||||||
super.onNetworkDestroyed();
|
|
||||||
if (mDisconnectedCallback != null) mDisconnectedCallback.run();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
assertEquals(na.getNetwork().netId, nmNetworkCaptor.getValue().netId);
|
assertEquals(na.getNetwork().netId, nmNetworkCaptor.getValue().netId);
|
||||||
mNmCallbacks = nmCbCaptor.getValue();
|
mNmCallbacks = nmCbCaptor.getValue();
|
||||||
@@ -4797,6 +4811,124 @@ public class ConnectivityServiceTest {
|
|||||||
testAvoidBadWifiConfig_controlledBySettings();
|
testAvoidBadWifiConfig_controlledBySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOffersAvoidsBadWifi() throws Exception {
|
||||||
|
// Normal mode : the carrier doesn't restrict moving away from bad wifi.
|
||||||
|
// This has getAvoidBadWifi return true.
|
||||||
|
doReturn(1).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi);
|
||||||
|
// Don't request cell separately for the purposes of this test.
|
||||||
|
setAlwaysOnNetworks(false);
|
||||||
|
|
||||||
|
final NetworkProvider cellProvider = new NetworkProvider(mServiceContext,
|
||||||
|
mCsHandlerThread.getLooper(), "Cell provider");
|
||||||
|
final NetworkProvider wifiProvider = new NetworkProvider(mServiceContext,
|
||||||
|
mCsHandlerThread.getLooper(), "Wifi provider");
|
||||||
|
|
||||||
|
mCm.registerNetworkProvider(cellProvider);
|
||||||
|
mCm.registerNetworkProvider(wifiProvider);
|
||||||
|
|
||||||
|
final NetworkScore cellScore = new NetworkScore.Builder().build();
|
||||||
|
final NetworkScore wifiScore = new NetworkScore.Builder().build();
|
||||||
|
final NetworkCapabilities defaultCaps = new NetworkCapabilities.Builder()
|
||||||
|
.addCapability(NET_CAPABILITY_INTERNET)
|
||||||
|
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
|
||||||
|
.build();
|
||||||
|
final NetworkCapabilities cellCaps = new NetworkCapabilities.Builder()
|
||||||
|
.addTransportType(TRANSPORT_CELLULAR)
|
||||||
|
.addCapability(NET_CAPABILITY_INTERNET)
|
||||||
|
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
|
||||||
|
.build();
|
||||||
|
final NetworkCapabilities wifiCaps = new NetworkCapabilities.Builder()
|
||||||
|
.addTransportType(TRANSPORT_WIFI)
|
||||||
|
.addCapability(NET_CAPABILITY_INTERNET)
|
||||||
|
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
|
||||||
|
.build();
|
||||||
|
final TestableNetworkOfferCallback cellCallback = new TestableNetworkOfferCallback(
|
||||||
|
TIMEOUT_MS /* timeout */, TEST_CALLBACK_TIMEOUT_MS /* noCallbackTimeout */);
|
||||||
|
final TestableNetworkOfferCallback wifiCallback = new TestableNetworkOfferCallback(
|
||||||
|
TIMEOUT_MS /* timeout */, TEST_CALLBACK_TIMEOUT_MS /* noCallbackTimeout */);
|
||||||
|
|
||||||
|
Log.e("ConnectivityService", "test registering " + cellProvider);
|
||||||
|
// Offer callbacks will run on the CS handler thread in this test.
|
||||||
|
cellProvider.registerNetworkOffer(cellScore, cellCaps, r -> r.run(), cellCallback);
|
||||||
|
wifiProvider.registerNetworkOffer(wifiScore, wifiCaps, r -> r.run(), wifiCallback);
|
||||||
|
|
||||||
|
// Both providers see the default request.
|
||||||
|
cellCallback.expectOnNetworkNeeded(defaultCaps);
|
||||||
|
wifiCallback.expectOnNetworkNeeded(defaultCaps);
|
||||||
|
|
||||||
|
// Listen to cell and wifi to know when agents are finished processing
|
||||||
|
final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
|
||||||
|
final NetworkRequest cellRequest = new NetworkRequest.Builder()
|
||||||
|
.addTransportType(TRANSPORT_CELLULAR).build();
|
||||||
|
mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
|
||||||
|
final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
|
||||||
|
final NetworkRequest wifiRequest = new NetworkRequest.Builder()
|
||||||
|
.addTransportType(TRANSPORT_WIFI).build();
|
||||||
|
mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
|
||||||
|
|
||||||
|
// Cell connects and validates.
|
||||||
|
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR,
|
||||||
|
new LinkProperties(), null /* ncTemplate */, cellProvider);
|
||||||
|
mCellNetworkAgent.connect(true);
|
||||||
|
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
|
||||||
|
cellCallback.assertNoCallback();
|
||||||
|
wifiCallback.assertNoCallback();
|
||||||
|
|
||||||
|
// Bring up wifi. At first it's invalidated, so cell is still needed.
|
||||||
|
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI,
|
||||||
|
new LinkProperties(), null /* ncTemplate */, wifiProvider);
|
||||||
|
mWiFiNetworkAgent.connect(false);
|
||||||
|
wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
|
||||||
|
cellCallback.assertNoCallback();
|
||||||
|
wifiCallback.assertNoCallback();
|
||||||
|
|
||||||
|
// Wifi validates. Cell is no longer needed, because it's outscored.
|
||||||
|
mWiFiNetworkAgent.setNetworkValid(true /* isStrictMode */);
|
||||||
|
// Have CS reconsider the network (see testPartialConnectivity)
|
||||||
|
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
|
||||||
|
wifiNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
|
||||||
|
cellCallback.expectOnNetworkUnneeded(defaultCaps);
|
||||||
|
wifiCallback.assertNoCallback();
|
||||||
|
|
||||||
|
// Wifi is no longer validated. Cell is needed again.
|
||||||
|
mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
|
||||||
|
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
|
||||||
|
wifiNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
|
||||||
|
cellCallback.expectOnNetworkNeeded(defaultCaps);
|
||||||
|
wifiCallback.assertNoCallback();
|
||||||
|
|
||||||
|
// Disconnect wifi and pretend the carrier restricts moving away from bad wifi.
|
||||||
|
mWiFiNetworkAgent.disconnect();
|
||||||
|
wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
|
||||||
|
// This has getAvoidBadWifi return false. This test doesn't change the value of the
|
||||||
|
// associated setting.
|
||||||
|
doReturn(0).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi);
|
||||||
|
mPolicyTracker.reevaluate();
|
||||||
|
waitForIdle();
|
||||||
|
|
||||||
|
// Connect wifi again, cell is needed until wifi validates.
|
||||||
|
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI,
|
||||||
|
new LinkProperties(), null /* ncTemplate */, wifiProvider);
|
||||||
|
mWiFiNetworkAgent.connect(false);
|
||||||
|
wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
|
||||||
|
cellCallback.assertNoCallback();
|
||||||
|
wifiCallback.assertNoCallback();
|
||||||
|
mWiFiNetworkAgent.setNetworkValid(true /* isStrictMode */);
|
||||||
|
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
|
||||||
|
wifiNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
|
||||||
|
cellCallback.expectOnNetworkUnneeded(defaultCaps);
|
||||||
|
wifiCallback.assertNoCallback();
|
||||||
|
|
||||||
|
// Wifi loses validation. Because the device doesn't avoid bad wifis, cell is
|
||||||
|
// not needed.
|
||||||
|
mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
|
||||||
|
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
|
||||||
|
wifiNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
|
||||||
|
cellCallback.assertNoCallback();
|
||||||
|
wifiCallback.assertNoCallback();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAvoidBadWifi() throws Exception {
|
public void testAvoidBadWifi() throws Exception {
|
||||||
final ContentResolver cr = mServiceContext.getContentResolver();
|
final ContentResolver cr = mServiceContext.getContentResolver();
|
||||||
|
|||||||
Reference in New Issue
Block a user