Support NetworkCallbacks based on signal strength.

Bug: 21405941
Change-Id: I2ed8a5aeb8dac464a4305671ed22abcacb485bc9
This commit is contained in:
Lorenzo Colitti
2015-07-06 23:50:27 +09:00
parent 493910ac44
commit 98a4c4d25b
5 changed files with 170 additions and 4 deletions

View File

@@ -184,6 +184,14 @@ public abstract class NetworkAgent extends Handler {
*/
public static final int EVENT_PACKET_KEEPALIVE = BASE + 13;
/**
* Sent by ConnectivityService to inform this network transport of signal strength thresholds
* that when crossed should trigger a system wakeup and a NetworkCapabilities update.
*
* obj = int[] describing signal strength thresholds.
*/
public static final int CMD_SET_SIGNAL_STRENGTH_THRESHOLDS = BASE + 14;
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score) {
this(looper, context, logTag, ni, nc, lp, score, null);
@@ -286,6 +294,11 @@ public abstract class NetworkAgent extends Handler {
stopPacketKeepalive(msg);
break;
}
case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: {
setSignalStrengthThresholds((int[]) msg.obj);
break;
}
}
}
@@ -445,6 +458,13 @@ public abstract class NetworkAgent extends Handler {
queueOrSendMessage(EVENT_PACKET_KEEPALIVE, slot, reason);
}
/**
* Called by ConnectivityService to inform this network transport of signal strength thresholds
* that when crossed should trigger a system wakeup and a NetworkCapabilities update.
*/
protected void setSignalStrengthThresholds(int[] thresholds) {
}
protected void log(String s) {
Log.d(LOG_TAG, "NetworkAgent: " + s);
}

View File

