[SP18] Poll network stats in OffloadController to support data warning am: bf6fa99b2a
Change-Id: Ib0549b36a1e5bf9a728c4187facd4caae6e6df2f
This commit is contained in:
@@ -23,6 +23,7 @@ import static android.net.NetworkStats.SET_DEFAULT;
|
||||
import static android.net.NetworkStats.TAG_NONE;
|
||||
import static android.net.NetworkStats.UID_ALL;
|
||||
import static android.net.NetworkStats.UID_TETHERING;
|
||||
import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
|
||||
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
@@ -76,6 +77,7 @@ public class OffloadController {
|
||||
private static final boolean DBG = false;
|
||||
private static final String ANYIP = "0.0.0.0";
|
||||
private static final ForwardedStats EMPTY_STATS = new ForwardedStats();
|
||||
private static final int DEFAULT_PERFORM_POLL_INTERVAL_MS = 5000;
|
||||
|
||||
@VisibleForTesting
|
||||
enum StatsType {
|
||||
@@ -115,6 +117,16 @@ public class OffloadController {
|
||||
// includes upstream interfaces that have a quota set.
|
||||
private HashMap<String, Long> mInterfaceQuotas = new HashMap<>();
|
||||
|
||||
// Tracking remaining alert quota. Unlike limit quota is subject to interface, the alert
|
||||
// quota is interface independent and global for tether offload. Note that this is only
|
||||
// accessed on the handler thread and in the constructor.
|
||||
private long mRemainingAlertQuota = QUOTA_UNLIMITED;
|
||||
// Runnable that used to schedule the next stats poll.
|
||||
private final Runnable mScheduledPollingTask = () -> {
|
||||
updateStatsForCurrentUpstream();
|
||||
maybeSchedulePollingStats();
|
||||
};
|
||||
|
||||
private int mNatUpdateCallbacksReceived;
|
||||
private int mNatUpdateNetlinkErrors;
|
||||
|
||||
@@ -240,6 +252,7 @@ public class OffloadController {
|
||||
mLog.log("tethering offload started");
|
||||
mNatUpdateCallbacksReceived = 0;
|
||||
mNatUpdateNetlinkErrors = 0;
|
||||
maybeSchedulePollingStats();
|
||||
}
|
||||
return isStarted;
|
||||
}
|
||||
@@ -255,6 +268,9 @@ public class OffloadController {
|
||||
mHwInterface.stopOffloadControl();
|
||||
mControlInitialized = false;
|
||||
mConfigInitialized = false;
|
||||
if (mHandler.hasCallbacks(mScheduledPollingTask)) {
|
||||
mHandler.removeCallbacks(mScheduledPollingTask);
|
||||
}
|
||||
if (wasStarted) mLog.log("tethering offload stopped");
|
||||
}
|
||||
|
||||
@@ -345,6 +361,11 @@ public class OffloadController {
|
||||
@Override
|
||||
public void onSetAlert(long quotaBytes) {
|
||||
// TODO: Ask offload HAL to notify alert without stopping traffic.
|
||||
// Post it to handler thread since it access remaining quota bytes.
|
||||
mHandler.post(() -> {
|
||||
updateAlertQuota(quotaBytes);
|
||||
maybeSchedulePollingStats();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,15 +387,66 @@ public class OffloadController {
|
||||
// the stats for each interface, and does not observe partial writes where rxBytes is
|
||||
// updated and txBytes is not.
|
||||
ForwardedStats diff = mHwInterface.getForwardedStats(iface);
|
||||
final long usedAlertQuota = diff.rxBytes + diff.txBytes;
|
||||
ForwardedStats base = mForwardedStats.get(iface);
|
||||
if (base != null) {
|
||||
diff.add(base);
|
||||
}
|
||||
|
||||
// Update remaining alert quota if it is still positive.
|
||||
if (mRemainingAlertQuota > 0 && usedAlertQuota > 0) {
|
||||
// Trim to zero if overshoot.
|
||||
final long newQuota = Math.max(mRemainingAlertQuota - usedAlertQuota, 0);
|
||||
updateAlertQuota(newQuota);
|
||||
}
|
||||
|
||||
mForwardedStats.put(iface, diff);
|
||||
// diff is a new object, just created by getForwardedStats(). Therefore, anyone reading from
|
||||
// mForwardedStats (i.e., any caller of getTetherStats) will see the new stats immediately.
|
||||
}
|
||||
|
||||
/**
|
||||
* Update remaining alert quota, fire the {@link NetworkStatsProvider#notifyAlertReached()}
|
||||
* callback when it reaches zero. This can be invoked either from service setting the alert, or
|
||||
* {@code maybeUpdateStats} when updating stats. Note that this can be only called on
|
||||
* handler thread.
|
||||
*
|
||||
* @param newQuota non-negative value to indicate the new quota, or
|
||||
* {@link NetworkStatsProvider#QUOTA_UNLIMITED} to indicate there is no
|
||||
* quota.
|
||||
*/
|
||||
private void updateAlertQuota(long newQuota) {
|
||||
if (newQuota < QUOTA_UNLIMITED) {
|
||||
throw new IllegalArgumentException("invalid quota value " + newQuota);
|
||||
}
|
||||
if (mRemainingAlertQuota == newQuota) return;
|
||||
|
||||
mRemainingAlertQuota = newQuota;
|
||||
if (mRemainingAlertQuota == 0) {
|
||||
mLog.i("notifyAlertReached");
|
||||
if (mStatsProvider != null) mStatsProvider.notifyAlertReached();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule polling if needed, this will be stopped if offload has been
|
||||
* stopped or remaining quota reaches zero or upstream is empty.
|
||||
* Note that this can be only called on handler thread.
|
||||
*/
|
||||
private void maybeSchedulePollingStats() {
|
||||
if (!isPollingStatsNeeded()) return;
|
||||
|
||||
if (mHandler.hasCallbacks(mScheduledPollingTask)) {
|
||||
mHandler.removeCallbacks(mScheduledPollingTask);
|
||||
}
|
||||
mHandler.postDelayed(mScheduledPollingTask, DEFAULT_PERFORM_POLL_INTERVAL_MS);
|
||||
}
|
||||
|
||||
private boolean isPollingStatsNeeded() {
|
||||
return started() && mRemainingAlertQuota > 0
|
||||
&& !TextUtils.isEmpty(currentUpstreamInterface());
|
||||
}
|
||||
|
||||
private boolean maybeUpdateDataLimit(String iface) {
|
||||
// setDataLimit may only be called while offload is occurring on this upstream.
|
||||
if (!started() || !TextUtils.equals(iface, currentUpstreamInterface())) {
|
||||
@@ -414,6 +486,8 @@ public class OffloadController {
|
||||
final String iface = currentUpstreamInterface();
|
||||
if (!TextUtils.isEmpty(iface)) mForwardedStats.putIfAbsent(iface, EMPTY_STATS);
|
||||
|
||||
maybeSchedulePollingStats();
|
||||
|
||||
// TODO: examine return code and decide what to do if programming
|
||||
// upstream parameters fails (probably just wait for a subsequent
|
||||
// onOffloadEvent() callback to tell us offload is available again and
|
||||
|
||||
@@ -308,7 +308,6 @@ public class OffloadHardwareInterface {
|
||||
return stats;
|
||||
}
|
||||
|
||||
mLog.log(logmsg + YIELDS + stats);
|
||||
return stats;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user