Multilayer support when NAI requests are updated
Updates to ConnectivityService to support multilayer requests in any flows which a NetworkAgentInfo has a NetworkRequest added/removed. This would include both 'listen' and 'request' types of NetworkRequest objects. Bug: 174271773 Bug: 171991028 Test: atest FrameworksNetTests atest NetworkStackTests atest FrameworksNetIntegrationTests atest NetworkStackIntegrationTests atest CtsNetTestCasesLatestSdk Change-Id: Iaff727e792828684e6ad4d07d0081e27992031be
This commit is contained in:
@@ -1456,9 +1456,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final String action = blocked ? "BLOCKED" : "UNBLOCKED";
|
final String action = blocked ? "BLOCKED" : "UNBLOCKED";
|
||||||
final NetworkRequest satisfiedRequest = nri.getSatisfiedRequest();
|
final int requestId = nri.getActiveRequest() != null
|
||||||
final int requestId = satisfiedRequest != null
|
? nri.getActiveRequest().requestId : nri.mRequests.get(0).requestId;
|
||||||
? satisfiedRequest.requestId : nri.mRequests.get(0).requestId;
|
|
||||||
mNetworkInfoBlockingLogs.log(String.format(
|
mNetworkInfoBlockingLogs.log(String.format(
|
||||||
"%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId()));
|
"%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId()));
|
||||||
}
|
}
|
||||||
@@ -2728,7 +2727,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
NetworkRequestInfo[] requestsSortedById() {
|
NetworkRequestInfo[] requestsSortedById() {
|
||||||
NetworkRequestInfo[] requests = new NetworkRequestInfo[0];
|
NetworkRequestInfo[] requests = new NetworkRequestInfo[0];
|
||||||
requests = mNetworkRequests.values().toArray(requests);
|
requests = getNrisFromGlobalRequests().toArray(requests);
|
||||||
// Sort the array based off the NRI containing the min requestId in its requests.
|
// Sort the array based off the NRI containing the min requestId in its requests.
|
||||||
Arrays.sort(requests,
|
Arrays.sort(requests,
|
||||||
Comparator.comparingInt(nri -> Collections.min(nri.mRequests,
|
Comparator.comparingInt(nri -> Collections.min(nri.mRequests,
|
||||||
@@ -3433,10 +3432,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
for (int i = 0; i < nai.numNetworkRequests(); i++) {
|
for (int i = 0; i < nai.numNetworkRequests(); i++) {
|
||||||
NetworkRequest request = nai.requestAt(i);
|
NetworkRequest request = nai.requestAt(i);
|
||||||
final NetworkRequestInfo nri = mNetworkRequests.get(request);
|
final NetworkRequestInfo nri = mNetworkRequests.get(request);
|
||||||
final NetworkAgentInfo currentNetwork = nri.mSatisfier;
|
final NetworkAgentInfo currentNetwork = nri.getSatisfier();
|
||||||
if (currentNetwork != null
|
if (currentNetwork != null
|
||||||
&& currentNetwork.network.getNetId() == nai.network.getNetId()) {
|
&& currentNetwork.network.getNetId() == nai.network.getNetId()) {
|
||||||
nri.mSatisfier = null;
|
nri.setSatisfier(null, null);
|
||||||
sendUpdatedScoreToFactories(request, null);
|
sendUpdatedScoreToFactories(request, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3540,7 +3539,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
rematchAllNetworksAndRequests();
|
rematchAllNetworksAndRequests();
|
||||||
if (nri.request.isRequest() && nri.mSatisfier == null) {
|
if (nri.request.isRequest() && nri.getSatisfier() == null) {
|
||||||
sendUpdatedScoreToFactories(nri.request, null);
|
sendUpdatedScoreToFactories(nri.request, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3603,6 +3602,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (final NetworkRequest req : nri.mRequests) {
|
for (final NetworkRequest req : nri.mRequests) {
|
||||||
|
// This multilayer listen request is satisfied therefore no further requests need to be
|
||||||
|
// evaluated deeming this network not a potential satisfier.
|
||||||
|
if (req.isListen() && nri.getActiveRequest() == req) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// As non-multilayer listen requests have already returned, the below would only happen
|
// As non-multilayer listen requests have already returned, the below would only happen
|
||||||
// for a multilayer request therefore continue to the next request if available.
|
// for a multilayer request therefore continue to the next request if available.
|
||||||
if (req.isListen()) {
|
if (req.isListen()) {
|
||||||
@@ -3623,7 +3627,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// 2. Unvalidated WiFi will not be reaped when validated cellular
|
// 2. Unvalidated WiFi will not be reaped when validated cellular
|
||||||
// is currently satisfying the request. This is desirable when
|
// is currently satisfying the request. This is desirable when
|
||||||
// WiFi ends up validating and out scoring cellular.
|
// WiFi ends up validating and out scoring cellular.
|
||||||
|| nri.mSatisfier.getCurrentScore()
|
|| nri.getSatisfier().getCurrentScore()
|
||||||
< candidate.getCurrentScoreAsValidated();
|
< candidate.getCurrentScoreAsValidated();
|
||||||
return isNetworkNeeded;
|
return isNetworkNeeded;
|
||||||
}
|
}
|
||||||
@@ -3653,7 +3657,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
if (mNetworkRequests.get(nri.request) == null) {
|
if (mNetworkRequests.get(nri.request) == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (nri.mSatisfier != null) {
|
if (nri.getSatisfier() != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (VDBG || (DBG && nri.request.isRequest())) {
|
if (VDBG || (DBG && nri.request.isRequest())) {
|
||||||
@@ -3679,21 +3683,68 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleRemoveNetworkRequest(final NetworkRequestInfo nri) {
|
private void handleRemoveNetworkRequest(@NonNull final NetworkRequestInfo nri) {
|
||||||
ensureRunningOnConnectivityServiceThread();
|
ensureRunningOnConnectivityServiceThread();
|
||||||
|
|
||||||
nri.unlinkDeathRecipient();
|
nri.unlinkDeathRecipient();
|
||||||
mNetworkRequests.remove(nri.request);
|
for (final NetworkRequest req : nri.mRequests) {
|
||||||
|
mNetworkRequests.remove(req);
|
||||||
|
if (req.isListen()) {
|
||||||
|
removeListenRequestFromNetworks(req);
|
||||||
|
}
|
||||||
|
}
|
||||||
mNetworkRequestCounter.decrementCount(nri.mUid);
|
mNetworkRequestCounter.decrementCount(nri.mUid);
|
||||||
|
|
||||||
mNetworkRequestInfoLogs.log("RELEASE " + nri);
|
mNetworkRequestInfoLogs.log("RELEASE " + nri);
|
||||||
if (nri.request.isRequest()) {
|
|
||||||
|
if (null != nri.getActiveRequest()) {
|
||||||
|
if (nri.getActiveRequest().isRequest()) {
|
||||||
|
removeSatisfiedNetworkRequestFromNetwork(nri);
|
||||||
|
} else {
|
||||||
|
nri.setSatisfier(null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelNpiRequests(nri);
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
|
||||||
|
nai.removeRequest(req.requestId);
|
||||||
|
if (req.networkCapabilities.hasSignalStrength()
|
||||||
|
&& nai.satisfiesImmutableCapabilitiesOf(req)) {
|
||||||
|
updateSignalStrengthThresholds(nai, "RELEASE", req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a NetworkRequestInfo's satisfied request from its 'satisfier' (NetworkAgentInfo) and
|
||||||
|
* manage the necessary upkeep (linger, teardown networks, etc.) when doing so.
|
||||||
|
* @param nri the NetworkRequestInfo to disassociate from its current NetworkAgentInfo
|
||||||
|
*/
|
||||||
|
private void removeSatisfiedNetworkRequestFromNetwork(@NonNull final NetworkRequestInfo nri) {
|
||||||
boolean wasKept = false;
|
boolean wasKept = false;
|
||||||
final NetworkAgentInfo nai = nri.mSatisfier;
|
final NetworkAgentInfo nai = nri.getSatisfier();
|
||||||
if (nai != null) {
|
if (nai != null) {
|
||||||
boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
|
final int requestLegacyType = nri.getActiveRequest().legacyType;
|
||||||
nai.removeRequest(nri.request.requestId);
|
final boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
|
||||||
|
nai.removeRequest(nri.getActiveRequest().requestId);
|
||||||
if (VDBG || DDBG) {
|
if (VDBG || DDBG) {
|
||||||
log(" Removing from current network " + nai.toShortString()
|
log(" Removing from current network " + nai.toShortString()
|
||||||
+ ", leaving " + nai.numNetworkRequests() + " requests.");
|
+ ", leaving " + nai.numNetworkRequests() + " requests.");
|
||||||
@@ -3710,27 +3761,26 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
} else {
|
} else {
|
||||||
wasKept = true;
|
wasKept = true;
|
||||||
}
|
}
|
||||||
nri.mSatisfier = null;
|
nri.setSatisfier(null, null);
|
||||||
if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
|
if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
|
||||||
// Went from foreground to background.
|
// Went from foreground to background.
|
||||||
updateCapabilitiesForNetwork(nai);
|
updateCapabilitiesForNetwork(nai);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Maintain the illusion. When this request arrived, we might have pretended
|
// Maintain the illusion. When this request arrived, we might have pretended
|
||||||
// that a network connected to serve it, even though the network was already
|
// that a network connected to serve it, even though the network was already
|
||||||
// connected. Now that this request has gone away, we might have to pretend
|
// connected. Now that this request has gone away, we might have to pretend
|
||||||
// that the network disconnected. LegacyTypeTracker will generate that
|
// that the network disconnected. LegacyTypeTracker will generate that
|
||||||
// phantom disconnect for this type.
|
// phantom disconnect for this type.
|
||||||
if (nri.request.legacyType != TYPE_NONE && nai != null) {
|
if (requestLegacyType != TYPE_NONE) {
|
||||||
boolean doRemove = true;
|
boolean doRemove = true;
|
||||||
if (wasKept) {
|
if (wasKept) {
|
||||||
// check if any of the remaining requests for this network are for the
|
// check if any of the remaining requests for this network are for the
|
||||||
// same legacy type - if so, don't remove the nai
|
// same legacy type - if so, don't remove the nai
|
||||||
for (int i = 0; i < nai.numNetworkRequests(); i++) {
|
for (int i = 0; i < nai.numNetworkRequests(); i++) {
|
||||||
NetworkRequest otherRequest = nai.requestAt(i);
|
NetworkRequest otherRequest = nai.requestAt(i);
|
||||||
if (otherRequest.legacyType == nri.request.legacyType &&
|
if (otherRequest.legacyType == requestLegacyType
|
||||||
otherRequest.isRequest()) {
|
&& otherRequest.isRequest()) {
|
||||||
if (DBG) log(" still have other legacy request - leaving");
|
if (DBG) log(" still have other legacy request - leaving");
|
||||||
doRemove = false;
|
doRemove = false;
|
||||||
}
|
}
|
||||||
@@ -3738,21 +3788,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (doRemove) {
|
if (doRemove) {
|
||||||
mLegacyTypeTracker.remove(nri.request.legacyType, nai, false);
|
mLegacyTypeTracker.remove(requestLegacyType, nai, false);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (NetworkProviderInfo npi : mNetworkProviderInfos.values()) {
|
|
||||||
npi.cancelRequest(nri.request);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// listens don't have a singular affectedNetwork. Check all networks to see
|
|
||||||
// if this listen request applies and remove it.
|
|
||||||
for (NetworkAgentInfo nai : mNetworkAgentInfos) {
|
|
||||||
nai.removeRequest(nri.request.requestId);
|
|
||||||
if (nri.request.networkCapabilities.hasSignalStrength() &&
|
|
||||||
nai.satisfiesImmutableCapabilitiesOf(nri.request)) {
|
|
||||||
updateSignalStrengthThresholds(nai, "RELEASE", nri.request);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5422,11 +5458,32 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
final List<NetworkRequest> mRequests;
|
final List<NetworkRequest> mRequests;
|
||||||
final NetworkRequest request;
|
final NetworkRequest request;
|
||||||
|
|
||||||
|
// mSatisfier and mActiveRequest rely on one another therefore set them together.
|
||||||
|
void setSatisfier(
|
||||||
|
@Nullable final NetworkAgentInfo satisfier,
|
||||||
|
@Nullable final NetworkRequest activeRequest) {
|
||||||
|
mSatisfier = satisfier;
|
||||||
|
mActiveRequest = activeRequest;
|
||||||
|
}
|
||||||
|
|
||||||
// The network currently satisfying this request, or null if none. Must only be touched
|
// The network currently satisfying this request, or null if none. Must only be touched
|
||||||
// on the handler thread. This only makes sense for network requests and not for listens,
|
// on the handler thread. This only makes sense for network requests and not for listens,
|
||||||
// as defined by NetworkRequest#isRequest(). For listens, this is always null.
|
// as defined by NetworkRequest#isRequest(). For listens, this is always null.
|
||||||
@Nullable
|
@Nullable
|
||||||
NetworkAgentInfo mSatisfier;
|
private NetworkAgentInfo mSatisfier;
|
||||||
|
NetworkAgentInfo getSatisfier() {
|
||||||
|
return mSatisfier;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The request in mRequests assigned to a network agent. This is null if none of the
|
||||||
|
// requests in mRequests can be satisfied. This member has the constraint of only being
|
||||||
|
// accessible on the handler thread.
|
||||||
|
@Nullable
|
||||||
|
private NetworkRequest mActiveRequest;
|
||||||
|
NetworkRequest getActiveRequest() {
|
||||||
|
return mActiveRequest;
|
||||||
|
}
|
||||||
|
|
||||||
final PendingIntent mPendingIntent;
|
final PendingIntent mPendingIntent;
|
||||||
boolean mPendingIntentSent;
|
boolean mPendingIntentSent;
|
||||||
private final IBinder mBinder;
|
private final IBinder mBinder;
|
||||||
@@ -5479,20 +5536,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
return Collections.unmodifiableList(tempRequests);
|
return Collections.unmodifiableList(tempRequests);
|
||||||
}
|
}
|
||||||
|
|
||||||
private NetworkRequest getSatisfiedRequest() {
|
|
||||||
if (mSatisfier == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (NetworkRequest req : mRequests) {
|
|
||||||
if (mSatisfier.isSatisfyingRequest(req.requestId)) {
|
|
||||||
return req;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlinkDeathRecipient() {
|
void unlinkDeathRecipient() {
|
||||||
if (mBinder != null) {
|
if (mBinder != null) {
|
||||||
mBinder.unlinkToDeath(this, 0);
|
mBinder.unlinkToDeath(this, 0);
|
||||||
@@ -5539,6 +5582,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
private int[] getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) {
|
private int[] getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) {
|
||||||
final SortedSet<Integer> thresholds = new TreeSet<>();
|
final SortedSet<Integer> thresholds = new TreeSet<>();
|
||||||
synchronized (nai) {
|
synchronized (nai) {
|
||||||
|
// mNetworkRequests may contain the same value multiple times in case of
|
||||||
|
// multilayer requests. It won't matter in this case because the thresholds
|
||||||
|
// will then be the same and be deduplicated as they enter the `thresholds` set.
|
||||||
|
// TODO : have mNetworkRequests be a Set<NetworkRequestInfo> or the like.
|
||||||
for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
|
for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
|
||||||
for (final NetworkRequest req : nri.mRequests) {
|
for (final NetworkRequest req : nri.mRequests) {
|
||||||
if (req.networkCapabilities.hasSignalStrength()
|
if (req.networkCapabilities.hasSignalStrength()
|
||||||
@@ -6845,6 +6892,39 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
private void sendUpdatedScoreToFactories(@NonNull NetworkRequest networkRequest,
|
||||||
@Nullable NetworkAgentInfo nai) {
|
@Nullable NetworkAgentInfo nai) {
|
||||||
final int score;
|
final int score;
|
||||||
@@ -6869,7 +6949,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
ensureRunningOnConnectivityServiceThread();
|
ensureRunningOnConnectivityServiceThread();
|
||||||
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
|
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
|
||||||
if (nri.request.isListen()) continue;
|
if (nri.request.isListen()) continue;
|
||||||
NetworkAgentInfo nai = nri.mSatisfier;
|
NetworkAgentInfo nai = nri.getSatisfier();
|
||||||
final int score;
|
final int score;
|
||||||
final int serial;
|
final int serial;
|
||||||
if (nai != null) {
|
if (nai != null) {
|
||||||
@@ -6888,7 +6968,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
if (notificationType == ConnectivityManager.CALLBACK_AVAILABLE && !nri.mPendingIntentSent) {
|
if (notificationType == ConnectivityManager.CALLBACK_AVAILABLE && !nri.mPendingIntentSent) {
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.putExtra(ConnectivityManager.EXTRA_NETWORK, networkAgent.network);
|
intent.putExtra(ConnectivityManager.EXTRA_NETWORK, networkAgent.network);
|
||||||
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_REQUEST, nri.request);
|
// If apps could file multi-layer requests with PendingIntents, they'd need to know
|
||||||
|
// which of the layer is satisfied alongside with some ID for the request. Hence, if
|
||||||
|
// such an API is ever implemented, there is no doubt the right request to send in
|
||||||
|
// EXTRA_NETWORK_REQUEST is mActiveRequest, and whatever ID would be added would need to
|
||||||
|
// be sent as a separate extra.
|
||||||
|
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_REQUEST, nri.getActiveRequest());
|
||||||
nri.mPendingIntentSent = true;
|
nri.mPendingIntentSent = true;
|
||||||
sendIntent(nri.mPendingIntent, intent);
|
sendIntent(nri.mPendingIntent, intent);
|
||||||
}
|
}
|
||||||
@@ -7060,19 +7145,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processNewlyLostListenRequests(@NonNull final NetworkAgentInfo nai) {
|
private void processNewlyLostListenRequests(@NonNull final NetworkAgentInfo nai) {
|
||||||
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
|
for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
|
||||||
NetworkRequest nr = nri.request;
|
if (nri.isMultilayerRequest()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final NetworkRequest nr = nri.mRequests.get(0);
|
||||||
if (!nr.isListen()) continue;
|
if (!nr.isListen()) continue;
|
||||||
if (nai.isSatisfyingRequest(nr.requestId) && !nai.satisfies(nr)) {
|
if (nai.isSatisfyingRequest(nr.requestId) && !nai.satisfies(nr)) {
|
||||||
nai.removeRequest(nri.request.requestId);
|
nai.removeRequest(nr.requestId);
|
||||||
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0);
|
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processNewlySatisfiedListenRequests(@NonNull final NetworkAgentInfo nai) {
|
private void processNewlySatisfiedListenRequests(@NonNull final NetworkAgentInfo nai) {
|
||||||
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
|
for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
|
||||||
NetworkRequest nr = nri.request;
|
if (nri.isMultilayerRequest()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final NetworkRequest nr = nri.mRequests.get(0);
|
||||||
if (!nr.isListen()) continue;
|
if (!nr.isListen()) continue;
|
||||||
if (nai.satisfies(nr) && !nai.isSatisfyingRequest(nr.requestId)) {
|
if (nai.satisfies(nr) && !nai.isSatisfyingRequest(nr.requestId)) {
|
||||||
nai.addRequest(nr);
|
nai.addRequest(nr);
|
||||||
@@ -7084,19 +7175,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// An accumulator class to gather the list of changes that result from a rematch.
|
// An accumulator class to gather the list of changes that result from a rematch.
|
||||||
private static class NetworkReassignment {
|
private static class NetworkReassignment {
|
||||||
static class RequestReassignment {
|
static class RequestReassignment {
|
||||||
@NonNull public final NetworkRequestInfo mRequest;
|
@NonNull public final NetworkRequestInfo mNetworkRequestInfo;
|
||||||
|
@NonNull public final NetworkRequest mOldNetworkRequest;
|
||||||
|
@NonNull public final NetworkRequest mNewNetworkRequest;
|
||||||
@Nullable public final NetworkAgentInfo mOldNetwork;
|
@Nullable public final NetworkAgentInfo mOldNetwork;
|
||||||
@Nullable public final NetworkAgentInfo mNewNetwork;
|
@Nullable public final NetworkAgentInfo mNewNetwork;
|
||||||
RequestReassignment(@NonNull final NetworkRequestInfo request,
|
RequestReassignment(@NonNull final NetworkRequestInfo networkRequestInfo,
|
||||||
|
@NonNull final NetworkRequest oldNetworkRequest,
|
||||||
|
@NonNull final NetworkRequest newNetworkRequest,
|
||||||
@Nullable final NetworkAgentInfo oldNetwork,
|
@Nullable final NetworkAgentInfo oldNetwork,
|
||||||
@Nullable final NetworkAgentInfo newNetwork) {
|
@Nullable final NetworkAgentInfo newNetwork) {
|
||||||
mRequest = request;
|
mNetworkRequestInfo = networkRequestInfo;
|
||||||
|
mOldNetworkRequest = oldNetworkRequest;
|
||||||
|
mNewNetworkRequest = newNetworkRequest;
|
||||||
mOldNetwork = oldNetwork;
|
mOldNetwork = oldNetwork;
|
||||||
mNewNetwork = newNetwork;
|
mNewNetwork = newNetwork;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return mRequest.mRequests.get(0).requestId + " : "
|
return mNetworkRequestInfo.mRequests.get(0).requestId + " : "
|
||||||
+ (null != mOldNetwork ? mOldNetwork.network.getNetId() : "null")
|
+ (null != mOldNetwork ? mOldNetwork.network.getNetId() : "null")
|
||||||
+ " → " + (null != mNewNetwork ? mNewNetwork.network.getNetId() : "null");
|
+ " → " + (null != mNewNetwork ? mNewNetwork.network.getNetId() : "null");
|
||||||
}
|
}
|
||||||
@@ -7114,7 +7211,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// sure this stays true, but without imposing this expensive check on all
|
// sure this stays true, but without imposing this expensive check on all
|
||||||
// reassignments on all user devices.
|
// reassignments on all user devices.
|
||||||
for (final RequestReassignment existing : mReassignments) {
|
for (final RequestReassignment existing : mReassignments) {
|
||||||
if (existing.mRequest.equals(reassignment.mRequest)) {
|
if (existing.mNetworkRequestInfo.equals(reassignment.mNetworkRequestInfo)) {
|
||||||
throw new IllegalStateException("Trying to reassign ["
|
throw new IllegalStateException("Trying to reassign ["
|
||||||
+ reassignment + "] but already have ["
|
+ reassignment + "] but already have ["
|
||||||
+ existing + "]");
|
+ existing + "]");
|
||||||
@@ -7129,7 +7226,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
@Nullable
|
@Nullable
|
||||||
private RequestReassignment getReassignment(@NonNull final NetworkRequestInfo nri) {
|
private RequestReassignment getReassignment(@NonNull final NetworkRequestInfo nri) {
|
||||||
for (final RequestReassignment event : getRequestReassignments()) {
|
for (final RequestReassignment event : getRequestReassignments()) {
|
||||||
if (nri == event.mRequest) return event;
|
if (nri == event.mNetworkRequestInfo) return event;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -7156,6 +7253,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateSatisfiersForRematchRequest(@NonNull final NetworkRequestInfo nri,
|
private void updateSatisfiersForRematchRequest(@NonNull final NetworkRequestInfo nri,
|
||||||
|
@NonNull final NetworkRequest previousRequest,
|
||||||
|
@NonNull final NetworkRequest newRequest,
|
||||||
@Nullable final NetworkAgentInfo previousSatisfier,
|
@Nullable final NetworkAgentInfo previousSatisfier,
|
||||||
@Nullable final NetworkAgentInfo newSatisfier,
|
@Nullable final NetworkAgentInfo newSatisfier,
|
||||||
final long now) {
|
final long now) {
|
||||||
@@ -7165,58 +7264,98 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
if (VDBG || DDBG) {
|
if (VDBG || DDBG) {
|
||||||
log(" accepting network in place of " + previousSatisfier.toShortString());
|
log(" accepting network in place of " + previousSatisfier.toShortString());
|
||||||
}
|
}
|
||||||
previousSatisfier.removeRequest(nri.request.requestId);
|
previousSatisfier.removeRequest(previousRequest.requestId);
|
||||||
previousSatisfier.lingerRequest(nri.request.requestId, now, mLingerDelayMs);
|
previousSatisfier.lingerRequest(previousRequest.requestId, now, mLingerDelayMs);
|
||||||
} else {
|
} else {
|
||||||
if (VDBG || DDBG) log(" accepting network in place of null");
|
if (VDBG || DDBG) log(" accepting network in place of null");
|
||||||
}
|
}
|
||||||
newSatisfier.unlingerRequest(nri.request.requestId);
|
newSatisfier.unlingerRequest(newRequest.requestId);
|
||||||
if (!newSatisfier.addRequest(nri.request)) {
|
if (!newSatisfier.addRequest(newRequest)) {
|
||||||
Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
|
Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
|
||||||
+ nri.request);
|
+ newRequest);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
log("Network " + previousSatisfier.toShortString() + " stopped satisfying"
|
log("Network " + previousSatisfier.toShortString() + " stopped satisfying"
|
||||||
+ " request " + nri.request.requestId);
|
+ " request " + previousRequest.requestId);
|
||||||
}
|
}
|
||||||
previousSatisfier.removeRequest(nri.request.requestId);
|
previousSatisfier.removeRequest(previousRequest.requestId);
|
||||||
}
|
}
|
||||||
nri.mSatisfier = newSatisfier;
|
nri.setSatisfier(newSatisfier, newRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is triggered when something can affect what network should satisfy what
|
||||||
|
* request, and it computes the network reassignment from the passed collection of requests to
|
||||||
|
* network match to the one that the system should now have. That data is encoded in an
|
||||||
|
* object that is a list of changes, each of them having an NRI, and old satisfier, and a new
|
||||||
|
* satisfier.
|
||||||
|
*
|
||||||
|
* After the reassignment is computed, it is applied to the state objects.
|
||||||
|
*
|
||||||
|
* @param networkRequests the nri objects to evaluate for possible network reassignment
|
||||||
|
* @return NetworkReassignment listing of proposed network assignment changes
|
||||||
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
private NetworkReassignment computeNetworkReassignment() {
|
private NetworkReassignment computeNetworkReassignment(
|
||||||
ensureRunningOnConnectivityServiceThread();
|
@NonNull final Collection<NetworkRequestInfo> networkRequests) {
|
||||||
final NetworkReassignment changes = new NetworkReassignment();
|
final NetworkReassignment changes = new NetworkReassignment();
|
||||||
|
|
||||||
// Gather the list of all relevant agents and sort them by score.
|
// Gather the list of all relevant agents and sort them by score.
|
||||||
final ArrayList<NetworkAgentInfo> nais = new ArrayList<>();
|
final ArrayList<NetworkAgentInfo> nais = new ArrayList<>();
|
||||||
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
|
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
|
||||||
if (!nai.everConnected) continue;
|
if (!nai.everConnected) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
nais.add(nai);
|
nais.add(nai);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
|
for (final NetworkRequestInfo nri : networkRequests) {
|
||||||
if (nri.request.isListen()) continue;
|
// Non-multilayer listen requests can be ignored.
|
||||||
final NetworkAgentInfo bestNetwork = mNetworkRanker.getBestNetwork(nri.request, nais);
|
if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
NetworkAgentInfo bestNetwork = null;
|
||||||
|
NetworkRequest bestRequest = null;
|
||||||
|
for (final NetworkRequest req : nri.mRequests) {
|
||||||
|
bestNetwork = mNetworkRanker.getBestNetwork(req, nais);
|
||||||
|
// Stop evaluating as the highest possible priority request is satisfied.
|
||||||
|
if (null != bestNetwork) {
|
||||||
|
bestRequest = req;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (bestNetwork != nri.mSatisfier) {
|
if (bestNetwork != nri.mSatisfier) {
|
||||||
// bestNetwork may be null if no network can satisfy this request.
|
// bestNetwork may be null if no network can satisfy this request.
|
||||||
changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
|
changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
|
||||||
nri, nri.mSatisfier, bestNetwork));
|
nri, nri.mActiveRequest, bestRequest, nri.getSatisfier(), bestNetwork));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<NetworkRequestInfo> getNrisFromGlobalRequests() {
|
||||||
|
return new HashSet<>(mNetworkRequests.values());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to rematch all Networks with NetworkRequests. This may result in Networks
|
* Attempt to rematch all Networks with all NetworkRequests. This may result in Networks
|
||||||
* being disconnected.
|
* being disconnected.
|
||||||
*/
|
*/
|
||||||
private void rematchAllNetworksAndRequests() {
|
private void rematchAllNetworksAndRequests() {
|
||||||
|
rematchNetworksAndRequests(getNrisFromGlobalRequests());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to rematch all Networks with given NetworkRequests. This may result in Networks
|
||||||
|
* being disconnected.
|
||||||
|
*/
|
||||||
|
private void rematchNetworksAndRequests(
|
||||||
|
@NonNull final Set<NetworkRequestInfo> networkRequests) {
|
||||||
|
ensureRunningOnConnectivityServiceThread();
|
||||||
// TODO: This may be slow, and should be optimized.
|
// TODO: This may be slow, and should be optimized.
|
||||||
final long now = SystemClock.elapsedRealtime();
|
final long now = SystemClock.elapsedRealtime();
|
||||||
final NetworkReassignment changes = computeNetworkReassignment();
|
final NetworkReassignment changes = computeNetworkReassignment(networkRequests);
|
||||||
if (VDBG || DDBG) {
|
if (VDBG || DDBG) {
|
||||||
log(changes.debugString());
|
log(changes.debugString());
|
||||||
} else if (DBG) {
|
} else if (DBG) {
|
||||||
@@ -7241,8 +7380,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// the linger status.
|
// the linger status.
|
||||||
for (final NetworkReassignment.RequestReassignment event :
|
for (final NetworkReassignment.RequestReassignment event :
|
||||||
changes.getRequestReassignments()) {
|
changes.getRequestReassignments()) {
|
||||||
updateSatisfiersForRematchRequest(event.mRequest, event.mOldNetwork,
|
updateSatisfiersForRematchRequest(event.mNetworkRequestInfo,
|
||||||
event.mNewNetwork, now);
|
event.mOldNetworkRequest, event.mNewNetworkRequest,
|
||||||
|
event.mOldNetwork, event.mNewNetwork,
|
||||||
|
now);
|
||||||
}
|
}
|
||||||
|
|
||||||
final NetworkAgentInfo oldDefaultNetwork = getDefaultNetwork();
|
final NetworkAgentInfo oldDefaultNetwork = getDefaultNetwork();
|
||||||
@@ -7294,12 +7435,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// trying to connect if they know they cannot match it.
|
// 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
|
// 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?
|
// network. Think of a way to reduce this. Push netid->request mapping to each factory?
|
||||||
sendUpdatedScoreToFactories(event.mRequest.request, event.mNewNetwork);
|
sendUpdatedScoreToFactories(event);
|
||||||
|
|
||||||
if (null != event.mNewNetwork) {
|
if (null != event.mNewNetwork) {
|
||||||
notifyNetworkAvailable(event.mNewNetwork, event.mRequest);
|
notifyNetworkAvailable(event.mNewNetwork, event.mNetworkRequestInfo);
|
||||||
} else {
|
} else {
|
||||||
callCallbackForRequest(event.mRequest, event.mOldNetwork,
|
callCallbackForRequest(event.mNetworkRequestInfo, event.mOldNetwork,
|
||||||
ConnectivityManager.CALLBACK_LOST, 0);
|
ConnectivityManager.CALLBACK_LOST, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user