Merge "Change to get network history from NetworkStatsManager."

This commit is contained in:
Doris Ling
2018-10-08 17:24:37 +00:00
committed by Android (Google) Code Review
5 changed files with 186 additions and 87 deletions

View File

@@ -24,6 +24,8 @@ import static android.telephony.TelephonyManager.SIM_STATE_READY;
import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
import android.app.usage.NetworkStats.Bucket;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetworkStatsService;
@@ -37,6 +39,7 @@ import android.os.ServiceManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.format.DateUtils;
import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.Range;
@@ -51,6 +54,8 @@ import java.util.Locale;
public class DataUsageController {
private static final String TAG = "DataUsageController";
@VisibleForTesting
static final String DATA_USAGE_V2 = "settings_data_usage_v2";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final int FIELDS = FIELD_RX_BYTES | FIELD_TX_BYTES;
private static final StringBuilder PERIOD_BUILDER = new StringBuilder(50);
@@ -62,6 +67,7 @@ public class DataUsageController {
private final ConnectivityManager mConnectivityManager;
private final INetworkStatsService mStatsService;
private final NetworkPolicyManager mPolicyManager;
private final NetworkStatsManager mNetworkStatsManager;
private INetworkStatsSession mSession;
private Callback mCallback;
@@ -74,6 +80,7 @@ public class DataUsageController {
mStatsService = INetworkStatsService.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
mPolicyManager = NetworkPolicyManager.from(mContext);
mNetworkStatsManager = context.getSystemService(NetworkStatsManager.class);
}
public void setNetworkController(NetworkNameProvider networkController) {
@@ -89,6 +96,7 @@ public class DataUsageController {
}
@VisibleForTesting
@Deprecated
INetworkStatsSession getSession() {
if (mSession == null) {
try {
@@ -128,71 +136,72 @@ public class DataUsageController {
}
public DataUsageInfo getDataUsageInfo(NetworkTemplate template) {
final INetworkStatsSession session = getSession();
if (session == null) {
return warn("no stats session");
}
final NetworkPolicy policy = findNetworkPolicy(template);
try {
final NetworkStatsHistory history = session.getHistoryForNetwork(template, FIELDS);
final long now = System.currentTimeMillis();
final long start, end;
final Iterator<Range<ZonedDateTime>> it =
(policy != null) ? policy.cycleIterator() : null;
if (it != null && it.hasNext()) {
final Range<ZonedDateTime> cycle = it.next();
start = cycle.getLower().toInstant().toEpochMilli();
end = cycle.getUpper().toInstant().toEpochMilli();
} else {
// period = last 4 wks
end = now;
start = now - DateUtils.WEEK_IN_MILLIS * 4;
}
final long callStart = System.currentTimeMillis();
final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null);
final long callEnd = System.currentTimeMillis();
if (DEBUG) Log.d(TAG, String.format("history call from %s to %s now=%s took %sms: %s",
new Date(start), new Date(end), new Date(now), callEnd - callStart,
historyEntryToString(entry)));
if (entry == null) {
return warn("no entry data");
}
final long totalBytes = entry.rxBytes + entry.txBytes;
final DataUsageInfo usage = new DataUsageInfo();
usage.startDate = start;
usage.usageLevel = totalBytes;
usage.period = formatDateRange(start, end);
usage.cycleStart = start;
usage.cycleEnd = end;
if (policy != null) {
usage.limitLevel = policy.limitBytes > 0 ? policy.limitBytes : 0;
usage.warningLevel = policy.warningBytes > 0 ? policy.warningBytes : 0;
} else {
usage.warningLevel = getDefaultWarningLevel();
}
if (usage != null && mNetworkController != null) {
usage.carrier = mNetworkController.getMobileDataNetworkName();
}
return usage;
} catch (RemoteException e) {
return warn("remote call failed");
final long now = System.currentTimeMillis();
final long start, end;
final Iterator<Range<ZonedDateTime>> it = (policy != null) ? policy.cycleIterator() : null;
if (it != null && it.hasNext()) {
final Range<ZonedDateTime> cycle = it.next();
start = cycle.getLower().toInstant().toEpochMilli();
end = cycle.getUpper().toInstant().toEpochMilli();
} else {
// period = last 4 wks
end = now;
start = now - DateUtils.WEEK_IN_MILLIS * 4;
}
final long totalBytes;
final long callStart = System.currentTimeMillis();
if (FeatureFlagUtils.isEnabled(mContext, DATA_USAGE_V2)) {
totalBytes = getUsageLevel(template, start, end);
} else {
totalBytes = getUsageLevel(template, start, end, now);
}
if (totalBytes < 0L) {
return warn("no entry data");
}
final DataUsageInfo usage = new DataUsageInfo();
usage.startDate = start;
usage.usageLevel = totalBytes;
usage.period = formatDateRange(start, end);
usage.cycleStart = start;
usage.cycleEnd = end;
if (policy != null) {
usage.limitLevel = policy.limitBytes > 0 ? policy.limitBytes : 0;
usage.warningLevel = policy.warningBytes > 0 ? policy.warningBytes : 0;
} else {
usage.warningLevel = getDefaultWarningLevel();
}
if (usage != null && mNetworkController != null) {
usage.carrier = mNetworkController.getMobileDataNetworkName();
}
return usage;
}
/**
* Get the total usage level recorded in the network history
* @param template the network template to retrieve the network history
* @return the total usage level recorded in the network history
* @return the total usage level recorded in the network history or -1L if there is error
* retrieving the data.
*/
public long getHistoriclUsageLevel(NetworkTemplate template) {
public long getHistoricalUsageLevel(NetworkTemplate template) {
if (FeatureFlagUtils.isEnabled(mContext, DATA_USAGE_V2)) {
return getUsageLevel(template, 0L /* start */, System.currentTimeMillis() /* end */);
} else {
final long now = System.currentTimeMillis();
return getUsageLevel(template, 0L /* start */, now /* end */, now);
}
}
@Deprecated
private long getUsageLevel(NetworkTemplate template, long start, long end, long now) {
final INetworkStatsSession session = getSession();
if (session != null) {
try {
final NetworkStatsHistory history = session.getHistoryForNetwork(template, FIELDS);
final long now = System.currentTimeMillis();
final NetworkStatsHistory.Entry entry =
history.getValues(0L /* start */, now /* end */, now, null /* recycle */);
final NetworkStatsHistory history =
session.getHistoryForNetwork(template, FIELDS);
final NetworkStatsHistory.Entry entry = history.getValues(
start, end, System.currentTimeMillis() /* now */, null /* recycle */);
if (entry != null) {
return entry.rxBytes + entry.txBytes;
}
@@ -201,7 +210,21 @@ public class DataUsageController {
Log.w(TAG, "Failed to get data usage, remote call failed");
}
}
return 0L;
return -1L;
}
private long getUsageLevel(NetworkTemplate template, long start, long end) {
try {
final Bucket bucket = mNetworkStatsManager.querySummaryForDevice(
getNetworkType(template), getActiveSubscriberId(mContext), start, end);
if (bucket != null) {
return bucket.getRxBytes() + bucket.getTxBytes();
}
Log.w(TAG, "Failed to get data usage, no entry data");
} catch (RemoteException e) {
Log.w(TAG, "Failed to get data usage, remote call failed");
}
return -1L;
}
private NetworkPolicy findNetworkPolicy(NetworkTemplate template) {
@@ -218,6 +241,7 @@ public class DataUsageController {
return null;
}
@Deprecated
private static String historyEntryToString(NetworkStatsHistory.Entry entry) {
return entry == null ? null : new StringBuilder("Entry[")
.append("bucketDuration=").append(entry.bucketDuration)
@@ -231,6 +255,17 @@ public class DataUsageController {
.append(']').toString();
}
private static String statsBucketToString(Bucket bucket) {
return bucket == null ? null : new StringBuilder("Entry[")
.append("bucketDuration=").append(bucket.getEndTimeStamp() - bucket.getStartTimeStamp())
.append(",bucketStart=").append(bucket.getStartTimeStamp())
.append(",rxBytes=").append(bucket.getRxBytes())
.append(",rxPackets=").append(bucket.getRxPackets())
.append(",txBytes=").append(bucket.getTxBytes())
.append(",txPackets=").append(bucket.getTxPackets())
.append(']').toString();
}
public void setMobileDataEnabled(boolean enabled) {
Log.d(TAG, "setMobileDataEnabled: enabled=" + enabled);
mTelephonyManager.setDataEnabled(enabled);
@@ -249,6 +284,25 @@ public class DataUsageController {
return mTelephonyManager.getDataEnabled();
}
static int getNetworkType(NetworkTemplate networkTemplate) {
if (networkTemplate == null) {
return ConnectivityManager.TYPE_NONE;
}
final int matchRule = networkTemplate.getMatchRule();
switch (matchRule) {
case NetworkTemplate.MATCH_MOBILE:
case NetworkTemplate.MATCH_MOBILE_WILDCARD:
return ConnectivityManager.TYPE_MOBILE;
case NetworkTemplate.MATCH_WIFI:
case NetworkTemplate.MATCH_WIFI_WILDCARD:
return ConnectivityManager.TYPE_WIFI;
case NetworkTemplate.MATCH_ETHERNET:
return ConnectivityManager.TYPE_ETHERNET;
default:
return ConnectivityManager.TYPE_MOBILE;
}
}
private static String getActiveSubscriberId(Context context) {
final TelephonyManager tele = TelephonyManager.from(context);
final String actualSubscriberId = tele.getSubscriberId(

View File

@@ -43,9 +43,9 @@ public class NetworkCycleChartDataLoader
@Override
void recordUsage(long start, long end) {
try {
final NetworkStats stats = mNetworkStatsManager.querySummary(
final NetworkStats.Bucket bucket = mNetworkStatsManager.querySummaryForDevice(
mNetworkType, mSubId, start, end);
final long total = getTotalUsage(stats);
final long total = bucket == null ? 0L : bucket.getRxBytes() + bucket.getTxBytes();
if (total > 0L) {
final NetworkCycleChartData.Builder builder = new NetworkCycleChartData.Builder();
builder.setUsageBuckets(getUsageBuckets(start, end))
@@ -80,9 +80,11 @@ public class NetworkCycleChartDataLoader
while (bucketEnd <= end) {
long usage = 0L;
try {
final NetworkStats stats = mNetworkStatsManager.querySummary(
final NetworkStats.Bucket bucket = mNetworkStatsManager.querySummaryForDevice(
mNetworkType, mSubId, bucketStart, bucketEnd);
usage = getTotalUsage(stats);
if (bucket != null) {
usage = bucket.getRxBytes() + bucket.getTxBytes();
}
} catch (RemoteException e) {
Log.e(TAG, "Exception querying network detail.", e);
}

View File

@@ -176,31 +176,11 @@ public abstract class NetworkCycleDataLoader<D> extends AsyncTaskLoader<D> {
public Builder<T> setNetworkTemplate(NetworkTemplate template) {
mNetworkTemplate = template;
setNetworkType();
mNetworkType = DataUsageController.getNetworkType(template);
return this;
}
public abstract T build();
private void setNetworkType() {
if (mNetworkTemplate != null) {
final int matchRule = mNetworkTemplate.getMatchRule();
switch (matchRule) {
case NetworkTemplate.MATCH_MOBILE:
case NetworkTemplate.MATCH_MOBILE_WILDCARD:
mNetworkType = ConnectivityManager.TYPE_MOBILE;
break;
case NetworkTemplate.MATCH_WIFI:
mNetworkType = ConnectivityManager.TYPE_WIFI;
break;
case NetworkTemplate.MATCH_ETHERNET:
mNetworkType = ConnectivityManager.TYPE_ETHERNET;
break;
default:
mNetworkType = ConnectivityManager.TYPE_MOBILE;
}
}
}
}
}

View File

@@ -24,16 +24,23 @@ import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.usage.NetworkStats;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetworkStatsSession;
import android.net.NetworkStatsHistory;
import android.net.NetworkStatsHistory.Entry;
import android.net.NetworkTemplate;
import android.os.RemoteException;
import android.telephony.TelephonyManager;
import android.text.format.DateUtils;
import android.util.FeatureFlagUtils;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
@@ -47,8 +54,14 @@ import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsLibRobolectricTestRunner.class)
public class DataUsageControllerTest {
private static final String SUB_ID = "Test Subscriber";
@Mock
private INetworkStatsSession mSession;
@Mock
private TelephonyManager mTelephonyManager;
@Mock
private NetworkStatsManager mNetworkStatsManager;
private Context mContext;
private DataUsageController mController;
@@ -63,13 +76,14 @@ public class DataUsageControllerTest {
new NetworkStatsHistory(DateUtils.DAY_IN_MILLIS /* bucketDuration */));
doReturn(mNetworkStatsHistory)
.when(mSession).getHistoryForNetwork(any(NetworkTemplate.class), anyInt());
doReturn(SUB_ID).when(mTelephonyManager).getSubscriberId(anyInt());
}
@Test
public void getHistoriclUsageLevel_noNetworkSession_shouldReturn0() {
public void getHistoricalUsageLevel_noNetworkSession_shouldReturnNegative1() {
doReturn(null).when(mController).getSession();
assertThat(mController.getHistoriclUsageLevel(null /* template */)).isEqualTo(0L);
assertThat(mController.getHistoricalUsageLevel(null /* template */)).isEqualTo(-1L);
}
@@ -77,13 +91,13 @@ public class DataUsageControllerTest {
public void getHistoriclUsageLevel_noUsageData_shouldReturn0() {
doReturn(mSession).when(mController).getSession();
assertThat(mController.getHistoriclUsageLevel(NetworkTemplate.buildTemplateWifiWildcard()))
assertThat(mController.getHistoricalUsageLevel(NetworkTemplate.buildTemplateWifiWildcard()))
.isEqualTo(0L);
}
@Test
public void getHistoriclUsageLevel_hasUsageData_shouldReturnTotalUsage() {
public void getHistoricalUsageLevel_hasUsageData_shouldReturnTotalUsage() {
doReturn(mSession).when(mController).getSession();
final long receivedBytes = 743823454L;
final long transmittedBytes = 16574289L;
@@ -94,8 +108,57 @@ public class DataUsageControllerTest {
when(mNetworkStatsHistory.getValues(eq(0L), anyLong(), anyLong(), nullable(Entry.class)))
.thenReturn(entry);
assertThat(mController.getHistoriclUsageLevel(NetworkTemplate.buildTemplateWifiWildcard()))
assertThat(mController.getHistoricalUsageLevel(NetworkTemplate.buildTemplateWifiWildcard()))
.isEqualTo(receivedBytes + transmittedBytes);
}
@Test
public void getHistoricalUsageLevel_v2_shouldQuerySummaryForDevice() throws Exception {
final Context context = mock(Context.class);
FeatureFlagUtils.setEnabled(context, DataUsageController.DATA_USAGE_V2, true);
when(context.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
when(context.getSystemService(NetworkStatsManager.class)).thenReturn(mNetworkStatsManager);
final DataUsageController controller = new DataUsageController(context);
controller.getHistoricalUsageLevel(NetworkTemplate.buildTemplateWifiWildcard());
verify(mNetworkStatsManager).querySummaryForDevice(eq(ConnectivityManager.TYPE_WIFI),
eq(SUB_ID), eq(0L) /* startTime */, anyLong() /* endTime */);
}
@Test
public void getHistoricalUsageLevel_v2NoUsageData_shouldReturn0() throws Exception {
final Context context = mock(Context.class);
FeatureFlagUtils.setEnabled(context, DataUsageController.DATA_USAGE_V2, true);
when(context.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
when(context.getSystemService(NetworkStatsManager.class)).thenReturn(mNetworkStatsManager);
when(mNetworkStatsManager.querySummaryForDevice(eq(ConnectivityManager.TYPE_WIFI),
eq(SUB_ID), eq(0L) /* startTime */, anyLong() /* endTime */))
.thenReturn(mock(NetworkStats.Bucket.class));
final DataUsageController controller = new DataUsageController(context);
assertThat(controller.getHistoricalUsageLevel(NetworkTemplate.buildTemplateWifiWildcard()))
.isEqualTo(0L);
}
@Test
public void getHistoricalUsageLevel_v2HasUsageData_shouldReturnTotalUsage()
throws Exception {
final Context context = mock(Context.class);
FeatureFlagUtils.setEnabled(context, DataUsageController.DATA_USAGE_V2, true);
when(context.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
when(context.getSystemService(NetworkStatsManager.class)).thenReturn(mNetworkStatsManager);
final long receivedBytes = 743823454L;
final long transmittedBytes = 16574289L;
final NetworkStats.Bucket bucket = mock(NetworkStats.Bucket.class);
when(bucket.getRxBytes()).thenReturn(receivedBytes);
when(bucket.getTxBytes()).thenReturn(transmittedBytes);
when(mNetworkStatsManager.querySummaryForDevice(eq(ConnectivityManager.TYPE_WIFI),
eq(SUB_ID), eq(0L) /* startTime */, anyLong() /* endTime */)).thenReturn(bucket);
final DataUsageController controller = new DataUsageController(context);
assertThat(controller.getHistoricalUsageLevel(NetworkTemplate.buildTemplateWifiWildcard()))
.isEqualTo(receivedBytes + transmittedBytes);
}
}

View File

@@ -58,7 +58,7 @@ public class NetworkCycleChartDataLoaderTest {
}
@Test
public void recordUsage_shouldQueryNetworkSummary() throws RemoteException {
public void recordUsage_shouldQueryNetworkSummaryForDevice() throws RemoteException {
final long end = System.currentTimeMillis();
final long start = end - (DateUtils.WEEK_IN_MILLIS * 4);
final int networkType = ConnectivityManager.TYPE_MOBILE;
@@ -68,6 +68,6 @@ public class NetworkCycleChartDataLoaderTest {
mLoader.recordUsage(start, end);
verify(mNetworkStatsManager).querySummary(networkType, subId, start, end);
verify(mNetworkStatsManager).querySummaryForDevice(networkType, subId, start, end);
}
}