@@ -48,6 +48,7 @@ public final class NetworkCapabilities implements Parcelable {
mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
mNetworkSpecifier = nc.mNetworkSpecifier;
mSignalStrength = nc.mSignalStrength;
}
}
@@ -60,6 +61,7 @@ public final class NetworkCapabilities implements Parcelable {
mNetworkCapabilities = mTransportTypes = 0;
mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = 0;
mNetworkSpecifier = null;
mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
}
/**
@@ -300,6 +302,7 @@ public final class NetworkCapabilities implements Parcelable {
return "unknown non-requestable capabilities " + Long.toHexString(mNetworkCapabilities);
}
if (mLinkUpBandwidthKbps != 0 || mLinkDownBandwidthKbps != 0) return "link bandwidth";
if (hasSignalStrength()) return "signalStrength";
return null;
}
@@ -568,6 +571,68 @@ public final class NetworkCapabilities implements Parcelable {
}
}
/**
* Magic value that indicates no signal strength provided. A request specifying this value is
* always satisfied.
*
* @hide
*/
public static final int SIGNAL_STRENGTH_UNSPECIFIED = Integer.MIN_VALUE;
/**
* Signal strength. This is a signed integer, and higher values indicate better signal.
* The exact units are bearer-dependent. For example, Wi-Fi uses RSSI.
*/
private int mSignalStrength;
/**
* Sets the signal strength. This is a signed integer, with higher values indicating a stronger
* signal. The exact units are bearer-dependent. For example, Wi-Fi uses the same RSSI units
* reported by WifiManager.
* <p>
* Note that when used to register a network callback, this specifies the minimum acceptable
* signal strength. When received as the state of an existing network it specifies the current
* value. A value of code SIGNAL_STRENGTH_UNSPECIFIED} means no value when received and has no
* effect when requesting a callback.
*
* @param signalStrength the bearer-specific signal strength.
* @hide
*/
public void setSignalStrength(int signalStrength) {
mSignalStrength = signalStrength;
}
/**
* Returns {@code true} if this object specifies a signal strength.
*
* @hide
*/
public boolean hasSignalStrength() {
return mSignalStrength > SIGNAL_STRENGTH_UNSPECIFIED;
}
/**
* Retrieves the signal strength.
*
* @return The bearer-specific signal strength.
* @hide
*/
public int getSignalStrength() {
return mSignalStrength;
}
private void combineSignalStrength(NetworkCapabilities nc) {
this.mSignalStrength = Math.max(this.mSignalStrength, nc.mSignalStrength);
}
private boolean satisfiedBySignalStrength(NetworkCapabilities nc) {
return this.mSignalStrength <= nc.mSignalStrength;
}
private boolean equalsSignalStrength(NetworkCapabilities nc) {
return this.mSignalStrength == nc.mSignalStrength;
}
/**
* Combine a set of Capabilities to this one. Useful for coming up with the complete set
* @hide
@@ -577,6 +642,7 @@ public final class NetworkCapabilities implements Parcelable {
combineTransportTypes(nc);
combineLinkBandwidths(nc);
combineSpecifiers(nc);
combineSignalStrength(nc);
}
/**
@@ -593,7 +659,8 @@ public final class NetworkCapabilities implements Parcelable {
satisfiedByNetCapabilities(nc, onlyImmutable) &&
satisfiedByTransportTypes(nc) &&
(onlyImmutable || satisfiedByLinkBandwidths(nc)) &&
satisfiedBySpecifier(nc));
satisfiedBySpecifier(nc) &&
(onlyImmutable || satisfiedBySignalStrength(nc)));
}
/**
@@ -638,6 +705,7 @@ public final class NetworkCapabilities implements Parcelable {
return (equalsNetCapabilities(that) &&
equalsTransportTypes(that) &&
equalsLinkBandwidths(that) &&
equalsSignalStrength(that) &&
equalsSpecifier(that));
}
@@ -649,7 +717,8 @@ public final class NetworkCapabilities implements Parcelable {
((int)(mTransportTypes >> 32) * 7) +
(mLinkUpBandwidthKbps * 11) +
(mLinkDownBandwidthKbps * 13) +
(TextUtils.isEmpty(mNetworkSpecifier) ? 0 : mNetworkSpecifier.hashCode() * 17));
(TextUtils.isEmpty(mNetworkSpecifier) ? 0 : mNetworkSpecifier.hashCode() * 17) +
(mSignalStrength * 19));
}
@Override
@@ -663,7 +732,9 @@ public final class NetworkCapabilities implements Parcelable {
dest.writeInt(mLinkUpBandwidthKbps);
dest.writeInt(mLinkDownBandwidthKbps);
dest.writeString(mNetworkSpecifier);
dest.writeInt(mSignalStrength);
}
public static final Creator<NetworkCapabilities> CREATOR =
new Creator<NetworkCapabilities>() {
@Override
@@ -675,6 +746,7 @@ public final class NetworkCapabilities implements Parcelable {
netCap.mLinkUpBandwidthKbps = in.readInt();
netCap.mLinkDownBandwidthKbps = in.readInt();
netCap.mNetworkSpecifier = in.readString();
netCap.mSignalStrength = in.readInt();
return netCap;
}
@Override
@@ -731,6 +803,8 @@ public final class NetworkCapabilities implements Parcelable {
String specifier = (mNetworkSpecifier == null ?
"" : " Specifier: <" + mNetworkSpecifier + ">");
return "[" + transports + capabilities + upBand + dnBand + specifier + "]";
String signalStrength = (hasSignalStrength() ? " SignalStrength: " + mSignalStrength : "");
return "[" + transports + capabilities + upBand + dnBand + specifier + signalStrength + "]";
}
}

View File

@@ -185,6 +185,24 @@ public class NetworkRequest implements Parcelable {
mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
return this;
}
/**
* Sets the signal strength. This is a signed integer, with higher values indicating a
* stronger signal. The exact units are bearer-dependent. For example, Wi-Fi uses the same
* RSSI units reported by WifiManager.
* <p>
* Note that when used to register a network callback, this specifies the minimum acceptable
* signal strength. When received as the state of an existing network it specifies the
* current value. A value of {@code SIGNAL_STRENGTH_UNSPECIFIED} means no value when
* received and has no effect when requesting a callback.
*
* @param signalStrength the bearer-specific signal strength.
* @hide
*/
public Builder setSignalStrength(int signalStrength) {
mNetworkCapabilities.setSignalStrength(signalStrength);
return this;
}
}
// implement the Parcelable interface

