[NS05] Feed network offer callbacks

The design is very simply expressed :
An offer is needed for a request if and only if that offer
might beat the satisfier for that request.

The implementation of "might beat" is NetworkRanker#mightBeat.

Test: FrameworksNetTests FrameworksWifiTests NetworkStackTests
Bug: 167544279
Merged-In: I3c2563d4ae4e3715d0c6270344ba8f7ef067872f
Merged-In: I0fe911eef2483ecbac48c733d56283b81538690a
Change-Id: I0fe911eef2483ecbac48c733d56283b81538690a
  (cherry-picked from 7b6a33bd50)
This commit is contained in:
Chalard Jean
2021-01-12 10:58:56 +09:00
committed by Junyu Lai
parent 3c5921caea
commit 0354d8c7e0
11 changed files with 625 additions and 294 deletions

View File

@@ -3359,8 +3359,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
nai.lastValidated = valid;
nai.everValidated |= valid;
updateCapabilities(oldScore, nai, nai.networkCapabilities);
// If score has changed, rebroadcast to NetworkProviders. b/17726566
if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
if (valid) {
handleFreshlyValidatedNetwork(nai);
// Clear NO_INTERNET, PRIVATE_DNS_BROKEN, PARTIAL_CONNECTIVITY and
@@ -3781,9 +3779,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (currentNetwork != null
&& currentNetwork.network.getNetId() == nai.network.getNetId()) {
// uid rules for this network will be removed in destroyNativeNetwork(nai).
// TODO : setting the satisfier is in fact the job of the rematch. Teach the
// rematch not to keep disconnected agents instead of setting it here ; this
// will also allow removing updating the offers below.
nri.setSatisfier(null, null);
if (request.isRequest()) {
sendUpdatedScoreToFactories(request, null);
for (final NetworkOfferInfo noi : mNetworkOffers) {
informOffer(nri, noi.offer, mNetworkRanker);
}
if (mDefaultRequest == nri) {
@@ -3939,16 +3940,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
rematchAllNetworksAndRequests();
for (final NetworkRequestInfo nri : nris) {
// If the nri is satisfied, return as its score has already been sent if needed.
if (nri.isBeingSatisfied()) {
return;
}
// As this request was not satisfied on rematch and thus never had any scores sent to
// the factories, send null now for each request of type REQUEST.
for (final NetworkRequest req : nri.mRequests) {
if (req.isRequest()) sendUpdatedScoreToFactories(req, null);
// Requests that have not been matched to a network will not have been sent to the
// providers, because the old satisfier and the new satisfier are the same (null in this
// case). Send these requests to the providers.
for (final NetworkRequestInfo nri : nris) {
for (final NetworkOfferInfo noi : mNetworkOffers) {
informOffer(nri, noi.offer, mNetworkRanker);
}
}
}
@@ -4156,7 +4154,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
cancelNpiRequests(nri);
// For all outstanding offers, cancel any of the layers of this NRI that used to be
// needed for this offer.
for (final NetworkOfferInfo noi : mNetworkOffers) {
for (final NetworkRequest req : nri.mRequests) {
if (req.isRequest() && noi.offer.neededFor(req)) {
noi.offer.onNetworkUnneeded(req);
}
}
}
}
private void handleRemoveNetworkRequests(@NonNull final Set<NetworkRequestInfo> nris) {
@@ -4169,20 +4175,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
private void cancelNpiRequests(@NonNull final NetworkRequestInfo nri) {
for (final NetworkRequest req : nri.mRequests) {
cancelNpiRequest(req);
}
}
private void cancelNpiRequest(@NonNull final NetworkRequest req) {
if (req.isRequest()) {
for (final NetworkProviderInfo npi : mNetworkProviderInfos.values()) {
npi.cancelRequest(req);
}
}
}
private void removeListenRequestFromNetworks(@NonNull final NetworkRequest req) {
// listens don't have a singular affected Network. Check all networks to see
// if this listen request applies and remove it.
@@ -4309,7 +4301,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
nai.networkAgentConfig.acceptPartialConnectivity = accept;
nai.updateScoreForNetworkAgentConfigUpdate();
rematchAllNetworksAndRequests();
sendUpdatedScoreToFactories(nai);
}
if (always) {
@@ -4377,7 +4368,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (!nai.avoidUnvalidated) {
nai.avoidUnvalidated = true;
rematchAllNetworksAndRequests();
sendUpdatedScoreToFactories(nai);
}
}
@@ -4482,14 +4472,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
return avoidBadWifi();
}
// TODO : this function is now useless.
private void rematchForAvoidBadWifiUpdate() {
rematchAllNetworksAndRequests();
for (NetworkAgentInfo nai: mNetworkAgentInfos) {
if (nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
sendUpdatedScoreToFactories(nai);
}
}
}
// TODO: Evaluate whether this is of interest to other consumers of
@@ -5514,24 +5499,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
void sendMessageToNetworkProvider(int what, int arg1, int arg2, Object obj) {
try {
messenger.send(Message.obtain(null /* handler */, what, arg1, arg2, obj));
} catch (RemoteException e) {
// Remote process died. Ignore; the death recipient will remove this
// NetworkProviderInfo from mNetworkProviderInfos.
}
}
void requestNetwork(NetworkRequest request, int score, int servingProviderId) {
sendMessageToNetworkProvider(NetworkProvider.CMD_REQUEST_NETWORK, score,
servingProviderId, request);
}
void cancelRequest(NetworkRequest request) {
sendMessageToNetworkProvider(NetworkProvider.CMD_CANCEL_REQUEST, 0, 0, request);
}
void connect(Context context, Handler handler) {
try {
messenger.getBinder().linkToDeath(mDeathRecipient, 0);
@@ -6240,7 +6207,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (DBG) log("Got NetworkProvider Messenger for " + npi.name);
mNetworkProviderInfos.put(npi.messenger, npi);
npi.connect(mContext, mTrackerHandler);
sendAllRequestsToProvider(npi);
}
@Override
@@ -6263,6 +6229,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
public void offerNetwork(final int providerId,
@NonNull final NetworkScore score, @NonNull final NetworkCapabilities caps,
@NonNull final INetworkOfferCallback callback) {
Objects.requireNonNull(score);
Objects.requireNonNull(caps);
Objects.requireNonNull(callback);
final NetworkOffer offer = new NetworkOffer(
FullScore.makeProspectiveScore(score, caps), caps, callback, providerId);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_OFFER, offer));
@@ -6287,7 +6256,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
toRemove.add(noi);
}
}
for (NetworkOfferInfo noi : toRemove) {
for (final NetworkOfferInfo noi : toRemove) {
handleUnregisterNetworkOffer(noi);
}
if (DBG) log("unregisterNetworkProvider for " + npi.name);
@@ -6707,7 +6676,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
return;
}
mNetworkOffers.add(noi);
// TODO : send requests to the provider.
issueNetworkNeeds(noi);
}
private void handleUnregisterNetworkOffer(@NonNull final NetworkOfferInfo noi) {
@@ -7482,100 +7451,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
updateLinkProperties(nai, newLp, new LinkProperties(nai.linkProperties));
}
private void sendUpdatedScoreToFactories(NetworkAgentInfo nai) {
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
// Don't send listening or track default request to factories. b/17393458
if (!nr.isRequest()) continue;
sendUpdatedScoreToFactories(nr, nai);
}
}
private void sendUpdatedScoreToFactories(
@NonNull final NetworkReassignment.RequestReassignment event) {
// If a request of type REQUEST is now being satisfied by a new network.
if (null != event.mNewNetworkRequest && event.mNewNetworkRequest.isRequest()) {
sendUpdatedScoreToFactories(event.mNewNetworkRequest, event.mNewNetwork);
}
// If a previously satisfied request of type REQUEST is no longer being satisfied.
if (null != event.mOldNetworkRequest && event.mOldNetworkRequest.isRequest()
&& event.mOldNetworkRequest != event.mNewNetworkRequest) {
sendUpdatedScoreToFactories(event.mOldNetworkRequest, null);
}
cancelMultilayerLowerPriorityNpiRequests(event.mNetworkRequestInfo);
}
/**
* Cancel with all NPIs the given NRI's multilayer requests that are a lower priority than
* its currently satisfied active request.
* @param nri the NRI to cancel lower priority requests for.
*/
private void cancelMultilayerLowerPriorityNpiRequests(
@NonNull final NetworkRequestInfo nri) {
if (!nri.isMultilayerRequest() || null == nri.mActiveRequest) {
return;
}
final int indexOfNewRequest = nri.mRequests.indexOf(nri.mActiveRequest);
for (int i = indexOfNewRequest + 1; i < nri.mRequests.size(); i++) {
cancelNpiRequest(nri.mRequests.get(i));
}
}
private void sendUpdatedScoreToFactories(@NonNull NetworkRequest networkRequest,
@Nullable NetworkAgentInfo nai) {
final int score;
final int serial;
if (nai != null) {
score = nai.getCurrentScore();
serial = nai.factorySerialNumber;
} else {
score = 0;
serial = 0;
}
if (VDBG || DDBG){
log("sending new Min Network Score(" + score + "): " + networkRequest.toString());
}
for (NetworkProviderInfo npi : mNetworkProviderInfos.values()) {
npi.requestNetwork(networkRequest, score, serial);
}
}
/** Sends all current NetworkRequests to the specified factory. */
private void sendAllRequestsToProvider(@NonNull final NetworkProviderInfo npi) {
ensureRunningOnConnectivityServiceThread();
for (final NetworkRequestInfo nri : getNrisFromGlobalRequests()) {
for (final NetworkRequest req : nri.mRequests) {
if (!req.isRequest() && nri.getActiveRequest() == req) {
break;
}
if (!req.isRequest()) {
continue;
}
// Only set the nai for the request it is satisfying.
final NetworkAgentInfo nai =
nri.getActiveRequest() == req ? nri.getSatisfier() : null;
final int score;
final int serial;
if (null != nai) {
score = nai.getCurrentScore();
serial = nai.factorySerialNumber;
} else {
score = 0;
serial = NetworkProvider.ID_NONE;
}
npi.requestNetwork(req, score, serial);
// For multilayer requests, don't send lower priority requests if a higher priority
// request is already satisfied.
if (null != nai) {
break;
}
}
}
}
private void sendPendingIntentForRequest(NetworkRequestInfo nri, NetworkAgentInfo networkAgent,
int notificationType) {
if (notificationType == ConnectivityManager.CALLBACK_AVAILABLE && !nri.mPendingIntentSent) {
@@ -8067,6 +7942,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
log(changes.toString()); // Shorter form, only one line of log
}
applyNetworkReassignment(changes, now);
issueNetworkNeeds();
}
private void applyNetworkReassignment(@NonNull final NetworkReassignment changes,
@@ -8098,12 +7974,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
// before LegacyTypeTracker sends legacy broadcasts
for (final NetworkReassignment.RequestReassignment event :
changes.getRequestReassignments()) {
// Tell NetworkProviders about the new score, so they can stop
// trying to connect if they know they cannot match it.
// TODO - this could get expensive if there are a lot of outstanding requests for this
// network. Think of a way to reduce this. Push netid->request mapping to each factory?
sendUpdatedScoreToFactories(event);
if (null != event.mNewNetwork) {
notifyNetworkAvailable(event.mNewNetwork, event.mNetworkRequestInfo);
} else {
@@ -8240,6 +8110,107 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
private void issueNetworkNeeds() {
ensureRunningOnConnectivityServiceThread();
for (final NetworkOfferInfo noi : mNetworkOffers) {
issueNetworkNeeds(noi);
}
}
private void issueNetworkNeeds(@NonNull final NetworkOfferInfo noi) {
ensureRunningOnConnectivityServiceThread();
for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
informOffer(nri, noi.offer, mNetworkRanker);
}
}
/**
* Inform a NetworkOffer about any new situation of a request.
*
* This function handles updates to offers. A number of events may happen that require
* updating the registrant for this offer about the situation :
* • The offer itself was updated. This may lead the offer to no longer being able
* to satisfy a request or beat a satisfier (and therefore be no longer needed),
* or conversely being strengthened enough to beat the satisfier (and therefore
* start being needed)
* • The network satisfying a request changed (including cases where the request
* starts or stops being satisfied). The new network may be a stronger or weaker
* match than the old one, possibly affecting whether the offer is needed.
* • The network satisfying a request updated their score. This may lead the offer
* to no longer be able to beat it if the current satisfier got better, or
* conversely start being a good choice if the current satisfier got weaker.
*
* @param nri The request
* @param offer The offer. This may be an updated offer.
*/
private static void informOffer(@NonNull NetworkRequestInfo nri,
@NonNull final NetworkOffer offer, @NonNull final NetworkRanker networkRanker) {
final NetworkRequest activeRequest = nri.isBeingSatisfied() ? nri.getActiveRequest() : null;
final NetworkAgentInfo satisfier = null != activeRequest ? nri.getSatisfier() : null;
final FullScore satisfierScore = null != satisfier ? satisfier.getScore() : null;
// Multi-layer requests have a currently active request, the one being satisfied.
// Since the system will try to bring up a better network than is currently satisfying
// the request, NetworkProviders need to be told the offers matching the requests *above*
// the currently satisfied one are needed, that the ones *below* the satisfied one are
// not needed, and the offer is needed for the active request iff the offer can beat
// the satisfier.
// For non-multilayer requests, the logic above gracefully degenerates to only the
// last case.
// To achieve this, the loop below will proceed in three steps. In a first phase, inform
// providers that the offer is needed for this request, until the active request is found.
// In a second phase, deal with the currently active request. In a third phase, inform
// the providers that offer is unneeded for the remaining requests.
// First phase : inform providers of all requests above the active request.
int i;
for (i = 0; nri.mRequests.size() > i; ++i) {
final NetworkRequest request = nri.mRequests.get(i);
if (activeRequest == request) break; // Found the active request : go to phase 2
if (!request.isRequest()) continue; // Listens/track defaults are never sent to offers
// Since this request is higher-priority than the one currently satisfied, if the
// offer can satisfy it, the provider should try and bring up the network for sure ;
// no need to even ask the ranker an offer that can satisfy is always better than
// no network. Hence tell the provider so unless it already knew.
if (request.canBeSatisfiedBy(offer.caps) && !offer.neededFor(request)) {
offer.onNetworkNeeded(request);
}
}
// Second phase : deal with the active request (if any)
if (null != activeRequest && activeRequest.isRequest()) {
final boolean oldNeeded = offer.neededFor(activeRequest);
// An offer is needed if it is currently served by this provider or if this offer
// can beat the current satisfier.
final boolean currentlyServing = satisfier != null
&& satisfier.factorySerialNumber == offer.providerId;
final boolean newNeeded = (currentlyServing
|| (activeRequest.canBeSatisfiedBy(offer.caps)
&& networkRanker.mightBeat(activeRequest, satisfierScore, offer)));
if (newNeeded != oldNeeded) {
if (newNeeded) {
offer.onNetworkNeeded(activeRequest);
} else {
// The offer used to be able to beat the satisfier. Now it can't.
offer.onNetworkUnneeded(activeRequest);
}
}
}
// Third phase : inform the providers that the offer isn't needed for any request
// below the active one.
for (++i /* skip the active request */; nri.mRequests.size() > i; ++i) {
final NetworkRequest request = nri.mRequests.get(i);
if (!request.isRequest()) continue; // Listens/track defaults are never sent to offers
// Since this request is lower-priority than the one currently satisfied, if the
// offer can satisfy it, the provider should not try and bring up the network.
// Hence tell the provider so unless it already knew.
if (offer.neededFor(request)) {
offer.onNetworkUnneeded(request);
}
}
}
private void addNetworkToLegacyTypeTracker(@NonNull final NetworkAgentInfo nai) {
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
@@ -8405,7 +8376,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (VDBG || DDBG) log("updateNetworkScore for " + nai.toShortString() + " to " + score);
nai.setScore(score);
rematchAllNetworksAndRequests();
sendUpdatedScoreToFactories(nai);
}
// Notify only this one new request of the current state. Transfer all the