use of com.android.server.connectivity.NetworkAgentInfo in project platform_frameworks_base by android.
the class ConnectivityService method rematchNetworkAndRequests.
// Handles a network appearing or improving its score.
//
// - Evaluates all current NetworkRequests that can be
// satisfied by newNetwork, and reassigns to newNetwork
// any such requests for which newNetwork is the best.
//
// - Lingers any validated Networks that as a result are no longer
// needed. A network is needed if it is the best network for
// one or more NetworkRequests, or if it is a VPN.
//
// - Tears down newNetwork if it just became validated
// but turns out to be unneeded.
//
// - If reapUnvalidatedNetworks==REAP, tears down unvalidated
// networks that have no chance (i.e. even if validated)
// of becoming the highest scoring network.
//
// NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy,
// it does not remove NetworkRequests that other Networks could better satisfy.
// If you need to handle decreases in score, use {@link rematchAllNetworksAndRequests}.
// This function should be used when possible instead of {@code rematchAllNetworksAndRequests}
// as it performs better by a factor of the number of Networks.
//
// @param newNetwork is the network to be matched against NetworkRequests.
// @param reapUnvalidatedNetworks indicates if an additional pass over all networks should be
// performed to tear down unvalidated networks that have no chance (i.e. even if
// validated) of becoming the highest scoring network.
private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, ReapUnvalidatedNetworks reapUnvalidatedNetworks, long now) {
if (!newNetwork.everConnected)
return;
boolean keep = newNetwork.isVPN();
boolean isNewDefault = false;
NetworkAgentInfo oldDefaultNetwork = null;
final boolean wasBackgroundNetwork = newNetwork.isBackgroundNetwork();
final int score = newNetwork.getCurrentScore();
if (VDBG)
log("rematching " + newNetwork.name());
// Find and migrate to this Network any NetworkRequests for
// which this network is now the best.
ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();
ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<NetworkRequestInfo>();
NetworkCapabilities nc = newNetwork.networkCapabilities;
if (VDBG)
log(" network has: " + nc);
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
// requests or not, and doesn't affect the network's score.
if (nri.request.isListen())
continue;
final NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
final boolean satisfies = newNetwork.satisfies(nri.request);
if (newNetwork == currentNetwork && satisfies) {
if (VDBG) {
log("Network " + newNetwork.name() + " was already satisfying" + " request " + nri.request.requestId + ". No change.");
}
keep = true;
continue;
}
// check if it satisfies the NetworkCapabilities
if (VDBG)
log(" checking if request is satisfied: " + nri.request);
if (satisfies) {
// this request
if (VDBG) {
log("currentScore = " + (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) + ", newScore = " + score);
}
if (currentNetwork == null || currentNetwork.getCurrentScore() < score) {
if (VDBG)
log("rematch for " + newNetwork.name());
if (currentNetwork != null) {
if (VDBG)
log(" accepting network in place of " + currentNetwork.name());
currentNetwork.removeRequest(nri.request.requestId);
currentNetwork.lingerRequest(nri.request, now, mLingerDelayMs);
affectedNetworks.add(currentNetwork);
} else {
if (VDBG)
log(" accepting network in place of null");
}
newNetwork.unlingerRequest(nri.request);
mNetworkForRequestId.put(nri.request.requestId, newNetwork);
if (!newNetwork.addRequest(nri.request)) {
Slog.wtf(TAG, "BUG: " + newNetwork.name() + " already has " + nri.request);
}
addedRequests.add(nri);
keep = true;
// Tell NetworkFactories about the new score, so they can stop
// trying to connect if they know they cannot match it.
// TODO - this could get expensive if we have alot of requests for this
// network. Think about if there is a way to reduce this. Push
// netid->request mapping to each factory?
sendUpdatedScoreToFactories(nri.request, score);
if (isDefaultRequest(nri)) {
isNewDefault = true;
oldDefaultNetwork = currentNetwork;
if (currentNetwork != null) {
mLingerMonitor.noteLingerDefaultNetwork(currentNetwork, newNetwork);
}
}
}
} else if (newNetwork.isSatisfyingRequest(nri.request.requestId)) {
// longer satisfies "nri" when "currentNetwork" does not equal "newNetwork".
if (DBG) {
log("Network " + newNetwork.name() + " stopped satisfying" + " request " + nri.request.requestId);
}
newNetwork.removeRequest(nri.request.requestId);
if (currentNetwork == newNetwork) {
mNetworkForRequestId.remove(nri.request.requestId);
sendUpdatedScoreToFactories(nri.request, 0);
} else {
Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " + newNetwork.name() + " without updating mNetworkForRequestId or factories!");
}
// TODO: Technically, sending CALLBACK_LOST here is
// incorrect if there is a replacement network currently
// connected that can satisfy nri, which is a request
// (not a listen). However, the only capability that can both
// a) be requested and b) change is NET_CAPABILITY_TRUSTED,
// so this code is only incorrect for a network that loses
// the TRUSTED capability, which is a rare case.
callCallbackForRequest(nri, newNetwork, ConnectivityManager.CALLBACK_LOST, 0);
}
}
if (isNewDefault) {
// Notify system services that this network is up.
makeDefault(newNetwork);
// Log 0 -> X and Y -> X default network transitions, where X is the new default.
logDefaultNetworkEvent(newNetwork, oldDefaultNetwork);
synchronized (ConnectivityService.this) {
// to reconnect over the new network
if (mNetTransitionWakeLock.isHeld()) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_CLEAR_NET_TRANSITION_WAKELOCK, mNetTransitionWakeLockSerialNumber, 0), 1000);
}
}
}
if (!newNetwork.networkCapabilities.equalRequestableCapabilities(nc)) {
Slog.wtf(TAG, String.format("BUG: %s changed requestable capabilities during rematch: %s -> %s", nc, newNetwork.networkCapabilities));
}
if (newNetwork.getCurrentScore() != score) {
Slog.wtf(TAG, String.format("BUG: %s changed score during rematch: %d -> %d", score, newNetwork.getCurrentScore()));
}
// Second pass: process all listens.
if (wasBackgroundNetwork != newNetwork.isBackgroundNetwork()) {
// If the network went from background to foreground or vice versa, we need to update
// its foreground state. It is safe to do this after rematching the requests because
// NET_CAPABILITY_FOREGROUND does not affect requests, as is not a requestable
// capability and does not affect the network's score (see the Slog.wtf call above).
updateCapabilities(score, newNetwork, newNetwork.networkCapabilities);
} else {
processListenRequests(newNetwork, false);
}
// before LegacyTypeTracker sends legacy broadcasts
for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);
// available callback for newNetwork.
for (NetworkAgentInfo nai : affectedNetworks) {
updateLingerState(nai, now);
}
// Possibly unlinger newNetwork. Unlingering a network does not send any callbacks so it
// does not need to be done in any particular order.
updateLingerState(newNetwork, now);
if (isNewDefault) {
// the new one connected.
if (oldDefaultNetwork != null) {
mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(), oldDefaultNetwork, true);
}
mDefaultInetConditionPublished = newNetwork.lastValidated ? 100 : 0;
mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
notifyLockdownVpn(newNetwork);
}
if (keep) {
// TODO: Avoid redoing this; this must only be done once when a network comes online.
try {
final IBatteryStats bs = BatteryStatsService.getService();
final int type = newNetwork.networkInfo.getType();
final String baseIface = newNetwork.linkProperties.getInterfaceName();
bs.noteNetworkInterfaceType(baseIface, type);
for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) {
final String stackedIface = stacked.getInterfaceName();
bs.noteNetworkInterfaceType(stackedIface, type);
NetworkStatsFactory.noteStackedIface(stackedIface, baseIface);
}
} catch (RemoteException ignored) {
}
// This is on top of the multiple intent sequencing referenced in the todo above.
for (int i = 0; i < newNetwork.numNetworkRequests(); i++) {
NetworkRequest nr = newNetwork.requestAt(i);
if (nr.legacyType != TYPE_NONE && nr.isRequest()) {
// legacy type tracker filters out repeat adds
mLegacyTypeTracker.add(nr.legacyType, newNetwork);
}
}
// newNetwork to the tracker explicitly (it's a no-op if it has already been added).
if (newNetwork.isVPN()) {
mLegacyTypeTracker.add(TYPE_VPN, newNetwork);
}
}
if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) {
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
if (unneeded(nai, UnneededFor.TEARDOWN)) {
if (nai.getLingerExpiry() > 0) {
// This network has active linger timers and no requests, but is not
// lingering. Linger it.
//
// One way (the only way?) this can happen if this network is unvalidated
// and became unneeded due to another network improving its score to the
// point where this network will no longer be able to satisfy any requests
// even if it validates.
updateLingerState(nai, now);
} else {
if (DBG)
log("Reaping " + nai.name());
teardownUnneededNetwork(nai);
}
}
}
}
}
use of com.android.server.connectivity.NetworkAgentInfo in project platform_frameworks_base by android.
the class ConnectivityService method rematchAllNetworksAndRequests.
/**
* Attempt to rematch all Networks with NetworkRequests. This may result in Networks
* being disconnected.
* @param changed If only one Network's score or capabilities have been modified since the last
* time this function was called, pass this Network in this argument, otherwise pass
* null.
* @param oldScore If only one Network has been changed but its NetworkCapabilities have not
* changed, pass in the Network's score (from getCurrentScore()) prior to the change via
* this argument, otherwise pass {@code changed.getCurrentScore()} or 0 if
* {@code changed} is {@code null}. This is because NetworkCapabilities influence a
* network's score.
*/
private void rematchAllNetworksAndRequests(NetworkAgentInfo changed, int oldScore) {
// TODO: This may get slow. The "changed" parameter is provided for future optimization
// to avoid the slowness. It is not simply enough to process just "changed", for
// example in the case where "changed"'s score decreases and another network should begin
// satifying a NetworkRequest that "changed" currently satisfies.
// Optimization: Only reprocess "changed" if its score improved. This is safe because it
// can only add more NetworkRequests satisfied by "changed", and this is exactly what
// rematchNetworkAndRequests() handles.
final long now = SystemClock.elapsedRealtime();
if (changed != null && oldScore < changed.getCurrentScore()) {
rematchNetworkAndRequests(changed, ReapUnvalidatedNetworks.REAP, now);
} else {
final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray(new NetworkAgentInfo[mNetworkAgentInfos.size()]);
// Rematch higher scoring networks first to prevent requests first matching a lower
// scoring network and then a higher scoring network, which could produce multiple
// callbacks and inadvertently unlinger networks.
Arrays.sort(nais);
for (NetworkAgentInfo nai : nais) {
rematchNetworkAndRequests(nai, // rematched.
(nai != nais[nais.length - 1]) ? ReapUnvalidatedNetworks.DONT_REAP : ReapUnvalidatedNetworks.REAP, now);
}
}
}
use of com.android.server.connectivity.NetworkAgentInfo in project platform_frameworks_base by android.
the class ConnectivityService method registerNetworkAgent.
public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkMisc networkMisc) {
enforceConnectivityInternalPermission();
// TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
// satisfies mDefaultRequest.
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), new Network(reserveNetId()), new NetworkInfo(networkInfo), new LinkProperties(linkProperties), new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);
synchronized (this) {
nai.networkMonitor.systemReady = mSystemReady;
}
addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network, networkInfo.getExtraInfo());
if (DBG)
log("registerNetworkAgent " + nai);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
return nai.network.netId;
}
use of com.android.server.connectivity.NetworkAgentInfo in project platform_frameworks_base by android.
the class ConnectivityService method requestBandwidthUpdate.
@Override
public boolean requestBandwidthUpdate(Network network) {
enforceAccessPermission();
NetworkAgentInfo nai = null;
if (network == null) {
return false;
}
synchronized (mNetworkForNetId) {
nai = mNetworkForNetId.get(network.netId);
}
if (nai != null) {
nai.asyncChannel.sendMessage(android.net.NetworkAgent.CMD_REQUEST_BANDWIDTH_UPDATE);
return true;
}
return false;
}
use of com.android.server.connectivity.NetworkAgentInfo in project platform_frameworks_base by android.
the class ConnectivityService method dumpNetworkDiagnostics.
private void dumpNetworkDiagnostics(IndentingPrintWriter pw) {
final List<NetworkDiagnostics> netDiags = new ArrayList<NetworkDiagnostics>();
final long DIAG_TIME_MS = 5000;
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
// Start gathering diagnostic information.
netDiags.add(new NetworkDiagnostics(nai.network, // Must be a copy.
new LinkProperties(nai.linkProperties), DIAG_TIME_MS));
}
for (NetworkDiagnostics netDiag : netDiags) {
pw.println();
netDiag.waitForMeasurements();
netDiag.dump(pw);
}
}
Aggregations