summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Plass <mplass@google.com>2020-04-10 08:37:19 -0700
committerMichael Plass <mplass@google.com>2020-04-20 14:36:53 +0000
commit9d1fa2cdb82d7435d25d88854726528962ca79c9 (patch)
tree3371e1c6d664ef9dbd81acb9388bd83a7e052ee4
parent1c93299eed327259785fd3a747d8abdec08397eb (diff)
Estimate the probability of getting internet
Use WifiScoreCard statistics to estimate how likely it is that a candidate BSSID will be able to provide internet access. Also hook up the success/failure stats for roaming. Bug: 111230798 Test: atest WifiScoreCardTest WifiCandidatesTest Change-Id: Ic344ce78c1544fb0f9be46a40e3900067cf5d991
-rw-r--r--service/java/com/android/server/wifi/WifiCandidates.java19
-rw-r--r--[-rwxr-xr-x]service/java/com/android/server/wifi/WifiNetworkScoreCache.java0
-rw-r--r--service/java/com/android/server/wifi/WifiScoreCard.java53
-rw-r--r--tests/wifitests/Android.bp6
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ConcreteCandidate.java13
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiCandidatesTest.java5
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java84
7 files changed, 163 insertions, 17 deletions
diff --git a/service/java/com/android/server/wifi/WifiCandidates.java b/service/java/com/android/server/wifi/WifiCandidates.java
index 24f814023..0513e5c1e 100644
--- a/service/java/com/android/server/wifi/WifiCandidates.java
+++ b/service/java/com/android/server/wifi/WifiCandidates.java
@@ -141,10 +141,14 @@ public class WifiCandidates {
*/
int getFrequency();
/**
- * Gets the predicted throughput in Mbps
+ * Gets the predicted throughput in Mbps.
*/
int getPredictedThroughputMbps();
/**
+ * Estimated probability of getting internet access (percent 0-100).
+ */
+ int getEstimatedPercentInternetAvailability();
+ /**
* Gets statistics from the scorecard.
*/
@Nullable WifiScoreCardProto.Signal getEventStatistics(WifiScoreCardProto.Event event);
@@ -171,6 +175,7 @@ public class WifiCandidates {
private final boolean mTrusted;
private final boolean mCarrierOrPrivileged;
private final int mPredictedThroughputMbps;
+ private final int mEstimatedPercentInternetAvailability;
CandidateImpl(Key key, WifiConfiguration config,
WifiScoreCard.PerBssid perBssid,
@@ -200,6 +205,8 @@ public class WifiCandidates {
this.mTrusted = config.trusted;
this.mCarrierOrPrivileged = isCarrierOrPrivileged;
this.mPredictedThroughputMbps = predictedThroughputMbps;
+ this.mEstimatedPercentInternetAvailability = perBssid == null ? 50 :
+ perBssid.estimatePercentInternetAvailability();
}
@Override
@@ -287,6 +294,11 @@ public class WifiCandidates {
return mPredictedThroughputMbps;
}
+ @Override
+ public int getEstimatedPercentInternetAvailability() {
+ return mEstimatedPercentInternetAvailability;
+ }
+
/**
* Accesses statistical information from the score card
*/
@@ -309,12 +321,13 @@ public class WifiCandidates {
+ ", ";
}
return "Candidate { "
- + "networkId = " + getNetworkConfigId() + ", "
+ + "config = " + getNetworkConfigId() + ", "
+ "bssid = " + key.bssid + ", "
- + "frequency = " + getFrequency() + ", "
+ + "freq = " + getFrequency() + ", "
+ "rssi = " + getScanRssi() + ", "
+ "Mbps = " + getPredictedThroughputMbps() + ", "
+ "nominator = " + getNominatorId() + ", "
+ + "pInternet = " + getEstimatedPercentInternetAvailability() + ", "
+ lastSelectionWeightString
+ (isCurrentBssid() ? "connected, " : "")
+ (isCurrentNetwork() ? "current, " : "")
diff --git a/service/java/com/android/server/wifi/WifiNetworkScoreCache.java b/service/java/com/android/server/wifi/WifiNetworkScoreCache.java
index 6bb3708ac..6bb3708ac 100755..100644
--- a/service/java/com/android/server/wifi/WifiNetworkScoreCache.java
+++ b/service/java/com/android/server/wifi/WifiNetworkScoreCache.java
diff --git a/service/java/com/android/server/wifi/WifiScoreCard.java b/service/java/com/android/server/wifi/WifiScoreCard.java
index fdf7a678b..071b9634d 100644
--- a/service/java/com/android/server/wifi/WifiScoreCard.java
+++ b/service/java/com/android/server/wifi/WifiScoreCard.java
@@ -205,7 +205,7 @@ public class WifiScoreCard {
*
* We want to gather statistics only on the first success.
*/
- private boolean mValidated = false;
+ private boolean mValidatedThisConnectionAtLeastOnce = false;
/**
* A note to ourself that we are attempting a network switch
@@ -279,7 +279,7 @@ public class WifiScoreCard {
}
mTsRoam = TS_NONE;
mPolled = false;
- mValidated = false;
+ mValidatedThisConnectionAtLeastOnce = false;
mNonlocalDisconnection = false;
}
@@ -363,9 +363,9 @@ public class WifiScoreCard {
* @param wifiInfo object holding relevant values
*/
public void noteValidationSuccess(@NonNull ExtendedWifiInfo wifiInfo) {
- if (mValidated) return; // Only once per connection
+ if (mValidatedThisConnectionAtLeastOnce) return; // Only once per connection
updatePerBssid(Event.VALIDATION_SUCCESS, wifiInfo);
- mValidated = true;
+ mValidatedThisConnectionAtLeastOnce = true;
doWrites();
}
@@ -375,7 +375,7 @@ public class WifiScoreCard {
* @param wifiInfo object holding relevant values
*/
public void noteValidationFailure(@NonNull ExtendedWifiInfo wifiInfo) {
- mValidated = false;
+ // VALIDATION_FAILURE is not currently recorded.
}
/**
@@ -448,10 +448,11 @@ public class WifiScoreCard {
* @param wifiInfo object holding relevant values
*/
public void noteIpReachabilityLost(@NonNull ExtendedWifiInfo wifiInfo) {
- updatePerBssid(Event.IP_REACHABILITY_LOST, wifiInfo);
if (mTsRoam > TS_NONE) {
mTsConnectionAttemptStart = mTsRoam; // just to update elapsed
updatePerBssid(Event.ROAM_FAILURE, wifiInfo);
+ } else {
+ updatePerBssid(Event.IP_REACHABILITY_LOST, wifiInfo);
}
// No need to call resetConnectionStateInternal() because
// resetConnectionState() will be called after WifiNative.disconnect() in ClientModeImpl
@@ -466,7 +467,7 @@ public class WifiScoreCard {
*
* @param wifiInfo object holding relevant values
*/
- public void noteRoam(@NonNull ExtendedWifiInfo wifiInfo) {
+ private void noteRoam(@NonNull ExtendedWifiInfo wifiInfo) {
updatePerBssid(Event.LAST_POLL_BEFORE_ROAM, wifiInfo);
mTsRoam = mClock.getElapsedSinceBootMillis();
}
@@ -479,6 +480,10 @@ public class WifiScoreCard {
*/
public void noteSupplicantStateChanging(@NonNull ExtendedWifiInfo wifiInfo,
SupplicantState state) {
+ if (state == SupplicantState.COMPLETED && wifiInfo.getSupplicantState() == state) {
+ // Our signal that a firmware roam has occurred
+ noteRoam(wifiInfo);
+ }
logd("Changing state to " + state + " " + wifiInfo);
}
@@ -788,6 +793,38 @@ public class WifiScoreCard {
}
merge(ap);
}
+
+ /**
+ * Estimates the probability of getting internet access, based on the
+ * device experience.
+ *
+ * @return a probability, expressed as a percentage in the range 0 to 100
+ */
+ public int estimatePercentInternetAvailability() {
+ // Initialize counts accoring to Laplace's rule of succession
+ int trials = 2;
+ int successes = 1;
+ // Aggregate over all of the frequencies
+ for (PerSignal s : mSignalForEventAndFrequency.values()) {
+ switch (s.event) {
+ case IP_CONFIGURATION_SUCCESS:
+ if (s.elapsedMs != null) {
+ trials += s.elapsedMs.count;
+ }
+ break;
+ case VALIDATION_SUCCESS:
+ if (s.elapsedMs != null) {
+ successes += s.elapsedMs.count;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ // Note that because of roaming it is possible to count successes
+ // without corresponding trials.
+ return Math.min(Math.max(Math.round(successes * 100.0f / trials), 0), 100);
+ }
}
/**
@@ -1712,7 +1749,7 @@ public class WifiScoreCard {
Preconditions.checkArgument(frequency == signal.getFrequency());
rssi.merge(signal.getRssi());
linkspeed.merge(signal.getLinkspeed());
- if (signal.hasElapsedMs()) {
+ if (elapsedMs != null && signal.hasElapsedMs()) {
elapsedMs.merge(signal.getElapsedMs());
}
return this;
diff --git a/tests/wifitests/Android.bp b/tests/wifitests/Android.bp
index 6ba8c908a..851a6016e 100644
--- a/tests/wifitests/Android.bp
+++ b/tests/wifitests/Android.bp
@@ -402,6 +402,9 @@ android_test {
"com.android.server.wifi.WifiCandidates",
"com.android.server.wifi.WifiCandidates$*",
"com.android.server.wifi.WifiCandidates.**",
+ "com.android.server.wifi.WifiCarrierInfoManager",
+ "com.android.server.wifi.WifiCarrierInfoManager$*",
+ "com.android.server.wifi.WifiCarrierInfoManager.**",
"com.android.server.wifi.WifiChannelUtilization",
"com.android.server.wifi.WifiChannelUtilization$*",
"com.android.server.wifi.WifiChannelUtilization.**",
@@ -933,9 +936,6 @@ android_test {
"com.android.server.wifi.util.StringUtil",
"com.android.server.wifi.util.StringUtil$*",
"com.android.server.wifi.util.StringUtil.**",
- "com.android.server.wifi.WifiCarrierInfoManager",
- "com.android.server.wifi.WifiCarrierInfoManager$*",
- "com.android.server.wifi.WifiCarrierInfoManager.**",
"com.android.server.wifi.util.TimedQuotaManager",
"com.android.server.wifi.util.TimedQuotaManager$*",
"com.android.server.wifi.util.TimedQuotaManager.**",
diff --git a/tests/wifitests/src/com/android/server/wifi/ConcreteCandidate.java b/tests/wifitests/src/com/android/server/wifi/ConcreteCandidate.java
index b95a1171b..37d2945cf 100644
--- a/tests/wifitests/src/com/android/server/wifi/ConcreteCandidate.java
+++ b/tests/wifitests/src/com/android/server/wifi/ConcreteCandidate.java
@@ -40,6 +40,7 @@ public final class ConcreteCandidate implements WifiCandidates.Candidate {
private int mScanRssi = -127;
private int mFrequency = -1;
private int mPredictedThroughputMbps = 0;
+ private int mEstimatedPercentInternetAvailability = 50;
private final Map<WifiScoreCardProto.Event, WifiScoreCardProto.Signal>
mEventStatisticsMap = new ArrayMap<>();
@@ -65,6 +66,8 @@ public final class ConcreteCandidate implements WifiCandidates.Candidate {
mScanRssi = candidate.getScanRssi();
mFrequency = candidate.getFrequency();
mPredictedThroughputMbps = candidate.getPredictedThroughputMbps();
+ mEstimatedPercentInternetAvailability = candidate
+ .getEstimatedPercentInternetAvailability();
for (WifiScoreCardProto.Event event : WifiScoreCardProto.Event.values()) {
WifiScoreCardProto.Signal signal = candidate.getEventStatistics(event);
if (signal != null) {
@@ -243,6 +246,16 @@ public final class ConcreteCandidate implements WifiCandidates.Candidate {
return mPredictedThroughputMbps;
}
+ public ConcreteCandidate setEstimatedPercentInternetAvailability(int percent) {
+ mEstimatedPercentInternetAvailability = percent;
+ return this;
+ }
+
+ @Override
+ public int getEstimatedPercentInternetAvailability() {
+ return mEstimatedPercentInternetAvailability;
+ }
+
public ConcreteCandidate setEventStatistics(
WifiScoreCardProto.Event event,
WifiScoreCardProto.Signal signal) {
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiCandidatesTest.java b/tests/wifitests/src/com/android/server/wifi/WifiCandidatesTest.java
index 7ce59c9ee..9ff064ed1 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiCandidatesTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiCandidatesTest.java
@@ -79,6 +79,7 @@ public class WifiCandidatesTest extends WifiBaseTest {
doReturn(mScanResult1).when(mScanDetail1).getScanResult();
doReturn(mScanResult2).when(mScanDetail2).getScanResult();
doReturn(mPerBssid).when(mWifiScoreCard).lookupBssid(any(), any());
+ doReturn(50).when(mPerBssid).estimatePercentInternetAvailability();
MockResources mResources = new MockResources();
mResources.setBoolean(R.bool.config_wifiSaeUpgradeEnabled, true);
doReturn(mResources).when(mContext).getResources();
@@ -182,13 +183,15 @@ public class WifiCandidatesTest extends WifiBaseTest {
*/
@Test
public void testCandidateToString() throws Exception {
+ doReturn(57).when(mPerBssid).estimatePercentInternetAvailability();
mWifiCandidates.add(mScanDetail1, mConfig1, 2, 0.0015001, false, 100);
WifiCandidates.Candidate c = mWifiCandidates.getGroupedCandidates()
.iterator().next().iterator().next();
String s = c.toString();
assertTrue(s, s.contains(" nominator = 2, "));
- assertTrue(s, s.contains(" networkId = " + mConfig1.networkId + ", "));
+ assertTrue(s, s.contains(" config = " + mConfig1.networkId + ", "));
assertTrue(s, s.contains(" lastSelectionWeight = 0.002, ")); // should be rounded
+ assertTrue(s, s.contains(" pInternet = 57, "));
for (String x : s.split(",")) {
if (x.startsWith("Candidate {")) x = x.substring("Candidate {".length());
if (x.endsWith(" }")) x = x.substring(0, x.length() - 2);
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java b/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java
index 3fc62609a..e5525c4c7 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java
@@ -39,6 +39,7 @@ import static org.mockito.Mockito.*;
import android.content.Context;
import android.net.MacAddress;
+import android.net.wifi.SupplicantState;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiSsid;
import android.util.Base64;
@@ -72,6 +73,7 @@ import java.util.List;
*/
@SmallTest
public class WifiScoreCardTest extends WifiBaseTest {
+
static final WifiSsid TEST_SSID_1 = WifiSsid.createFromAsciiEncoded("Joe's Place");
static final WifiSsid TEST_SSID_2 = WifiSsid.createFromAsciiEncoded("Poe's Ravn");
@@ -364,9 +366,10 @@ public class WifiScoreCardTest extends WifiBaseTest {
secondsPass(9900);
// Second validation success should not matter.
mWifiScoreCard.noteValidationSuccess(mWifiInfo);
+ mWifiInfo.setRssi(-88);
+ mWifiScoreCard.noteIpReachabilityLost(mWifiInfo);
mWifiScoreCard.noteWifiDisabled(mWifiInfo);
-
// Now verify
WifiScoreCard.PerBssid perBssid = mWifiScoreCard.fetchByBssid(TEST_BSSID_1);
assertEquals(1, perBssid.lookupSignal(Event.IP_CONFIGURATION_SUCCESS, 5805)
@@ -375,14 +378,91 @@ public class WifiScoreCardTest extends WifiBaseTest {
.elapsedMs.sum, TOL);
assertEquals(9999999.0, perBssid.lookupSignal(Event.WIFI_DISABLED, 5805)
.elapsedMs.maxValue, TOL);
- assertEquals(999.0, perBssid.lookupSignal(Event.FIRST_POLL_AFTER_CONNECTION, 5805)
+ assertEquals(999.0, perBssid.lookupSignal(Event.FIRST_POLL_AFTER_CONNECTION, 5805)
.elapsedMs.minValue, TOL);
assertEquals(99999.0, perBssid.lookupSignal(Event.VALIDATION_SUCCESS, 5805)
.elapsedMs.sum, TOL);
+ assertEquals(-88.0, perBssid.lookupSignal(Event.IP_REACHABILITY_LOST, 5805)
+ .rssi.sum, TOL);
assertNull(perBssid.lookupSignal(Event.SIGNAL_POLL, 5805).elapsedMs);
}
/**
+ * Firmware roam
+ */
+ @Test
+ public void testFirmwareRoam() throws Exception {
+ // Start out disconnected; start connecting
+ mWifiInfo.setBSSID(android.net.wifi.WifiInfo.DEFAULT_MAC_ADDRESS);
+ mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
+
+ // First poll has a bad RSSI
+ millisecondsPass(111);
+ mWifiInfo.setBSSID(TEST_BSSID_1.toString());
+ mWifiInfo.setSupplicantState(SupplicantState.COMPLETED);
+ mWifiInfo.setFrequency(5805);
+ mWifiInfo.setRssi(WifiInfo.INVALID_RSSI);
+
+ // A bit later, connection is complete (up through DHCP)
+ millisecondsPass(222);
+ mWifiInfo.setRssi(-55);
+ mWifiScoreCard.noteIpConfiguration(mWifiInfo);
+
+ millisecondsPass(666);
+ mWifiInfo.setRssi(-77);
+ // Rssi polls for 99 seconds
+ for (int i = 0; i < 99; i += 9) {
+ mWifiScoreCard.noteSignalPoll(mWifiInfo);
+ secondsPass(9);
+ }
+
+ // Make sure our simulated time adds up
+ assertEquals(mMilliSecondsSinceBoot, 99999);
+ // Validation success, rather late!
+ mWifiScoreCard.noteValidationSuccess(mWifiInfo);
+ // Simulate a successful roam
+ mWifiScoreCard.noteSupplicantStateChanging(mWifiInfo, SupplicantState.COMPLETED);
+ millisecondsPass(1);
+ mWifiInfo.setBSSID(TEST_BSSID_2.toString());
+ mWifiInfo.setRssi(-66);
+ mWifiInfo.setFrequency(2412);
+ mWifiInfo.setSupplicantState(SupplicantState.COMPLETED);
+ mWifiScoreCard.noteSupplicantStateChanged(mWifiInfo);
+ secondsPass(9);
+ assertEquals(mMilliSecondsSinceBoot, 109000);
+ mWifiScoreCard.noteSignalPoll(mWifiInfo);
+
+ // Simulate an unsuccessful roam
+ secondsPass(1);
+ mWifiInfo.setRssi(-74);
+ mWifiScoreCard.noteSignalPoll(mWifiInfo);
+ secondsPass(1);
+ mWifiScoreCard.noteSupplicantStateChanging(mWifiInfo, SupplicantState.COMPLETED);
+ mWifiInfo.setBSSID(TEST_BSSID_1.toString());
+ mWifiInfo.setFrequency(5805);
+ mWifiInfo.setSupplicantState(SupplicantState.COMPLETED);
+ mWifiScoreCard.noteSupplicantStateChanged(mWifiInfo);
+ secondsPass(3);
+ mWifiScoreCard.noteIpReachabilityLost(mWifiInfo);
+
+ // Now verify
+ WifiScoreCard.PerBssid perBssid = mWifiScoreCard.fetchByBssid(TEST_BSSID_1);
+ assertEquals(1, perBssid.lookupSignal(Event.IP_CONFIGURATION_SUCCESS, 5805)
+ .elapsedMs.count);
+ assertEquals(-77, perBssid.lookupSignal(Event.LAST_POLL_BEFORE_ROAM, 5805)
+ .rssi.minValue, TOL);
+ assertEquals(1, perBssid.lookupSignal(Event.ROAM_FAILURE, 5805)
+ .rssi.count);
+
+ assertEquals(67, perBssid.estimatePercentInternetAvailability());
+
+ perBssid = mWifiScoreCard.fetchByBssid(TEST_BSSID_2);
+ assertEquals(-66.0, perBssid.lookupSignal(Event.ROAM_SUCCESS, 2412)
+ .rssi.sum, TOL);
+ assertEquals(50, perBssid.estimatePercentInternetAvailability());
+ }
+
+ /**
* Constructs a protobuf form of AccessPoint example.
*/
private byte[] makeSerializedAccessPointExample() {