summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorKai Shi <kaishi@google.com>2020-02-19 18:43:58 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2020-02-19 18:43:58 +0000
commit56471f597e58543ef21c82b10b781b34a6ed5df6 (patch)
treed757f614d73e7d4812e81efcd111c450b30a9015 /service
parent29c1c28ab297ed0d629a5440b4c9cfa736923064 (diff)
parent4a2fb2b8eabb847a25df501e7faa7d5e0ab56ae1 (diff)
Merge changes Ic92cadbd,I93dc5aa6
* changes: add ConnectionDurationStats to WifiMetrics Add isCellularDataAvailable() in WifiDataStall
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/ClientModeImpl.java2
-rw-r--r--service/java/com/android/server/wifi/WifiDataStall.java109
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java4
-rw-r--r--service/java/com/android/server/wifi/WifiMetrics.java62
-rw-r--r--service/proto/src/metrics.proto14
5 files changed, 169 insertions, 22 deletions
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index 0577212a0..6bb0153ce 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -3449,6 +3449,7 @@ public class ClientModeImpl extends StateMachine {
mWifiDiagnostics.startLogging(mInterfaceName);
mMboOceController.enable();
+ mWifiDataStall.enablePhoneStateListener();
/**
* Enable bluetooth coexistence scan mode when bluetooth connection is active.
@@ -3486,6 +3487,7 @@ public class ClientModeImpl extends StateMachine {
mWifiDiagnostics.stopLogging(mInterfaceName);
mMboOceController.disable();
+ mWifiDataStall.disablePhoneStateListener();
if (mIpClient != null && mIpClient.shutdown()) {
// Block to make sure IpClient has really shut down, lest cleanup
// race with, say, bringup code over in tethering.
diff --git a/service/java/com/android/server/wifi/WifiDataStall.java b/service/java/com/android/server/wifi/WifiDataStall.java
index d7f3a61d9..b71aca921 100644
--- a/service/java/com/android/server/wifi/WifiDataStall.java
+++ b/service/java/com/android/server/wifi/WifiDataStall.java
@@ -18,12 +18,18 @@ package com.android.server.wifi;
import static com.android.server.wifi.util.InformationElementUtil.BssLoad.CHANNEL_UTILIZATION_SCALE;
+import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager.DeviceMobilityState;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
import android.util.Log;
import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiIsUnusableEvent;
import com.android.server.wifi.util.InformationElementUtil.BssLoad;
+import com.android.wifi.resources.R;
/**
* Looks for Wifi data stalls
@@ -32,7 +38,7 @@ public class WifiDataStall {
private static final String TAG = "WifiDataStall";
private boolean mVerboseLoggingEnabled = false;
// Maximum time gap between two WifiLinkLayerStats to trigger a data stall
- public static final long MAX_MS_DELTA_FOR_DATA_STALL = 60 * 1000; // 1 minute
+ public static final int MAX_MS_DELTA_FOR_DATA_STALL = 60 * 1000; // 1 minute
// Maximum time that a data stall start time stays valid.
public static final long VALIDITY_PERIOD_OF_DATA_STALL_START_MS = 30 * 1000; // 0.5 minutes
// Default Tx packet error rate when there is no Tx attempt
@@ -42,11 +48,15 @@ public class WifiDataStall {
public static final int DEFAULT_CCA_LEVEL_ABOVE_2G = CHANNEL_UTILIZATION_SCALE * 6 / 100;
// Minimum time interval in ms between two link layer stats cache updates
private static final int LLSTATS_CACHE_UPDATE_INTERVAL_MIN_MS = 6 * 1000;
+ // Maximum time margin between two link layer stats for connection duration update
+ public static final int MAX_TIME_MARGIN_LAST_TWO_POLLS_MS = 200;
- FrameworkFacade mFacade;
+ private final FrameworkFacade mFacade;
private final DeviceConfigFacade mDeviceConfigFacade;
private final WifiMetrics mWifiMetrics;
+ private final Context mContext;
private final WifiChannelUtilization mWifiChannelUtilization;
+ private TelephonyManager mTelephonyManager;
private int mLastFrequency = -1;
private String mLastBssid;
@@ -57,17 +67,60 @@ public class WifiDataStall {
private long mLastTxBytes;
private long mLastRxBytes;
private boolean mIsThroughputSufficient = true;
+ private boolean mIsCellularDataAvailable = false;
+ private final PhoneStateListener mPhoneStateListener;
+ private boolean mPhoneStateListenerEnabled = false;
- public WifiDataStall(FrameworkFacade facade, WifiMetrics wifiMetrics,
- DeviceConfigFacade deviceConfigFacade,
- WifiChannelUtilization wifiChannelUtilization, Clock clock) {
+ public WifiDataStall(FrameworkFacade facade, WifiMetrics wifiMetrics, Context context,
+ DeviceConfigFacade deviceConfigFacade, WifiChannelUtilization wifiChannelUtilization,
+ Clock clock, Handler handler) {
mFacade = facade;
mDeviceConfigFacade = deviceConfigFacade;
mWifiMetrics = wifiMetrics;
+ mContext = context;
mClock = clock;
mWifiChannelUtilization = wifiChannelUtilization;
mWifiChannelUtilization.init(null);
mWifiChannelUtilization.setCacheUpdateIntervalMs(LLSTATS_CACHE_UPDATE_INTERVAL_MIN_MS);
+ mPhoneStateListener = new PhoneStateListener(new HandlerExecutor(handler)) {
+ @Override
+ public void onDataConnectionStateChanged(int state, int networkType) {
+ if (state == TelephonyManager.DATA_CONNECTED) {
+ mIsCellularDataAvailable = true;
+ } else if (state == TelephonyManager.DATA_DISCONNECTED) {
+ mIsCellularDataAvailable = false;
+ } else {
+ Log.e(TAG, "onDataConnectionStateChanged unexpected State: " + state);
+ return;
+ }
+ logd("Cellular Data: " + mIsCellularDataAvailable);
+ }
+ };
+ }
+
+ /**
+ * Enable phone state listener
+ */
+ public void enablePhoneStateListener() {
+ if (mTelephonyManager == null) {
+ mTelephonyManager = (TelephonyManager) mContext
+ .getSystemService(Context.TELEPHONY_SERVICE);
+ }
+ if (mTelephonyManager != null && !mPhoneStateListenerEnabled) {
+ mPhoneStateListenerEnabled = true;
+ mTelephonyManager.listen(mPhoneStateListener,
+ PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
+ }
+ }
+
+ /**
+ * Disable phone state listener
+ */
+ public void disablePhoneStateListener() {
+ if (mTelephonyManager != null && mPhoneStateListenerEnabled) {
+ mPhoneStateListenerEnabled = false;
+ mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+ }
}
/**
@@ -96,8 +149,16 @@ public class WifiDataStall {
}
/**
- * Checks for data stall and throughput sufficiency by looking at link layer stats and L3
- * byte counts
+ * Check if cellular data is available
+ * @return true if it is available and false otherwise
+ */
+ public boolean isCellularDataAvailable() {
+ return mIsCellularDataAvailable;
+ }
+
+ /**
+ * Update data stall detection, check throughput sufficiency and report wifi health stat
+ * with the latest link layer stats
* @param oldStats second most recent WifiLinkLayerStats
* @param newStats most recent WifiLinkLayerStats
* @param wifiInfo WifiInfo for current connection
@@ -130,14 +191,14 @@ public class WifiDataStall {
+ newStats.rxmpdu_vi + newStats.rxmpdu_vo)
- (oldStats.rxmpdu_be + oldStats.rxmpdu_bk
+ oldStats.rxmpdu_vi + oldStats.rxmpdu_vo);
- long timeMsDelta = newStats.timeStampInMs - oldStats.timeStampInMs;
+ int timeDeltaLastTwoPollsMs = (int) (newStats.timeStampInMs - oldStats.timeStampInMs);
long totalTxDelta = txSuccessDelta + txRetriesDelta;
boolean isTxTrafficHigh = (totalTxDelta * 1000)
- > (mDeviceConfigFacade.getTxPktPerSecondThr() * timeMsDelta);
+ > (mDeviceConfigFacade.getTxPktPerSecondThr() * timeDeltaLastTwoPollsMs);
boolean isRxTrafficHigh = (rxSuccessDelta * 1000)
- > (mDeviceConfigFacade.getTxPktPerSecondThr() * timeMsDelta);
- if (timeMsDelta < 0
+ > (mDeviceConfigFacade.getTxPktPerSecondThr() * timeDeltaLastTwoPollsMs);
+ if (timeDeltaLastTwoPollsMs < 0
|| txSuccessDelta < 0
|| txRetriesDelta < 0
|| txBadDelta < 0
@@ -149,7 +210,7 @@ public class WifiDataStall {
}
mWifiMetrics.updateWifiIsUnusableLinkLayerStats(txSuccessDelta, txRetriesDelta,
- txBadDelta, rxSuccessDelta, timeMsDelta);
+ txBadDelta, rxSuccessDelta, timeDeltaLastTwoPollsMs);
int txLinkSpeedMbps = wifiInfo.getLinkSpeed();
int rxLinkSpeedMbps = wifiInfo.getRxLinkSpeedMbps();
@@ -187,7 +248,15 @@ public class WifiDataStall {
}
mIsThroughputSufficient = isThroughputSufficientInternal(txTputKbps, rxTputKbps,
- isTxTrafficHigh, isRxTrafficHigh, timeMsDelta);
+ isTxTrafficHigh, isRxTrafficHigh, timeDeltaLastTwoPollsMs);
+
+ int maxTimeDeltaMs = mContext.getResources().getInteger(
+ R.integer.config_wifiPollRssiIntervalMilliseconds)
+ + MAX_TIME_MARGIN_LAST_TWO_POLLS_MS;
+ if (timeDeltaLastTwoPollsMs > 0 && timeDeltaLastTwoPollsMs <= maxTimeDeltaMs) {
+ mWifiMetrics.incrementConnectionDuration(timeDeltaLastTwoPollsMs,
+ mIsThroughputSufficient, mIsCellularDataAvailable);
+ }
boolean possibleDataStallTx = isTxTputLow
|| ccaLevel >= mDeviceConfigFacade.getDataStallCcaLevelThr()
@@ -198,15 +267,15 @@ public class WifiDataStall {
boolean dataStallTx = isTxTrafficHigh ? possibleDataStallTx : mDataStallTx;
boolean dataStallRx = isRxTrafficHigh ? possibleDataStallRx : mDataStallRx;
- return detectConsecutiveTwoDataStalls(timeMsDelta, dataStallTx, dataStallRx);
+ return detectConsecutiveTwoDataStalls(timeDeltaLastTwoPollsMs, dataStallTx, dataStallRx);
}
// Data stall event is triggered if there are consecutive Tx and/or Rx data stalls
// 1st data stall should be preceded by no data stall
// Reset mDataStallStartTimeMs to -1 if currently there is no Tx or Rx data stall
- private int detectConsecutiveTwoDataStalls(long timeMsDelta,
+ private int detectConsecutiveTwoDataStalls(int timeDeltaLastTwoPollsMs,
boolean dataStallTx, boolean dataStallRx) {
- if (timeMsDelta >= MAX_MS_DELTA_FOR_DATA_STALL) {
+ if (timeDeltaLastTwoPollsMs >= MAX_MS_DELTA_FOR_DATA_STALL) {
return WifiIsUnusableEvent.TYPE_UNKNOWN;
}
@@ -271,18 +340,18 @@ public class WifiDataStall {
}
private boolean isThroughputSufficientInternal(int l2TxTputKbps, int l2RxTputKbps,
- boolean isTxTrafficHigh, boolean isRxTrafficHigh, long timeMsDelta) {
+ boolean isTxTrafficHigh, boolean isRxTrafficHigh, int timeDeltaLastTwoPollsMs) {
long txBytes = mFacade.getTotalTxBytes() - mFacade.getMobileTxBytes();
long rxBytes = mFacade.getTotalRxBytes() - mFacade.getMobileRxBytes();
- if (timeMsDelta > MAX_MS_DELTA_FOR_DATA_STALL
+ if (timeDeltaLastTwoPollsMs > MAX_MS_DELTA_FOR_DATA_STALL
|| mLastTxBytes == 0 || mLastRxBytes == 0) {
mLastTxBytes = txBytes;
mLastRxBytes = rxBytes;
return true;
}
- int l3TxTputKbps = (int) ((txBytes - mLastTxBytes) * 8 / timeMsDelta);
- int l3RxTputKbps = (int) ((rxBytes - mLastRxBytes) * 8 / timeMsDelta);
+ int l3TxTputKbps = (int) ((txBytes - mLastTxBytes) * 8 / timeDeltaLastTwoPollsMs);
+ int l3RxTputKbps = (int) ((rxBytes - mLastRxBytes) * 8 / timeDeltaLastTwoPollsMs);
mLastTxBytes = txBytes;
mLastRxBytes = rxBytes;
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index e6dcb6368..71f8b7073 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -317,8 +317,8 @@ public class WifiInjector {
mContext, this, mWifiNative, mBuildProperties,
new LastMileLogger(this), mClock);
mWifiChannelUtilizationConnected = new WifiChannelUtilization(mClock);
- mWifiDataStall = new WifiDataStall(mFrameworkFacade, mWifiMetrics, mDeviceConfigFacade,
- mWifiChannelUtilizationConnected, mClock);
+ mWifiDataStall = new WifiDataStall(mFrameworkFacade, mWifiMetrics, mContext,
+ mDeviceConfigFacade, mWifiChannelUtilizationConnected, mClock, wifiHandler);
mWifiMetrics.setWifiDataStall(mWifiDataStall);
mLinkProbeManager = new LinkProbeManager(mClock, mWifiNative, mWifiMetrics,
mFrameworkFacade, wifiHandler, mContext);
diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java
index e6c5058be..688857a70 100644
--- a/service/java/com/android/server/wifi/WifiMetrics.java
+++ b/service/java/com/android/server/wifi/WifiMetrics.java
@@ -439,6 +439,9 @@ public class WifiMetrics {
/** Mapping of failure code to the respective passpoint provision failure count. */
private final IntCounter mPasspointProvisionFailureCounts = new IntCounter();
+ // Connection duration stats collected while link layer stats reports are on
+ private final ConnectionDurationStats mConnectionDurationStats = new ConnectionDurationStats();
+
@VisibleForTesting
static class NetworkSelectionExperimentResults {
public static final int MAX_CHOICES = 10;
@@ -531,6 +534,49 @@ public class WifiMetrics {
}
}
+ class ConnectionDurationStats {
+ private int mConnectionDurationCellularDataOffMs;
+ private int mConnectionDurationSufficientThroughputMs;
+ private int mConnectionDurationInSufficientThroughputMs;
+
+ public WifiMetricsProto.ConnectionDurationStats toProto() {
+ WifiMetricsProto.ConnectionDurationStats proto =
+ new WifiMetricsProto.ConnectionDurationStats();
+ proto.totalTimeSufficientThroughputMs = mConnectionDurationSufficientThroughputMs;
+ proto.totalTimeInsufficientThroughputMs = mConnectionDurationInSufficientThroughputMs;
+ proto.totalTimeCellularDataOffMs = mConnectionDurationCellularDataOffMs;
+ return proto;
+ }
+ public void clear() {
+ mConnectionDurationCellularDataOffMs = 0;
+ mConnectionDurationSufficientThroughputMs = 0;
+ mConnectionDurationInSufficientThroughputMs = 0;
+ }
+ public void incrementDurationCount(int timeDeltaLastTwoPollsMs,
+ boolean isThroughputSufficient, boolean isCellularDataAvailable) {
+ if (!isCellularDataAvailable) {
+ mConnectionDurationCellularDataOffMs += timeDeltaLastTwoPollsMs;
+ } else {
+ if (isThroughputSufficient) {
+ mConnectionDurationSufficientThroughputMs += timeDeltaLastTwoPollsMs;
+ } else {
+ mConnectionDurationInSufficientThroughputMs += timeDeltaLastTwoPollsMs;
+ }
+ }
+ }
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("connectionDurationSufficientThroughputMs=")
+ .append(mConnectionDurationSufficientThroughputMs)
+ .append(", connectionDurationInSufficientThroughputMs=")
+ .append(mConnectionDurationInSufficientThroughputMs)
+ .append(", connectionDurationCellularDataOffMs=")
+ .append(mConnectionDurationCellularDataOffMs);
+ return sb.toString();
+ }
+ }
+
/**
* Log event, tracking the start time, end time and result of a wireless connection attempt.
*/
@@ -2897,6 +2943,8 @@ public class WifiMetrics {
pw.println("mWifiLogProto.rxLinkSpeedCount5gHigh=" + mRxLinkSpeedCount5gHigh);
pw.println("mWifiLogProto.numIpRenewalFailure="
+ mWifiLogProto.numIpRenewalFailure);
+ pw.println("mWifiLogProto.connectionDurationStats="
+ + mConnectionDurationStats.toString());
}
}
}
@@ -3458,6 +3506,7 @@ public class WifiMetrics {
mWifiLogProto.healthMonitorMetrics = healthMonitorMetrics;
}
mWifiLogProto.bssidBlocklistStats = mBssidBlocklistStats.toProto();
+ mWifiLogProto.connectionDurationStats = mConnectionDurationStats.toProto();
}
}
@@ -3653,6 +3702,8 @@ public class WifiMetrics {
mPasspointProvisionFailureCounts.clear();
mNumProvisionSuccess = 0;
mBssidBlocklistStats = new BssidBlocklistStats();
+ mConnectionDurationStats.clear();
+
}
}
@@ -5210,4 +5261,15 @@ public class WifiMetrics {
mExperimentValues.dataStallCcaLevelThr = ccaLevel;
}
}
+
+ /**
+ * Increment connection duration while link layer stats report are on
+ */
+ public void incrementConnectionDuration(int timeDeltaLastTwoPollsMs,
+ boolean isThroughputSufficient, boolean isCellularDataAvailable) {
+ synchronized (mLock) {
+ mConnectionDurationStats.incrementDurationCount(timeDeltaLastTwoPollsMs,
+ isThroughputSufficient, isCellularDataAvailable);
+ }
+ }
}
diff --git a/service/proto/src/metrics.proto b/service/proto/src/metrics.proto
index 8989b3bfa..10f61965f 100644
--- a/service/proto/src/metrics.proto
+++ b/service/proto/src/metrics.proto
@@ -582,6 +582,9 @@ message WifiLog {
// Metrics related to the BssidBlocklistMonitor
optional BssidBlocklistStats bssid_blocklist_stats = 159;
+
+ // Connection duration under various health conditions
+ optional ConnectionDurationStats connection_duration_stats = 160;
}
// Information that gets logged for every WiFi connection.
@@ -2785,3 +2788,14 @@ message HealthMonitorMetrics {
// Number of networks with sufficient connection attempts for both current and previous builds
optional int32 num_network_sufficient_recent_prev_stats = 5;
}
+
+// Connection duration statistics collected under various health conditions
+// while Wifi link layer stats report are on
+message ConnectionDurationStats {
+ // Total time with sufficient Wifi throughput and with cellular data on
+ optional int32 total_time_sufficient_throughput_ms = 1;
+ // Total time with insufficient Wifi throughput and with cellular data on
+ optional int32 total_time_insufficient_throughput_ms = 2;
+ // Total time with cellular data off
+ optional int32 total_time_cellular_data_off_ms = 3;
+}