[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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user