[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:
@@ -316,9 +316,16 @@ package android.net {
|
|||||||
method public int getProviderId();
|
method public int getProviderId();
|
||||||
method public void onNetworkRequestWithdrawn(@NonNull android.net.NetworkRequest);
|
method public void onNetworkRequestWithdrawn(@NonNull android.net.NetworkRequest);
|
||||||
method public void onNetworkRequested(@NonNull android.net.NetworkRequest, @IntRange(from=0, to=99) int, int);
|
method public void onNetworkRequested(@NonNull android.net.NetworkRequest, @IntRange(from=0, to=99) int, int);
|
||||||
|
method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void registerNetworkOffer(@NonNull android.net.NetworkScore, @NonNull android.net.NetworkCapabilities, @NonNull java.util.concurrent.Executor, @NonNull android.net.NetworkProvider.NetworkOfferCallback);
|
||||||
|
method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void unregisterNetworkOffer(@NonNull android.net.NetworkProvider.NetworkOfferCallback);
|
||||||
field public static final int ID_NONE = -1; // 0xffffffff
|
field public static final int ID_NONE = -1; // 0xffffffff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static interface NetworkProvider.NetworkOfferCallback {
|
||||||
|
method public void onNetworkNeeded(@NonNull android.net.NetworkRequest);
|
||||||
|
method public void onNetworkUnneeded(@NonNull android.net.NetworkRequest);
|
||||||
|
}
|
||||||
|
|
||||||
public class NetworkReleasedException extends java.lang.Exception {
|
public class NetworkReleasedException extends java.lang.Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3360,7 +3360,7 @@ public class ConnectivityManager {
|
|||||||
* @param score The prospective score of the network.
|
* @param score The prospective score of the network.
|
||||||
* @param caps The prospective capabilities of the network.
|
* @param caps The prospective capabilities of the network.
|
||||||
* @param callback The callback to call when this offer is needed or unneeded.
|
* @param callback The callback to call when this offer is needed or unneeded.
|
||||||
* @hide
|
* @hide exposed via the NetworkProvider class.
|
||||||
*/
|
*/
|
||||||
@RequiresPermission(anyOf = {
|
@RequiresPermission(anyOf = {
|
||||||
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
|
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
|
||||||
@@ -3383,7 +3383,7 @@ public class ConnectivityManager {
|
|||||||
*
|
*
|
||||||
* @param callback The callback passed at registration time. This must be the same object
|
* @param callback The callback passed at registration time. This must be the same object
|
||||||
* that was passed to {@link #offerNetwork}
|
* that was passed to {@link #offerNetwork}
|
||||||
* @hide
|
* @hide exposed via the NetworkProvider class.
|
||||||
*/
|
*/
|
||||||
public void unofferNetwork(@NonNull final INetworkOfferCallback callback) {
|
public void unofferNetwork(@NonNull final INetworkOfferCallback callback) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -51,10 +51,8 @@ oneway interface INetworkOfferCallback {
|
|||||||
/**
|
/**
|
||||||
* Called when a network for this offer is needed to fulfill this request.
|
* Called when a network for this offer is needed to fulfill this request.
|
||||||
* @param networkRequest the request to satisfy
|
* @param networkRequest the request to satisfy
|
||||||
* @param providerId the ID of the provider currently satisfying
|
|
||||||
* this request, or NetworkProvider.ID_NONE if none.
|
|
||||||
*/
|
*/
|
||||||
void onNetworkNeeded(in NetworkRequest networkRequest, int providerId);
|
void onNetworkNeeded(in NetworkRequest networkRequest);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Informs the registrant that the offer is no longer valuable to fulfill this request.
|
* Informs the registrant that the offer is no longer valuable to fulfill this request.
|
||||||
|
|||||||
@@ -168,12 +168,16 @@ public class NetworkProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
// TODO : make @SystemApi when the impl is complete
|
@SystemApi
|
||||||
public interface NetworkOfferCallback {
|
public interface NetworkOfferCallback {
|
||||||
/** Called by the system when a network for this offer is needed to satisfy some
|
/**
|
||||||
* networking request. */
|
* Called by the system when a network for this offer is needed to satisfy some
|
||||||
void onNetworkNeeded(@NonNull NetworkRequest request, int providerId);
|
* networking request.
|
||||||
/** Called by the system when this offer is no longer valuable for this request. */
|
*/
|
||||||
|
void onNetworkNeeded(@NonNull NetworkRequest request);
|
||||||
|
/**
|
||||||
|
* Called by the system when this offer is no longer valuable for this request.
|
||||||
|
*/
|
||||||
void onNetworkUnneeded(@NonNull NetworkRequest request);
|
void onNetworkUnneeded(@NonNull NetworkRequest request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,9 +192,8 @@ public class NetworkProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNetworkNeeded(final @NonNull NetworkRequest request,
|
public void onNetworkNeeded(final @NonNull NetworkRequest request) {
|
||||||
final int providerId) {
|
mExecutor.execute(() -> callback.onNetworkNeeded(request));
|
||||||
mExecutor.execute(() -> callback.onNetworkNeeded(request, providerId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -254,8 +257,11 @@ public class NetworkProvider {
|
|||||||
*
|
*
|
||||||
* The capabilities and score act as filters as to what requests the provider will see.
|
* The capabilities and score act as filters as to what requests the provider will see.
|
||||||
* They are not promises, but for best performance, the providers should strive to put
|
* They are not promises, but for best performance, the providers should strive to put
|
||||||
* as much known information as possible in the offer. For capabilities in particular, it
|
* as much known information as possible in the offer. For the score, it should put as
|
||||||
* should put all NetworkAgent-managed capabilities a network may have, even if it doesn't
|
* strong a score as the networks will have, since this will filter what requests the
|
||||||
|
* provider sees – it's not a promise, it only serves to avoid sending requests that
|
||||||
|
* the provider can't ever hope to satisfy better than any current network. For capabilities,
|
||||||
|
* it should put all NetworkAgent-managed capabilities a network may have, even if it doesn't
|
||||||
* have them at first. This applies to INTERNET, for example ; if a provider thinks the
|
* have them at first. This applies to INTERNET, for example ; if a provider thinks the
|
||||||
* network it can bring up for this offer may offer Internet access it should include the
|
* network it can bring up for this offer may offer Internet access it should include the
|
||||||
* INTERNET bit. It's fine if the brought up network ends up not actually having INTERNET.
|
* INTERNET bit. It's fine if the brought up network ends up not actually having INTERNET.
|
||||||
@@ -268,9 +274,9 @@ public class NetworkProvider {
|
|||||||
*
|
*
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
// TODO : make @SystemApi when the impl is complete
|
@SystemApi
|
||||||
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
|
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
|
||||||
public void offerNetwork(@NonNull final NetworkScore score,
|
public void registerNetworkOffer(@NonNull final NetworkScore score,
|
||||||
@NonNull final NetworkCapabilities caps, @NonNull final Executor executor,
|
@NonNull final NetworkCapabilities caps, @NonNull final Executor executor,
|
||||||
@NonNull final NetworkOfferCallback callback) {
|
@NonNull final NetworkOfferCallback callback) {
|
||||||
// Can't offer a network with a provider that is not yet registered or already unregistered.
|
// Can't offer a network with a provider that is not yet registered or already unregistered.
|
||||||
@@ -307,9 +313,9 @@ public class NetworkProvider {
|
|||||||
*
|
*
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
// TODO : make @SystemApi when the impl is complete
|
@SystemApi
|
||||||
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
|
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
|
||||||
public void unofferNetwork(final @NonNull NetworkOfferCallback callback) {
|
public void unregisterNetworkOffer(final @NonNull NetworkOfferCallback callback) {
|
||||||
final NetworkOfferCallbackProxy proxy = findProxyForCallback(callback);
|
final NetworkOfferCallbackProxy proxy = findProxyForCallback(callback);
|
||||||
if (null == proxy) return;
|
if (null == proxy) return;
|
||||||
mProxies.remove(proxy);
|
mProxies.remove(proxy);
|
||||||
|
|||||||
@@ -3359,8 +3359,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
nai.lastValidated = valid;
|
nai.lastValidated = valid;
|
||||||
nai.everValidated |= valid;
|
nai.everValidated |= valid;
|
||||||
updateCapabilities(oldScore, nai, nai.networkCapabilities);
|
updateCapabilities(oldScore, nai, nai.networkCapabilities);
|
||||||
// If score has changed, rebroadcast to NetworkProviders. b/17726566
|
|
||||||
if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
|
|
||||||
if (valid) {
|
if (valid) {
|
||||||
handleFreshlyValidatedNetwork(nai);
|
handleFreshlyValidatedNetwork(nai);
|
||||||
// Clear NO_INTERNET, PRIVATE_DNS_BROKEN, PARTIAL_CONNECTIVITY and
|
// Clear NO_INTERNET, PRIVATE_DNS_BROKEN, PARTIAL_CONNECTIVITY and
|
||||||
@@ -3781,9 +3779,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
if (currentNetwork != null
|
if (currentNetwork != null
|
||||||
&& currentNetwork.network.getNetId() == nai.network.getNetId()) {
|
&& currentNetwork.network.getNetId() == nai.network.getNetId()) {
|
||||||
// uid rules for this network will be removed in destroyNativeNetwork(nai).
|
// 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);
|
nri.setSatisfier(null, null);
|
||||||
if (request.isRequest()) {
|
for (final NetworkOfferInfo noi : mNetworkOffers) {
|
||||||
sendUpdatedScoreToFactories(request, null);
|
informOffer(nri, noi.offer, mNetworkRanker);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mDefaultRequest == nri) {
|
if (mDefaultRequest == nri) {
|
||||||
@@ -3939,16 +3940,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
rematchAllNetworksAndRequests();
|
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
|
// Requests that have not been matched to a network will not have been sent to the
|
||||||
// the factories, send null now for each request of type REQUEST.
|
// providers, because the old satisfier and the new satisfier are the same (null in this
|
||||||
for (final NetworkRequest req : nri.mRequests) {
|
// case). Send these requests to the providers.
|
||||||
if (req.isRequest()) sendUpdatedScoreToFactories(req, null);
|
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) {
|
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) {
|
private void removeListenRequestFromNetworks(@NonNull final NetworkRequest req) {
|
||||||
// listens don't have a singular affected Network. Check all networks to see
|
// listens don't have a singular affected Network. Check all networks to see
|
||||||
// if this listen request applies and remove it.
|
// if this listen request applies and remove it.
|
||||||
@@ -4309,7 +4301,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
nai.networkAgentConfig.acceptPartialConnectivity = accept;
|
nai.networkAgentConfig.acceptPartialConnectivity = accept;
|
||||||
nai.updateScoreForNetworkAgentConfigUpdate();
|
nai.updateScoreForNetworkAgentConfigUpdate();
|
||||||
rematchAllNetworksAndRequests();
|
rematchAllNetworksAndRequests();
|
||||||
sendUpdatedScoreToFactories(nai);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (always) {
|
if (always) {
|
||||||
@@ -4377,7 +4368,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
if (!nai.avoidUnvalidated) {
|
if (!nai.avoidUnvalidated) {
|
||||||
nai.avoidUnvalidated = true;
|
nai.avoidUnvalidated = true;
|
||||||
rematchAllNetworksAndRequests();
|
rematchAllNetworksAndRequests();
|
||||||
sendUpdatedScoreToFactories(nai);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4482,14 +4472,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
return avoidBadWifi();
|
return avoidBadWifi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO : this function is now useless.
|
||||||
private void rematchForAvoidBadWifiUpdate() {
|
private void rematchForAvoidBadWifiUpdate() {
|
||||||
rematchAllNetworksAndRequests();
|
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
|
// 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) {
|
void connect(Context context, Handler handler) {
|
||||||
try {
|
try {
|
||||||
messenger.getBinder().linkToDeath(mDeathRecipient, 0);
|
messenger.getBinder().linkToDeath(mDeathRecipient, 0);
|
||||||
@@ -6240,7 +6207,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
if (DBG) log("Got NetworkProvider Messenger for " + npi.name);
|
if (DBG) log("Got NetworkProvider Messenger for " + npi.name);
|
||||||
mNetworkProviderInfos.put(npi.messenger, npi);
|
mNetworkProviderInfos.put(npi.messenger, npi);
|
||||||
npi.connect(mContext, mTrackerHandler);
|
npi.connect(mContext, mTrackerHandler);
|
||||||
sendAllRequestsToProvider(npi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -6263,6 +6229,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
public void offerNetwork(final int providerId,
|
public void offerNetwork(final int providerId,
|
||||||
@NonNull final NetworkScore score, @NonNull final NetworkCapabilities caps,
|
@NonNull final NetworkScore score, @NonNull final NetworkCapabilities caps,
|
||||||
@NonNull final INetworkOfferCallback callback) {
|
@NonNull final INetworkOfferCallback callback) {
|
||||||
|
Objects.requireNonNull(score);
|
||||||
|
Objects.requireNonNull(caps);
|
||||||
|
Objects.requireNonNull(callback);
|
||||||
final NetworkOffer offer = new NetworkOffer(
|
final NetworkOffer offer = new NetworkOffer(
|
||||||
FullScore.makeProspectiveScore(score, caps), caps, callback, providerId);
|
FullScore.makeProspectiveScore(score, caps), caps, callback, providerId);
|
||||||
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_OFFER, offer));
|
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_OFFER, offer));
|
||||||
@@ -6287,7 +6256,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
toRemove.add(noi);
|
toRemove.add(noi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (NetworkOfferInfo noi : toRemove) {
|
for (final NetworkOfferInfo noi : toRemove) {
|
||||||
handleUnregisterNetworkOffer(noi);
|
handleUnregisterNetworkOffer(noi);
|
||||||
}
|
}
|
||||||
if (DBG) log("unregisterNetworkProvider for " + npi.name);
|
if (DBG) log("unregisterNetworkProvider for " + npi.name);
|
||||||
@@ -6707,7 +6676,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mNetworkOffers.add(noi);
|
mNetworkOffers.add(noi);
|
||||||
// TODO : send requests to the provider.
|
issueNetworkNeeds(noi);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleUnregisterNetworkOffer(@NonNull final NetworkOfferInfo 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));
|
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,
|
private void sendPendingIntentForRequest(NetworkRequestInfo nri, NetworkAgentInfo networkAgent,
|
||||||
int notificationType) {
|
int notificationType) {
|
||||||
if (notificationType == ConnectivityManager.CALLBACK_AVAILABLE && !nri.mPendingIntentSent) {
|
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
|
log(changes.toString()); // Shorter form, only one line of log
|
||||||
}
|
}
|
||||||
applyNetworkReassignment(changes, now);
|
applyNetworkReassignment(changes, now);
|
||||||
|
issueNetworkNeeds();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyNetworkReassignment(@NonNull final NetworkReassignment changes,
|
private void applyNetworkReassignment(@NonNull final NetworkReassignment changes,
|
||||||
@@ -8098,12 +7974,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// before LegacyTypeTracker sends legacy broadcasts
|
// before LegacyTypeTracker sends legacy broadcasts
|
||||||
for (final NetworkReassignment.RequestReassignment event :
|
for (final NetworkReassignment.RequestReassignment event :
|
||||||
changes.getRequestReassignments()) {
|
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) {
|
if (null != event.mNewNetwork) {
|
||||||
notifyNetworkAvailable(event.mNewNetwork, event.mNetworkRequestInfo);
|
notifyNetworkAvailable(event.mNewNetwork, event.mNetworkRequestInfo);
|
||||||
} else {
|
} 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) {
|
private void addNetworkToLegacyTypeTracker(@NonNull final NetworkAgentInfo nai) {
|
||||||
for (int i = 0; i < nai.numNetworkRequests(); i++) {
|
for (int i = 0; i < nai.numNetworkRequests(); i++) {
|
||||||
NetworkRequest nr = nai.requestAt(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);
|
if (VDBG || DDBG) log("updateNetworkScore for " + nai.toShortString() + " to " + score);
|
||||||
nai.setScore(score);
|
nai.setScore(score);
|
||||||
rematchAllNetworksAndRequests();
|
rematchAllNetworksAndRequests();
|
||||||
sendUpdatedScoreToFactories(nai);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify only this one new request of the current state. Transfer all the
|
// Notify only this one new request of the current state. Transfer all the
|
||||||
|
|||||||
@@ -893,6 +893,10 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
|||||||
return isWifi && !avoidBadWifi && everValidated;
|
return isWifi && !avoidBadWifi && everValidated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FullScore getScore() {
|
||||||
|
return mScore;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the current score for this Network. This may be modified from what the
|
// Get the current score for this Network. This may be modified from what the
|
||||||
// NetworkAgent sent, as it has modifiers applied to it.
|
// NetworkAgent sent, as it has modifiers applied to it.
|
||||||
public int getCurrentScore() {
|
public int getCurrentScore() {
|
||||||
|
|||||||
@@ -17,13 +17,14 @@
|
|||||||
package com.android.server.connectivity;
|
package com.android.server.connectivity;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
|
||||||
import android.net.INetworkOfferCallback;
|
import android.net.INetworkOfferCallback;
|
||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an offer made by a NetworkProvider to create a network if a need arises.
|
* Represents an offer made by a NetworkProvider to create a network if a need arises.
|
||||||
@@ -44,46 +45,86 @@ public class NetworkOffer {
|
|||||||
@NonNull public final NetworkCapabilities caps;
|
@NonNull public final NetworkCapabilities caps;
|
||||||
@NonNull public final INetworkOfferCallback callback;
|
@NonNull public final INetworkOfferCallback callback;
|
||||||
@NonNull public final int providerId;
|
@NonNull public final int providerId;
|
||||||
|
// While this could, in principle, be deduced from the old values of the satisfying networks,
|
||||||
|
// doing so would add a lot of complexity and performance penalties. For each request, the
|
||||||
|
// ranker would have to run again to figure out if this offer used to be able to beat the
|
||||||
|
// previous satisfier to know if there is a change in whether this offer is now needed ;
|
||||||
|
// besides, there would be a need to handle an edge case when a new request comes online,
|
||||||
|
// where it's not satisfied before the first rematch, where starting to satisfy a request
|
||||||
|
// should not result in sending unneeded to this offer. This boolean, while requiring that
|
||||||
|
// the offers are only ever manipulated on the CS thread, is by far a simpler and
|
||||||
|
// economical solution.
|
||||||
|
private final Set<NetworkRequest> mCurrentlyNeeded = new HashSet<>();
|
||||||
|
|
||||||
private static NetworkCapabilities emptyCaps() {
|
|
||||||
final NetworkCapabilities nc = new NetworkCapabilities();
|
|
||||||
return nc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ideally the caps argument would be non-null, but null has historically meant no filter
|
|
||||||
// and telephony passes null. Keep backward compatibility.
|
|
||||||
public NetworkOffer(@NonNull final FullScore score,
|
public NetworkOffer(@NonNull final FullScore score,
|
||||||
@Nullable final NetworkCapabilities caps,
|
@NonNull final NetworkCapabilities caps,
|
||||||
@NonNull final INetworkOfferCallback callback,
|
@NonNull final INetworkOfferCallback callback,
|
||||||
@NonNull final int providerId) {
|
@NonNull final int providerId) {
|
||||||
this.score = Objects.requireNonNull(score);
|
this.score = Objects.requireNonNull(score);
|
||||||
this.caps = null != caps ? caps : emptyCaps();
|
this.caps = Objects.requireNonNull(caps);
|
||||||
this.callback = Objects.requireNonNull(callback);
|
this.callback = Objects.requireNonNull(callback);
|
||||||
this.providerId = providerId;
|
this.providerId = providerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the provider for this offer that the network is needed for a request.
|
||||||
|
* @param request the request for which the offer is needed
|
||||||
|
*/
|
||||||
|
public void onNetworkNeeded(@NonNull final NetworkRequest request) {
|
||||||
|
if (mCurrentlyNeeded.contains(request)) {
|
||||||
|
throw new IllegalStateException("Network already needed");
|
||||||
|
}
|
||||||
|
mCurrentlyNeeded.add(request);
|
||||||
|
try {
|
||||||
|
callback.onNetworkNeeded(request);
|
||||||
|
} catch (final RemoteException e) {
|
||||||
|
// The provider is dead. It will be removed by the death recipient.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the provider for this offer that the network is no longer needed for this request.
|
||||||
|
*
|
||||||
|
* onNetworkNeeded will have been called with the same request before.
|
||||||
|
*
|
||||||
|
* @param request the request
|
||||||
|
*/
|
||||||
|
public void onNetworkUnneeded(@NonNull final NetworkRequest request) {
|
||||||
|
if (!mCurrentlyNeeded.contains(request)) {
|
||||||
|
throw new IllegalStateException("Network already unneeded");
|
||||||
|
}
|
||||||
|
mCurrentlyNeeded.remove(request);
|
||||||
|
try {
|
||||||
|
callback.onNetworkUnneeded(request);
|
||||||
|
} catch (final RemoteException e) {
|
||||||
|
// The provider is dead. It will be removed by the death recipient.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this offer is currently needed for this request.
|
||||||
|
* @param request the request
|
||||||
|
* @return whether the offer is currently considered needed
|
||||||
|
*/
|
||||||
|
public boolean neededFor(@NonNull final NetworkRequest request) {
|
||||||
|
return mCurrentlyNeeded.contains(request);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Migrate from, and take over, a previous offer.
|
* Migrate from, and take over, a previous offer.
|
||||||
*
|
*
|
||||||
* When an updated offer is sent from a provider, call this method on the new offer, passing
|
* When an updated offer is sent from a provider, call this method on the new offer, passing
|
||||||
* the old one, to take over the state.
|
* the old one, to take over the state.
|
||||||
*
|
*
|
||||||
* @param previousOffer
|
* @param previousOffer the previous offer
|
||||||
*/
|
*/
|
||||||
public void migrateFrom(@NonNull final NetworkOffer previousOffer) {
|
public void migrateFrom(@NonNull final NetworkOffer previousOffer) {
|
||||||
if (!callback.equals(previousOffer.callback)) {
|
if (!callback.equals(previousOffer.callback)) {
|
||||||
throw new IllegalArgumentException("Can only migrate from a previous version of"
|
throw new IllegalArgumentException("Can only migrate from a previous version of"
|
||||||
+ " the same offer");
|
+ " the same offer");
|
||||||
}
|
}
|
||||||
}
|
mCurrentlyNeeded.clear();
|
||||||
|
mCurrentlyNeeded.addAll(previousOffer.mCurrentlyNeeded);
|
||||||
/**
|
|
||||||
* Returns whether an offer can satisfy a NetworkRequest, according to its capabilities.
|
|
||||||
* @param request The request to test against.
|
|
||||||
* @return Whether this offer can satisfy the request.
|
|
||||||
*/
|
|
||||||
public final boolean canSatisfy(@NonNull final NetworkRequest request) {
|
|
||||||
return request.networkCapabilities.satisfiedByNetworkCapabilities(caps);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.server.connectivity;
|
|||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
import android.net.NetworkCapabilities;
|
||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -47,4 +48,41 @@ public class NetworkRanker {
|
|||||||
}
|
}
|
||||||
return bestNetwork;
|
return bestNetwork;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether an offer has a chance to beat a champion network for a request.
|
||||||
|
*
|
||||||
|
* Offers are sent by network providers when they think they might be able to make a network
|
||||||
|
* with the characteristics contained in the offer. If the offer has no chance to beat
|
||||||
|
* the currently best network for a given request, there is no point in the provider spending
|
||||||
|
* power trying to find and bring up such a network.
|
||||||
|
*
|
||||||
|
* Note that having an offer up does not constitute a commitment from the provider part
|
||||||
|
* to be able to bring up a network with these characteristics, or a network at all for
|
||||||
|
* that matter. This is only used to save power by letting providers know when they can't
|
||||||
|
* beat a current champion.
|
||||||
|
*
|
||||||
|
* @param request The request to evaluate against.
|
||||||
|
* @param championScore The currently best network for this request.
|
||||||
|
* @param offer The offer.
|
||||||
|
* @return Whether the offer stands a chance to beat the champion.
|
||||||
|
*/
|
||||||
|
public boolean mightBeat(@NonNull final NetworkRequest request,
|
||||||
|
@Nullable final FullScore championScore,
|
||||||
|
@NonNull final NetworkOffer offer) {
|
||||||
|
// If this network can't even satisfy the request then it can't beat anything, not
|
||||||
|
// even an absence of network. It can't satisfy it anyway.
|
||||||
|
if (!request.canBeSatisfiedBy(offer.caps)) return false;
|
||||||
|
// If there is no satisfying network, then this network can beat, because some network
|
||||||
|
// is always better than no network.
|
||||||
|
if (null == championScore) return true;
|
||||||
|
final int offerIntScore;
|
||||||
|
if (offer.caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
|
||||||
|
// If the offer might have Internet access, then it might validate.
|
||||||
|
offerIntScore = offer.score.getLegacyIntAsValidated();
|
||||||
|
} else {
|
||||||
|
offerIntScore = offer.score.getLegacyInt();
|
||||||
|
}
|
||||||
|
return championScore.getLegacyInt() < offerIntScore;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,4 +198,4 @@ class NetworkProviderTest {
|
|||||||
cb.expectCallback<OnUnavailable>() { nr.getNetworkSpecifier() == specifier }
|
cb.expectCallback<OnUnavailable>() { nr.getNetworkSpecifier() == specifier }
|
||||||
mCm.unregisterNetworkProvider(provider)
|
mCm.unregisterNetworkProvider(provider)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1029,8 +1029,6 @@ public class ConnectivityServiceTest {
|
|||||||
* operations have been processed and test for them.
|
* operations have been processed and test for them.
|
||||||
*/
|
*/
|
||||||
private static class MockNetworkFactory extends NetworkFactory {
|
private static class MockNetworkFactory extends NetworkFactory {
|
||||||
private final ConditionVariable mNetworkStartedCV = new ConditionVariable();
|
|
||||||
private final ConditionVariable mNetworkStoppedCV = new ConditionVariable();
|
|
||||||
private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
|
private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
|
||||||
|
|
||||||
static class RequestEntry {
|
static class RequestEntry {
|
||||||
@@ -1042,11 +1040,8 @@ public class ConnectivityServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static final class Add extends RequestEntry {
|
static final class Add extends RequestEntry {
|
||||||
public final int factorySerialNumber;
|
Add(@NonNull final NetworkRequest request) {
|
||||||
|
|
||||||
Add(@NonNull final NetworkRequest request, final int factorySerialNumber) {
|
|
||||||
super(request);
|
super(request);
|
||||||
this.factorySerialNumber = factorySerialNumber;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1055,6 +1050,11 @@ public class ConnectivityServiceTest {
|
|||||||
super(request);
|
super(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "RequestEntry [ " + getClass().getName() + " : " + request + " ]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// History of received requests adds and removes.
|
// History of received requests adds and removes.
|
||||||
@@ -1066,7 +1066,6 @@ public class ConnectivityServiceTest {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public RequestEntry.Add expectRequestAdd() {
|
public RequestEntry.Add expectRequestAdd() {
|
||||||
return failIfNull((RequestEntry.Add) mRequestHistory.poll(TIMEOUT_MS,
|
return failIfNull((RequestEntry.Add) mRequestHistory.poll(TIMEOUT_MS,
|
||||||
it -> it instanceof RequestEntry.Add), "Expected request add");
|
it -> it instanceof RequestEntry.Add), "Expected request add");
|
||||||
@@ -1106,40 +1105,28 @@ public class ConnectivityServiceTest {
|
|||||||
|
|
||||||
protected void startNetwork() {
|
protected void startNetwork() {
|
||||||
mNetworkStarted.set(true);
|
mNetworkStarted.set(true);
|
||||||
mNetworkStartedCV.open();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void stopNetwork() {
|
protected void stopNetwork() {
|
||||||
mNetworkStarted.set(false);
|
mNetworkStarted.set(false);
|
||||||
mNetworkStoppedCV.open();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getMyStartRequested() {
|
public boolean getMyStartRequested() {
|
||||||
return mNetworkStarted.get();
|
return mNetworkStarted.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConditionVariable getNetworkStartedCV() {
|
|
||||||
mNetworkStartedCV.close();
|
|
||||||
return mNetworkStartedCV;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConditionVariable getNetworkStoppedCV() {
|
|
||||||
mNetworkStoppedCV.close();
|
|
||||||
return mNetworkStoppedCV;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleAddRequest(NetworkRequest request, int score,
|
protected void needNetworkFor(NetworkRequest request) {
|
||||||
int factorySerialNumber) {
|
|
||||||
mNetworkRequests.put(request.requestId, request);
|
mNetworkRequests.put(request.requestId, request);
|
||||||
super.handleAddRequest(request, score, factorySerialNumber);
|
super.needNetworkFor(request);
|
||||||
mRequestHistory.add(new RequestEntry.Add(request, factorySerialNumber));
|
mRequestHistory.add(new RequestEntry.Add(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleRemoveRequest(NetworkRequest request) {
|
protected void releaseNetworkFor(NetworkRequest request) {
|
||||||
mNetworkRequests.remove(request.requestId);
|
mNetworkRequests.remove(request.requestId);
|
||||||
super.handleRemoveRequest(request);
|
super.releaseNetworkFor(request);
|
||||||
mRequestHistory.add(new RequestEntry.Remove(request));
|
mRequestHistory.add(new RequestEntry.Remove(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3095,25 +3082,23 @@ public class ConnectivityServiceTest {
|
|||||||
handlerThread.start();
|
handlerThread.start();
|
||||||
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
|
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
|
||||||
mServiceContext, "testFactory", filter, mCsHandlerThread);
|
mServiceContext, "testFactory", filter, mCsHandlerThread);
|
||||||
testFactory.setScoreFilter(40);
|
testFactory.setScoreFilter(45);
|
||||||
ConditionVariable cv = testFactory.getNetworkStartedCV();
|
|
||||||
testFactory.register();
|
testFactory.register();
|
||||||
testFactory.expectRequestAdd();
|
|
||||||
testFactory.assertRequestCountEquals(1);
|
final NetworkCallback networkCallback;
|
||||||
int expectedRequestCount = 1;
|
|
||||||
NetworkCallback networkCallback = null;
|
|
||||||
// For non-INTERNET capabilities we cannot rely on the default request being present, so
|
|
||||||
// add one.
|
|
||||||
if (capability != NET_CAPABILITY_INTERNET) {
|
if (capability != NET_CAPABILITY_INTERNET) {
|
||||||
|
// If the capability passed in argument is part of the default request, then the
|
||||||
|
// factory will see the default request. Otherwise the filter will prevent the
|
||||||
|
// factory from seeing it. In that case, add a request so it can be tested.
|
||||||
assertFalse(testFactory.getMyStartRequested());
|
assertFalse(testFactory.getMyStartRequested());
|
||||||
NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build();
|
NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build();
|
||||||
networkCallback = new NetworkCallback();
|
networkCallback = new NetworkCallback();
|
||||||
mCm.requestNetwork(request, networkCallback);
|
mCm.requestNetwork(request, networkCallback);
|
||||||
expectedRequestCount++;
|
} else {
|
||||||
testFactory.expectRequestAdd();
|
networkCallback = null;
|
||||||
}
|
}
|
||||||
waitFor(cv);
|
testFactory.expectRequestAdd();
|
||||||
testFactory.assertRequestCountEquals(expectedRequestCount);
|
testFactory.assertRequestCountEquals(1);
|
||||||
assertTrue(testFactory.getMyStartRequested());
|
assertTrue(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
// Now bring in a higher scored network.
|
// Now bring in a higher scored network.
|
||||||
@@ -3122,20 +3107,45 @@ public class ConnectivityServiceTest {
|
|||||||
// own NetworkRequest during startup, just bump up the score to cancel out the
|
// own NetworkRequest during startup, just bump up the score to cancel out the
|
||||||
// unvalidated penalty.
|
// unvalidated penalty.
|
||||||
testAgent.adjustScore(40);
|
testAgent.adjustScore(40);
|
||||||
cv = testFactory.getNetworkStoppedCV();
|
|
||||||
|
|
||||||
// When testAgent connects, ConnectivityService will re-send us all current requests with
|
// When testAgent connects, because of its 50 score (50 for cell + 40 adjustment score
|
||||||
// the new score. There are expectedRequestCount such requests, and we must wait for all of
|
// - 40 penalty for not being validated), it will beat the testFactory's offer, so
|
||||||
// them.
|
// the request will be removed.
|
||||||
testAgent.connect(false);
|
testAgent.connect(false);
|
||||||
testAgent.addCapability(capability);
|
testAgent.addCapability(capability);
|
||||||
waitFor(cv);
|
testFactory.expectRequestRemove();
|
||||||
testFactory.expectRequestAdds(expectedRequestCount);
|
testFactory.assertRequestCountEquals(0);
|
||||||
testFactory.assertRequestCountEquals(expectedRequestCount);
|
|
||||||
assertFalse(testFactory.getMyStartRequested());
|
assertFalse(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
|
// Add a request and make sure it's not sent to the factory, because the agent
|
||||||
|
// is satisfying it better.
|
||||||
|
final NetworkCallback cb = new ConnectivityManager.NetworkCallback();
|
||||||
|
mCm.requestNetwork(new NetworkRequest.Builder().addCapability(capability).build(), cb);
|
||||||
|
expectNoRequestChanged(testFactory);
|
||||||
|
testFactory.assertRequestCountEquals(0);
|
||||||
|
assertFalse(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
|
// Make the test agent weak enough to have the exact same score as the
|
||||||
|
// factory (50 for cell + 40 adjustment -40 validation penalty - 5 adjustment). Make sure
|
||||||
|
// the factory doesn't see the request.
|
||||||
|
testAgent.adjustScore(-5);
|
||||||
|
expectNoRequestChanged(testFactory);
|
||||||
|
assertFalse(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
|
// Make the test agent weak enough to see the two requests (the one that was just sent,
|
||||||
|
// and either the default one or the one sent at the top of this test if the default
|
||||||
|
// won't be seen).
|
||||||
|
testAgent.adjustScore(-45);
|
||||||
|
testFactory.expectRequestAdds(2);
|
||||||
|
testFactory.assertRequestCountEquals(2);
|
||||||
|
assertTrue(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
|
// Now unregister and make sure the request is removed.
|
||||||
|
mCm.unregisterNetworkCallback(cb);
|
||||||
|
testFactory.expectRequestRemove();
|
||||||
|
|
||||||
// Bring in a bunch of requests.
|
// Bring in a bunch of requests.
|
||||||
assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
|
assertEquals(1, testFactory.getMyRequestCount());
|
||||||
ConnectivityManager.NetworkCallback[] networkCallbacks =
|
ConnectivityManager.NetworkCallback[] networkCallbacks =
|
||||||
new ConnectivityManager.NetworkCallback[10];
|
new ConnectivityManager.NetworkCallback[10];
|
||||||
for (int i = 0; i< networkCallbacks.length; i++) {
|
for (int i = 0; i< networkCallbacks.length; i++) {
|
||||||
@@ -3145,24 +3155,28 @@ public class ConnectivityServiceTest {
|
|||||||
mCm.requestNetwork(builder.build(), networkCallbacks[i]);
|
mCm.requestNetwork(builder.build(), networkCallbacks[i]);
|
||||||
}
|
}
|
||||||
testFactory.expectRequestAdds(10);
|
testFactory.expectRequestAdds(10);
|
||||||
testFactory.assertRequestCountEquals(10 + expectedRequestCount);
|
testFactory.assertRequestCountEquals(11); // +1 for the default/test specific request
|
||||||
assertFalse(testFactory.getMyStartRequested());
|
assertTrue(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
// Remove the requests.
|
// Remove the requests.
|
||||||
for (int i = 0; i < networkCallbacks.length; i++) {
|
for (int i = 0; i < networkCallbacks.length; i++) {
|
||||||
mCm.unregisterNetworkCallback(networkCallbacks[i]);
|
mCm.unregisterNetworkCallback(networkCallbacks[i]);
|
||||||
}
|
}
|
||||||
testFactory.expectRequestRemoves(10);
|
testFactory.expectRequestRemoves(10);
|
||||||
testFactory.assertRequestCountEquals(expectedRequestCount);
|
testFactory.assertRequestCountEquals(1);
|
||||||
|
assertTrue(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
|
// Adjust the agent score up again. Expect the request to be withdrawn.
|
||||||
|
testAgent.adjustScore(50);
|
||||||
|
testFactory.expectRequestRemove();
|
||||||
|
testFactory.assertRequestCountEquals(0);
|
||||||
assertFalse(testFactory.getMyStartRequested());
|
assertFalse(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
// Drop the higher scored network.
|
// Drop the higher scored network.
|
||||||
cv = testFactory.getNetworkStartedCV();
|
|
||||||
testAgent.disconnect();
|
testAgent.disconnect();
|
||||||
waitFor(cv);
|
testFactory.expectRequestAdd();
|
||||||
testFactory.expectRequestAdds(expectedRequestCount);
|
testFactory.assertRequestCountEquals(1);
|
||||||
testFactory.assertRequestCountEquals(expectedRequestCount);
|
assertEquals(1, testFactory.getMyRequestCount());
|
||||||
assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
|
|
||||||
assertTrue(testFactory.getMyStartRequested());
|
assertTrue(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
testFactory.terminate();
|
testFactory.terminate();
|
||||||
@@ -3194,9 +3208,34 @@ public class ConnectivityServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNetworkFactoryUnregister() throws Exception {
|
public void testRegisterIgnoringScore() throws Exception {
|
||||||
|
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
|
||||||
|
mWiFiNetworkAgent.adjustScore(30); // score = 60 (wifi) + 30 = 90
|
||||||
|
mWiFiNetworkAgent.connect(true /* validated */);
|
||||||
|
|
||||||
|
// Make sure the factory sees the default network
|
||||||
final NetworkCapabilities filter = new NetworkCapabilities();
|
final NetworkCapabilities filter = new NetworkCapabilities();
|
||||||
filter.clearAll();
|
filter.addCapability(NET_CAPABILITY_INTERNET);
|
||||||
|
filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||||
|
final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
|
||||||
|
handlerThread.start();
|
||||||
|
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
|
||||||
|
mServiceContext, "testFactory", filter, mCsHandlerThread);
|
||||||
|
testFactory.registerIgnoringScore();
|
||||||
|
testFactory.expectRequestAdd();
|
||||||
|
|
||||||
|
mWiFiNetworkAgent.adjustScore(20); // exceed the maximum score
|
||||||
|
expectNoRequestChanged(testFactory); // still seeing the request
|
||||||
|
|
||||||
|
mWiFiNetworkAgent.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkFactoryUnregister() throws Exception {
|
||||||
|
// Make sure the factory sees the default network
|
||||||
|
final NetworkCapabilities filter = new NetworkCapabilities();
|
||||||
|
filter.addCapability(NET_CAPABILITY_INTERNET);
|
||||||
|
filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||||
|
|
||||||
final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
|
final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
|
||||||
handlerThread.start();
|
handlerThread.start();
|
||||||
@@ -4455,6 +4494,7 @@ public class ConnectivityServiceTest {
|
|||||||
testFactory.register();
|
testFactory.register();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Expect the factory to receive the default network request.
|
||||||
testFactory.expectRequestAdd();
|
testFactory.expectRequestAdd();
|
||||||
testFactory.assertRequestCountEquals(1);
|
testFactory.assertRequestCountEquals(1);
|
||||||
assertTrue(testFactory.getMyStartRequested());
|
assertTrue(testFactory.getMyStartRequested());
|
||||||
@@ -4463,25 +4503,44 @@ public class ConnectivityServiceTest {
|
|||||||
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
|
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
|
||||||
// Score 60 - 40 penalty for not validated yet, then 60 when it validates
|
// Score 60 - 40 penalty for not validated yet, then 60 when it validates
|
||||||
mWiFiNetworkAgent.connect(true);
|
mWiFiNetworkAgent.connect(true);
|
||||||
// Default request and mobile always on request
|
// The network connects with a low score, so the offer can still beat it and
|
||||||
testFactory.expectRequestAdds(2);
|
// nothing happens. Then the network validates, and the offer with its filter score
|
||||||
|
// of 40 can no longer beat it and the request is removed.
|
||||||
|
testFactory.expectRequestRemove();
|
||||||
|
testFactory.assertRequestCountEquals(0);
|
||||||
|
|
||||||
assertFalse(testFactory.getMyStartRequested());
|
assertFalse(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
// Turn on mobile data always on. The factory starts looking again.
|
// Turn on mobile data always on. This request will not match the wifi request, so
|
||||||
|
// it will be sent to the test factory whose filters allow to see it.
|
||||||
setAlwaysOnNetworks(true);
|
setAlwaysOnNetworks(true);
|
||||||
testFactory.expectRequestAdd();
|
testFactory.expectRequestAdd();
|
||||||
testFactory.assertRequestCountEquals(2);
|
testFactory.assertRequestCountEquals(1);
|
||||||
|
|
||||||
assertTrue(testFactory.getMyStartRequested());
|
assertTrue(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
// Bring up cell data and check that the factory stops looking.
|
// Bring up cell data and check that the factory stops looking.
|
||||||
assertLength(1, mCm.getAllNetworks());
|
assertLength(1, mCm.getAllNetworks());
|
||||||
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
|
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
|
||||||
mCellNetworkAgent.connect(true);
|
mCellNetworkAgent.connect(false);
|
||||||
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
|
cellNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent, false, false, false,
|
||||||
testFactory.expectRequestAdds(2); // Unvalidated and validated
|
TEST_CALLBACK_TIMEOUT_MS);
|
||||||
testFactory.assertRequestCountEquals(2);
|
// When cell connects, it will satisfy the "mobile always on request" right away
|
||||||
// The cell network outscores the factory filter, so start is not requested.
|
// by virtue of being the only network that can satisfy the request. However, its
|
||||||
|
// score is low (50 - 40 = 10) so the test factory can still hope to beat it.
|
||||||
|
expectNoRequestChanged(testFactory);
|
||||||
|
|
||||||
|
// Next, cell validates. This gives it a score of 50 and the test factory can't
|
||||||
|
// hope to beat that according to its filters. It will see the message that its
|
||||||
|
// offer is now unnecessary.
|
||||||
|
mCellNetworkAgent.setNetworkValid(true);
|
||||||
|
// Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
|
||||||
|
// validated – see testPartialConnectivity.
|
||||||
|
mCm.reportNetworkConnectivity(mCellNetworkAgent.getNetwork(), true);
|
||||||
|
cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mCellNetworkAgent);
|
||||||
|
testFactory.expectRequestRemove();
|
||||||
|
testFactory.assertRequestCountEquals(0);
|
||||||
|
// Accordingly, the factory shouldn't be started.
|
||||||
assertFalse(testFactory.getMyStartRequested());
|
assertFalse(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
// Check that cell data stays up.
|
// Check that cell data stays up.
|
||||||
@@ -4489,10 +4548,27 @@ public class ConnectivityServiceTest {
|
|||||||
verifyActiveNetwork(TRANSPORT_WIFI);
|
verifyActiveNetwork(TRANSPORT_WIFI);
|
||||||
assertLength(2, mCm.getAllNetworks());
|
assertLength(2, mCm.getAllNetworks());
|
||||||
|
|
||||||
// Turn off mobile data always on and expect the request to disappear...
|
// Cell disconnects. There is still the "mobile data always on" request outstanding,
|
||||||
setAlwaysOnNetworks(false);
|
// and the test factory should see it now that it isn't hopelessly outscored.
|
||||||
testFactory.expectRequestRemove();
|
mCellNetworkAgent.disconnect();
|
||||||
|
cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
|
||||||
|
assertLength(1, mCm.getAllNetworks());
|
||||||
|
testFactory.expectRequestAdd();
|
||||||
|
testFactory.assertRequestCountEquals(1);
|
||||||
|
|
||||||
|
// Reconnect cell validated, see the request disappear again. Then withdraw the
|
||||||
|
// mobile always on request. This will tear down cell, and there shouldn't be a
|
||||||
|
// blip where the test factory briefly sees the request or anything.
|
||||||
|
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
|
||||||
|
mCellNetworkAgent.connect(true);
|
||||||
|
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
|
||||||
|
assertLength(2, mCm.getAllNetworks());
|
||||||
|
testFactory.expectRequestRemove();
|
||||||
|
testFactory.assertRequestCountEquals(0);
|
||||||
|
setAlwaysOnNetworks(false);
|
||||||
|
expectNoRequestChanged(testFactory);
|
||||||
|
testFactory.assertRequestCountEquals(0);
|
||||||
|
assertFalse(testFactory.getMyStartRequested());
|
||||||
// ... and cell data to be torn down after nascent network timeout.
|
// ... and cell data to be torn down after nascent network timeout.
|
||||||
cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent,
|
cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent,
|
||||||
mService.mNascentDelayMs + TEST_CALLBACK_TIMEOUT_MS);
|
mService.mNascentDelayMs + TEST_CALLBACK_TIMEOUT_MS);
|
||||||
@@ -4795,7 +4871,8 @@ public class ConnectivityServiceTest {
|
|||||||
handlerThread.start();
|
handlerThread.start();
|
||||||
NetworkCapabilities filter = new NetworkCapabilities()
|
NetworkCapabilities filter = new NetworkCapabilities()
|
||||||
.addTransportType(TRANSPORT_WIFI)
|
.addTransportType(TRANSPORT_WIFI)
|
||||||
.addCapability(NET_CAPABILITY_INTERNET);
|
.addCapability(NET_CAPABILITY_INTERNET)
|
||||||
|
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||||
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
|
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
|
||||||
mServiceContext, "testFactory", filter, mCsHandlerThread);
|
mServiceContext, "testFactory", filter, mCsHandlerThread);
|
||||||
testFactory.setScoreFilter(40);
|
testFactory.setScoreFilter(40);
|
||||||
@@ -4804,32 +4881,43 @@ public class ConnectivityServiceTest {
|
|||||||
testFactory.register();
|
testFactory.register();
|
||||||
testFactory.expectRequestAdd();
|
testFactory.expectRequestAdd();
|
||||||
|
|
||||||
// Now file the test request and expect it.
|
try {
|
||||||
mCm.requestNetwork(nr, networkCallback);
|
// Now file the test request and expect it.
|
||||||
final NetworkRequest newRequest = testFactory.expectRequestAdd().request;
|
mCm.requestNetwork(nr, networkCallback);
|
||||||
|
final NetworkRequest newRequest = testFactory.expectRequestAdd().request;
|
||||||
|
|
||||||
if (preUnregister) {
|
if (preUnregister) {
|
||||||
mCm.unregisterNetworkCallback(networkCallback);
|
mCm.unregisterNetworkCallback(networkCallback);
|
||||||
|
|
||||||
// Simulate the factory releasing the request as unfulfillable: no-op since
|
// The request has been released : the factory should see it removed
|
||||||
// the callback has already been unregistered (but a test that no exceptions are
|
// immediately.
|
||||||
// thrown).
|
testFactory.expectRequestRemove();
|
||||||
testFactory.triggerUnfulfillable(newRequest);
|
|
||||||
} else {
|
|
||||||
// Simulate the factory releasing the request as unfulfillable and expect onUnavailable!
|
|
||||||
testFactory.triggerUnfulfillable(newRequest);
|
|
||||||
|
|
||||||
networkCallback.expectCallback(CallbackEntry.UNAVAILABLE, (Network) null);
|
// Simulate the factory releasing the request as unfulfillable: no-op since
|
||||||
|
// the callback has already been unregistered (but a test that no exceptions are
|
||||||
|
// thrown).
|
||||||
|
testFactory.triggerUnfulfillable(newRequest);
|
||||||
|
} else {
|
||||||
|
// Simulate the factory releasing the request as unfulfillable and expect
|
||||||
|
// onUnavailable!
|
||||||
|
testFactory.triggerUnfulfillable(newRequest);
|
||||||
|
|
||||||
// unregister network callback - a no-op (since already freed by the
|
networkCallback.expectCallback(CallbackEntry.UNAVAILABLE, (Network) null);
|
||||||
// on-unavailable), but should not fail or throw exceptions.
|
|
||||||
mCm.unregisterNetworkCallback(networkCallback);
|
// Declaring a request unfulfillable releases it automatically.
|
||||||
|
testFactory.expectRequestRemove();
|
||||||
|
|
||||||
|
// unregister network callback - a no-op (since already freed by the
|
||||||
|
// on-unavailable), but should not fail or throw exceptions.
|
||||||
|
mCm.unregisterNetworkCallback(networkCallback);
|
||||||
|
|
||||||
|
// The factory should not see any further removal, as this request has
|
||||||
|
// already been removed.
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
testFactory.terminate();
|
||||||
|
handlerThread.quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
testFactory.expectRequestRemove();
|
|
||||||
|
|
||||||
testFactory.terminate();
|
|
||||||
handlerThread.quit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
|
private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
|
||||||
@@ -11588,6 +11676,115 @@ public class ConnectivityServiceTest {
|
|||||||
// default callbacks will be unregistered in tearDown
|
// default callbacks will be unregistered in tearDown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkFactoryRequestsWithMultilayerRequest()
|
||||||
|
throws Exception {
|
||||||
|
// First use OEM_PAID preference to create a multi-layer request : 1. listen for
|
||||||
|
// unmetered, 2. request network with cap OEM_PAID, 3, request the default network for
|
||||||
|
// fallback.
|
||||||
|
@OemNetworkPreferences.OemNetworkPreference final int networkPref =
|
||||||
|
OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
|
||||||
|
setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
|
||||||
|
|
||||||
|
final HandlerThread handlerThread = new HandlerThread("MockFactory");
|
||||||
|
handlerThread.start();
|
||||||
|
NetworkCapabilities internetFilter = new NetworkCapabilities()
|
||||||
|
.addCapability(NET_CAPABILITY_INTERNET)
|
||||||
|
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||||
|
final MockNetworkFactory internetFactory = new MockNetworkFactory(handlerThread.getLooper(),
|
||||||
|
mServiceContext, "internetFactory", internetFilter, mCsHandlerThread);
|
||||||
|
internetFactory.setScoreFilter(40);
|
||||||
|
internetFactory.register();
|
||||||
|
// Default internet request & 3rd (fallback) request in OEM_PAID NRI. The unmetered request
|
||||||
|
// is never sent to factories (it's a LISTEN, not requestable) and the OEM_PAID request
|
||||||
|
// doesn't match the internetFactory filter.
|
||||||
|
internetFactory.expectRequestAdds(2);
|
||||||
|
|
||||||
|
NetworkCapabilities oemPaidFilter = new NetworkCapabilities()
|
||||||
|
.addCapability(NET_CAPABILITY_INTERNET)
|
||||||
|
.addCapability(NET_CAPABILITY_OEM_PAID)
|
||||||
|
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
|
||||||
|
.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
|
||||||
|
final MockNetworkFactory oemPaidFactory = new MockNetworkFactory(handlerThread.getLooper(),
|
||||||
|
mServiceContext, "oemPaidFactory", oemPaidFilter, mCsHandlerThread);
|
||||||
|
oemPaidFactory.setScoreFilter(40);
|
||||||
|
oemPaidFactory.register();
|
||||||
|
oemPaidFactory.expectRequestAdd(); // Because nobody satisfies the request
|
||||||
|
|
||||||
|
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
|
||||||
|
mCellNetworkAgent.connect(true);
|
||||||
|
|
||||||
|
// A network connected that satisfies the default internet request. For the OEM_PAID
|
||||||
|
// preference, this is not as good as an OEM_PAID network, so even if the score of
|
||||||
|
// the network is better than the factory announced, it still should try to bring up
|
||||||
|
// the network.
|
||||||
|
expectNoRequestChanged(oemPaidFactory);
|
||||||
|
oemPaidFactory.assertRequestCountEquals(1);
|
||||||
|
// The internet factory however is outscored, and should lose its requests.
|
||||||
|
internetFactory.expectRequestRemoves(2);
|
||||||
|
internetFactory.assertRequestCountEquals(0);
|
||||||
|
|
||||||
|
final NetworkCapabilities oemPaidNc = new NetworkCapabilities();
|
||||||
|
oemPaidNc.addCapability(NET_CAPABILITY_OEM_PAID);
|
||||||
|
oemPaidNc.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
|
||||||
|
final TestNetworkAgentWrapper oemPaidAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR,
|
||||||
|
new LinkProperties(), oemPaidNc);
|
||||||
|
oemPaidAgent.connect(true);
|
||||||
|
|
||||||
|
// The oemPaidAgent has score 50 (default for cell) so it beats what the oemPaidFactory can
|
||||||
|
// provide, therefore it loses the request.
|
||||||
|
oemPaidFactory.expectRequestRemove();
|
||||||
|
oemPaidFactory.assertRequestCountEquals(0);
|
||||||
|
expectNoRequestChanged(internetFactory);
|
||||||
|
internetFactory.assertRequestCountEquals(0);
|
||||||
|
|
||||||
|
oemPaidAgent.adjustScore(-30);
|
||||||
|
// Now the that the agent is weak, the oemPaidFactory can beat the existing network for the
|
||||||
|
// OEM_PAID request. The internet factory however can't beat a network that has OEM_PAID
|
||||||
|
// for the preference request, so it doesn't see the request.
|
||||||
|
oemPaidFactory.expectRequestAdd();
|
||||||
|
oemPaidFactory.assertRequestCountEquals(1);
|
||||||
|
expectNoRequestChanged(internetFactory);
|
||||||
|
internetFactory.assertRequestCountEquals(0);
|
||||||
|
|
||||||
|
mCellNetworkAgent.disconnect();
|
||||||
|
// The network satisfying the default internet request has disconnected, so the
|
||||||
|
// internetFactory sees the default request again. However there is a network with OEM_PAID
|
||||||
|
// connected, so the 2nd OEM_PAID req is already satisfied, so the oemPaidFactory doesn't
|
||||||
|
// care about networks that don't have OEM_PAID.
|
||||||
|
expectNoRequestChanged(oemPaidFactory);
|
||||||
|
oemPaidFactory.assertRequestCountEquals(1);
|
||||||
|
internetFactory.expectRequestAdd();
|
||||||
|
internetFactory.assertRequestCountEquals(1);
|
||||||
|
|
||||||
|
// Cell connects again, still with score 50. Back to the previous state.
|
||||||
|
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
|
||||||
|
mCellNetworkAgent.connect(true);
|
||||||
|
expectNoRequestChanged(oemPaidFactory);
|
||||||
|
oemPaidFactory.assertRequestCountEquals(1);
|
||||||
|
internetFactory.expectRequestRemove();
|
||||||
|
internetFactory.assertRequestCountEquals(0);
|
||||||
|
|
||||||
|
// Now WiFi connects and it's unmetered, but it's weaker than cell.
|
||||||
|
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
|
||||||
|
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
|
||||||
|
mWiFiNetworkAgent.adjustScore(-30); // Not the best Internet network, but unmetered
|
||||||
|
mWiFiNetworkAgent.connect(true);
|
||||||
|
|
||||||
|
// The OEM_PAID preference prefers an unmetered network to an OEM_PAID network, so
|
||||||
|
// the oemPaidFactory can't beat this no matter how high its score.
|
||||||
|
oemPaidFactory.expectRequestRemove();
|
||||||
|
expectNoRequestChanged(internetFactory);
|
||||||
|
|
||||||
|
mCellNetworkAgent.disconnect();
|
||||||
|
// Now that the best internet network (cell, with its 50 score compared to 30 for WiFi
|
||||||
|
// at this point), the default internet request is satisfied by a network worse than
|
||||||
|
// the internetFactory announced, so it gets the request. However, there is still an
|
||||||
|
// unmetered network, so the oemPaidNetworkFactory still can't beat this.
|
||||||
|
expectNoRequestChanged(oemPaidFactory);
|
||||||
|
internetFactory.expectRequestAdd();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK in the following order:
|
* Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK in the following order:
|
||||||
* NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID
|
* NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID
|
||||||
@@ -11909,11 +12106,11 @@ public class ConnectivityServiceTest {
|
|||||||
testFactory.setScoreFilter(40);
|
testFactory.setScoreFilter(40);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Register the factory and expect it will see default request, because all requests
|
// Register the factory. It doesn't see the default request because its filter does
|
||||||
// are sent to all factories.
|
// not include INTERNET.
|
||||||
testFactory.register();
|
testFactory.register();
|
||||||
testFactory.expectRequestAdd();
|
expectNoRequestChanged(testFactory);
|
||||||
testFactory.assertRequestCountEquals(1);
|
testFactory.assertRequestCountEquals(0);
|
||||||
// The factory won't try to start the network since the default request doesn't
|
// The factory won't try to start the network since the default request doesn't
|
||||||
// match the filter (no INTERNET capability).
|
// match the filter (no INTERNET capability).
|
||||||
assertFalse(testFactory.getMyStartRequested());
|
assertFalse(testFactory.getMyStartRequested());
|
||||||
@@ -11926,7 +12123,7 @@ public class ConnectivityServiceTest {
|
|||||||
bestMatchingCb, mCsHandlerThread.getThreadHandler());
|
bestMatchingCb, mCsHandlerThread.getThreadHandler());
|
||||||
bestMatchingCb.assertNoCallback();
|
bestMatchingCb.assertNoCallback();
|
||||||
expectNoRequestChanged(testFactory);
|
expectNoRequestChanged(testFactory);
|
||||||
testFactory.assertRequestCountEquals(1);
|
testFactory.assertRequestCountEquals(0);
|
||||||
assertFalse(testFactory.getMyStartRequested());
|
assertFalse(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
// Fire a normal mms request, verify the factory will only see the request.
|
// Fire a normal mms request, verify the factory will only see the request.
|
||||||
@@ -11935,13 +12132,13 @@ public class ConnectivityServiceTest {
|
|||||||
.addCapability(NET_CAPABILITY_MMS).build();
|
.addCapability(NET_CAPABILITY_MMS).build();
|
||||||
mCm.requestNetwork(mmsRequest, mmsNetworkCallback);
|
mCm.requestNetwork(mmsRequest, mmsNetworkCallback);
|
||||||
testFactory.expectRequestAdd();
|
testFactory.expectRequestAdd();
|
||||||
testFactory.assertRequestCountEquals(2);
|
testFactory.assertRequestCountEquals(1);
|
||||||
assertTrue(testFactory.getMyStartRequested());
|
assertTrue(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
// Unregister best matching callback, verify factory see no change.
|
// Unregister best matching callback, verify factory see no change.
|
||||||
mCm.unregisterNetworkCallback(bestMatchingCb);
|
mCm.unregisterNetworkCallback(bestMatchingCb);
|
||||||
expectNoRequestChanged(testFactory);
|
expectNoRequestChanged(testFactory);
|
||||||
testFactory.assertRequestCountEquals(2);
|
testFactory.assertRequestCountEquals(1);
|
||||||
assertTrue(testFactory.getMyStartRequested());
|
assertTrue(testFactory.getMyStartRequested());
|
||||||
} finally {
|
} finally {
|
||||||
testFactory.terminate();
|
testFactory.terminate();
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.connectivity
|
||||||
|
|
||||||
|
import android.net.INetworkOfferCallback
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
|
import android.net.NetworkRequest
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentMatchers.eq
|
||||||
|
import org.mockito.Mockito.mock
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import kotlin.test.assertFalse
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
const val POLICY_NONE = 0L
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class NetworkOfferTest {
|
||||||
|
val mockCallback = mock(INetworkOfferCallback::class.java)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOfferNeededUnneeded() {
|
||||||
|
val score = FullScore(50, POLICY_NONE)
|
||||||
|
val offer = NetworkOffer(score, NetworkCapabilities.Builder().build(), mockCallback,
|
||||||
|
1 /* providerId */)
|
||||||
|
val request1 = mock(NetworkRequest::class.java)
|
||||||
|
val request2 = mock(NetworkRequest::class.java)
|
||||||
|
offer.onNetworkNeeded(request1)
|
||||||
|
verify(mockCallback).onNetworkNeeded(eq(request1))
|
||||||
|
assertTrue(offer.neededFor(request1))
|
||||||
|
assertFalse(offer.neededFor(request2))
|
||||||
|
|
||||||
|
offer.onNetworkNeeded(request2)
|
||||||
|
verify(mockCallback).onNetworkNeeded(eq(request2))
|
||||||
|
assertTrue(offer.neededFor(request1))
|
||||||
|
assertTrue(offer.neededFor(request2))
|
||||||
|
|
||||||
|
// Note that the framework never calls onNetworkNeeded multiple times with the same
|
||||||
|
// request without calling onNetworkUnneeded first. It would be incorrect usage and the
|
||||||
|
// behavior would be undefined, so there is nothing to test.
|
||||||
|
|
||||||
|
offer.onNetworkUnneeded(request1)
|
||||||
|
verify(mockCallback).onNetworkUnneeded(eq(request1))
|
||||||
|
assertFalse(offer.neededFor(request1))
|
||||||
|
assertTrue(offer.neededFor(request2))
|
||||||
|
|
||||||
|
offer.onNetworkUnneeded(request2)
|
||||||
|
verify(mockCallback).onNetworkUnneeded(eq(request2))
|
||||||
|
assertFalse(offer.neededFor(request1))
|
||||||
|
assertFalse(offer.neededFor(request2))
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user