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:
Chalard Jean
2021-08-18 01:35:19 +09:00
parent 7262180c07
commit bb902a5fee
5 changed files with 221 additions and 38 deletions

View File

@@ -4622,9 +4622,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private void updateAvoidBadWifi() {
ensureRunningOnConnectivityServiceThread();
// Agent info scores and offer scores depend on whether cells yields to bad wifi.
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
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();
}
@@ -6413,11 +6420,23 @@ public class ConnectivityService extends IConnectivityManager.Stub
Objects.requireNonNull(score);
Objects.requireNonNull(caps);
Objects.requireNonNull(callback);
final boolean yieldToBadWiFi = caps.hasTransport(TRANSPORT_CELLULAR) && !avoidBadWifi();
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));
}
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
public void unofferNetwork(@NonNull final INetworkOfferCallback 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
* offer, it is an update of that offer.
*/
// TODO : rename this to handleRegisterOrUpdateNetworkOffer
private void handleRegisterNetworkOffer(@NonNull final NetworkOffer newOffer) {
ensureRunningOnConnectivityServiceThread();
if (!isNetworkProviderWithIdRegistered(newOffer.providerId)) {
@@ -6852,6 +6872,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (null != existingOffer) {
handleUnregisterNetworkOffer(existingOffer);
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);
try {
@@ -6866,6 +6894,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void handleUnregisterNetworkOffer(@NonNull final NetworkOfferInfo noi) {
ensureRunningOnConnectivityServiceThread();
if (DBG) {
log("unregister offer from providerId " + noi.offer.providerId + " : " + noi.offer);
}
mNetworkOffers.remove(noi);
noi.offer.callback.asBinder().unlinkToDeath(noi, 0 /* flags */);
}