View File

@@ -150,6 +150,8 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -1914,7 +1916,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
(NetworkCapabilities)msg.obj;
if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL) ||
networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
Slog.wtf(TAG, "BUG: " + nai + " has stateful capability.");
Slog.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
}
if (nai.created && !nai.networkCapabilities.equalImmutableCapabilities(
networkCapabilities)) {
@@ -2274,6 +2276,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
bestNetwork = network;
}
}
if (!nri.isRequest && network.satisfiesImmutableCapabilitiesOf(nri.request)) {
updateSignalStrengthThresholds(network);
}
}
if (bestNetwork != null) {
if (DBG) log("using " + bestNetwork.name());
@@ -2419,6 +2424,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
// if this listen request applies and remove it.
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
nai.networkRequests.remove(nri.request.requestId);
if (nai.satisfiesImmutableCapabilitiesOf(nri.request)) {
updateSignalStrengthThresholds(nai);
}
}
}
callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED);
@@ -3664,6 +3672,34 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
private int[] getSignalStrengthThresholds(NetworkAgentInfo nai) {
final SortedSet<Integer> thresholds = new TreeSet();
synchronized (nai) {
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
if (nri.request.networkCapabilities.hasSignalStrength() &&
nai.satisfiesImmutableCapabilitiesOf(nri.request)) {
thresholds.add(nri.request.networkCapabilities.getSignalStrength());
}
}
}
// We can't just do something like:
// return thresholds.toArray(new int[thresholds.size()]);
// because autoboxing does not work for primitive arrays.
final int[] out = new int[thresholds.size()];
int pos = 0;
for (Integer threshold : thresholds) {
out[pos] = threshold;
pos++;
}
return out;
}
private void updateSignalStrengthThresholds(NetworkAgentInfo nai) {
nai.asyncChannel.sendMessage(
android.net.NetworkAgent.CMD_SET_SIGNAL_STRENGTH_THRESHOLDS,
0, 0, getSignalStrengthThresholds(nai));
}
@Override
public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
@@ -4132,6 +4168,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
networkAgent.networkCapabilities = networkCapabilities;
}
rematchAllNetworksAndRequests(networkAgent, networkAgent.getCurrentScore(), nascent);
// TODO: reduce the number of callbacks where possible. For example, only send signal
// strength changes if the NetworkRequest used to register the callback specified a
// signalStrength.
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
}
@@ -4594,6 +4633,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
// TODO: support proxy per network.
}
// Whether a particular NetworkRequest listen should cause signal strength thresholds to
// be communicated to a particular NetworkAgent depends only on the network's immutable,
// capabilities, so it only needs to be done once on initial connect, not every time the
// network's capabilities change. Note that we do this before rematching the network,
// so we could decide to tear it down immediately afterwards. That's fine though - on
// disconnection NetworkAgents should stop any signal strength monitoring they have been
// doing.
updateSignalStrengthThresholds(networkAgent);
// Consider network even though it is not yet validated.
rematchNetworkAndRequests(networkAgent, NascentState.NOT_JUST_VALIDATED,
ReapUnvalidatedNetworks.REAP);

View File

@@ -128,6 +128,12 @@ public class NetworkAgentInfo {
request.networkCapabilities.satisfiedByNetworkCapabilities(networkCapabilities);
}
public boolean satisfiesImmutableCapabilitiesOf(NetworkRequest request) {
return created &&
request.networkCapabilities.satisfiedByImmutableNetworkCapabilities(
networkCapabilities);
}
public boolean isVPN() {
return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
}