[MS46] Remove INetworkStatsSession usage from NetworkCycleDataLoader
Use public API instead. Also, since the android.app.usage.NetworkStats is not friendly for test injection, add several util methods for test injection. Test: make RunSettingsLibRoboTests \ ROBOTEST_FILTER=NetworkCycleDataLoaderTest Bug: 204830222 Change-Id: I1b8328010803050b5e1f176b47654ae18e8e1a0b
This commit is contained in:
@@ -16,23 +16,16 @@
|
||||
|
||||
package com.android.settingslib.net;
|
||||
|
||||
import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
|
||||
import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.usage.NetworkStats;
|
||||
import android.app.usage.NetworkStatsManager;
|
||||
import android.content.Context;
|
||||
import android.net.INetworkStatsService;
|
||||
import android.net.INetworkStatsSession;
|
||||
import android.net.NetworkPolicy;
|
||||
import android.net.NetworkPolicyManager;
|
||||
import android.net.NetworkStatsHistory;
|
||||
import android.net.NetworkTemplate;
|
||||
import android.net.TrafficStats;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.Pair;
|
||||
import android.util.Range;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.loader.content.AsyncTaskLoader;
|
||||
@@ -52,8 +45,6 @@ public abstract class NetworkCycleDataLoader<D> extends AsyncTaskLoader<D> {
|
||||
protected final NetworkTemplate mNetworkTemplate;
|
||||
private final NetworkPolicy mPolicy;
|
||||
private final ArrayList<Long> mCycles;
|
||||
@VisibleForTesting
|
||||
final INetworkStatsService mNetworkStatsService;
|
||||
|
||||
protected NetworkCycleDataLoader(Builder<?> builder) {
|
||||
super(builder.mContext);
|
||||
@@ -61,8 +52,6 @@ public abstract class NetworkCycleDataLoader<D> extends AsyncTaskLoader<D> {
|
||||
mCycles = builder.mCycles;
|
||||
mNetworkStatsManager = (NetworkStatsManager)
|
||||
builder.mContext.getSystemService(Context.NETWORK_STATS_SERVICE);
|
||||
mNetworkStatsService = INetworkStatsService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
|
||||
final NetworkPolicyEditor policyEditor =
|
||||
new NetworkPolicyEditor(NetworkPolicyManager.from(builder.mContext));
|
||||
policyEditor.read();
|
||||
@@ -112,23 +101,20 @@ public abstract class NetworkCycleDataLoader<D> extends AsyncTaskLoader<D> {
|
||||
|
||||
@VisibleForTesting
|
||||
void loadFourWeeksData() {
|
||||
if (mNetworkTemplate == null) return;
|
||||
final NetworkStats stats = mNetworkStatsManager.queryDetailsForDevice(
|
||||
mNetworkTemplate, Long.MIN_VALUE, Long.MAX_VALUE);
|
||||
try {
|
||||
final INetworkStatsSession networkSession = mNetworkStatsService.openSession();
|
||||
final NetworkStatsHistory networkHistory = networkSession.getHistoryForNetwork(
|
||||
mNetworkTemplate, FIELD_RX_BYTES | FIELD_TX_BYTES);
|
||||
final long historyStart = networkHistory.getStart();
|
||||
final long historyEnd = networkHistory.getEnd();
|
||||
final Range<Long> historyTimeRange = getTimeRangeOf(stats);
|
||||
|
||||
long cycleEnd = historyEnd;
|
||||
while (cycleEnd > historyStart) {
|
||||
long cycleEnd = historyTimeRange.getUpper();
|
||||
while (cycleEnd > historyTimeRange.getLower()) {
|
||||
final long cycleStart = cycleEnd - (DateUtils.WEEK_IN_MILLIS * 4);
|
||||
recordUsage(cycleStart, cycleEnd);
|
||||
cycleEnd = cycleStart;
|
||||
}
|
||||
|
||||
TrafficStats.closeQuietly(networkSession);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Empty history, ignore.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,6 +155,32 @@ public abstract class NetworkCycleDataLoader<D> extends AsyncTaskLoader<D> {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@VisibleForTesting
|
||||
Range getTimeRangeOf(@NonNull NetworkStats stats) {
|
||||
long start = Long.MAX_VALUE;
|
||||
long end = Long.MIN_VALUE;
|
||||
while (hasNextBucket(stats)) {
|
||||
final NetworkStats.Bucket bucket = getNextBucket(stats);
|
||||
start = Math.min(start, bucket.getStartTimeStamp());
|
||||
end = Math.max(end, bucket.getEndTimeStamp());
|
||||
}
|
||||
return new Range(start, end);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean hasNextBucket(@NonNull NetworkStats stats) {
|
||||
return stats.hasNextBucket();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@VisibleForTesting
|
||||
NetworkStats.Bucket getNextBucket(@NonNull NetworkStats stats) {
|
||||
NetworkStats.Bucket bucket = new NetworkStats.Bucket();
|
||||
stats.getNextBucket(bucket);
|
||||
return bucket;
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
|
||||
public ArrayList<Long> getCycles() {
|
||||
return mCycles;
|
||||
|
||||
@@ -16,24 +16,24 @@
|
||||
|
||||
package com.android.settingslib.net;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static android.app.usage.NetworkStats.Bucket.UID_ALL;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
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.annotation.NonNull;
|
||||
import android.app.usage.NetworkStats;
|
||||
import android.app.usage.NetworkStatsManager;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.INetworkStatsService;
|
||||
import android.net.INetworkStatsSession;
|
||||
import android.net.NetworkPolicy;
|
||||
import android.net.NetworkPolicyManager;
|
||||
import android.net.NetworkStatsHistory;
|
||||
import android.net.NetworkTemplate;
|
||||
import android.os.RemoteException;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.Range;
|
||||
|
||||
@@ -49,6 +49,8 @@ import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class NetworkCycleDataLoaderTest {
|
||||
@@ -63,8 +65,6 @@ public class NetworkCycleDataLoaderTest {
|
||||
private NetworkPolicy mPolicy;
|
||||
@Mock
|
||||
private Iterator<Range<ZonedDateTime>> mIterator;
|
||||
@Mock
|
||||
private INetworkStatsService mNetworkStatsService;
|
||||
|
||||
private NetworkCycleDataTestLoader mLoader;
|
||||
|
||||
@@ -132,20 +132,24 @@ public class NetworkCycleDataLoaderTest {
|
||||
verify(mLoader).recordUsage(nowInMs, nowInMs);
|
||||
}
|
||||
|
||||
private NetworkStats.Bucket makeMockBucket(int uid, long rxBytes, long txBytes,
|
||||
long start, long end) {
|
||||
NetworkStats.Bucket ret = mock(NetworkStats.Bucket.class);
|
||||
when(ret.getUid()).thenReturn(uid);
|
||||
when(ret.getRxBytes()).thenReturn(rxBytes);
|
||||
when(ret.getTxBytes()).thenReturn(txBytes);
|
||||
when(ret.getStartTimeStamp()).thenReturn(start);
|
||||
when(ret.getEndTimeStamp()).thenReturn(end);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadFourWeeksData_shouldRecordUsageForLast4Weeks() throws RemoteException {
|
||||
public void loadFourWeeksData_shouldRecordUsageForLast4Weeks() {
|
||||
mLoader = spy(new NetworkCycleDataTestLoader(mContext));
|
||||
ReflectionHelpers.setField(mLoader, "mNetworkStatsService", mNetworkStatsService);
|
||||
final INetworkStatsSession networkSession = mock(INetworkStatsSession.class);
|
||||
when(mNetworkStatsService.openSession()).thenReturn(networkSession);
|
||||
final NetworkStatsHistory networkHistory = mock(NetworkStatsHistory.class);
|
||||
when(networkSession.getHistoryForNetwork(nullable(NetworkTemplate.class), anyInt()))
|
||||
.thenReturn(networkHistory);
|
||||
final long now = System.currentTimeMillis();
|
||||
final long fourWeeksAgo = now - (DateUtils.WEEK_IN_MILLIS * 4);
|
||||
final long twoDaysAgo = now - (DateUtils.DAY_IN_MILLIS * 2);
|
||||
when(networkHistory.getStart()).thenReturn(twoDaysAgo);
|
||||
when(networkHistory.getEnd()).thenReturn(now);
|
||||
mLoader.addBucket(makeMockBucket(UID_ALL, 123, 456, twoDaysAgo, now));
|
||||
|
||||
mLoader.loadFourWeeksData();
|
||||
|
||||
@@ -173,10 +177,31 @@ public class NetworkCycleDataLoaderTest {
|
||||
verify(mLoader).recordUsage(thirtyDaysAgo, twentyDaysAgo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTimeRangeOf() {
|
||||
mLoader = spy(new NetworkCycleDataTestLoader(mContext));
|
||||
// If empty, new Range(MAX_VALUE, MIN_VALUE) will be constructed. Hence, the function
|
||||
// should throw.
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> mLoader.getTimeRangeOf(mock(NetworkStats.class)));
|
||||
|
||||
mLoader.addBucket(makeMockBucket(UID_ALL, 123, 456, 0, 10));
|
||||
// Feed the function with unused NetworkStats. The actual data injection is
|
||||
// done by addBucket.
|
||||
assertEquals(new Range(0L, 10L), mLoader.getTimeRangeOf(mock(NetworkStats.class)));
|
||||
|
||||
mLoader.addBucket(makeMockBucket(UID_ALL, 123, 456, 0, 10));
|
||||
mLoader.addBucket(makeMockBucket(UID_ALL, 123, 456, 30, 40));
|
||||
mLoader.addBucket(makeMockBucket(UID_ALL, 123, 456, 10, 25));
|
||||
assertEquals(new Range(0L, 40L), mLoader.getTimeRangeOf(mock(NetworkStats.class)));
|
||||
}
|
||||
|
||||
public class NetworkCycleDataTestLoader extends NetworkCycleDataLoader<List<NetworkCycleData>> {
|
||||
private final Queue<NetworkStats.Bucket> mMockedBuckets = new LinkedBlockingQueue<>();
|
||||
|
||||
private NetworkCycleDataTestLoader(Context context) {
|
||||
super(NetworkCycleDataLoader.builder(mContext));
|
||||
super(NetworkCycleDataLoader.builder(mContext)
|
||||
.setNetworkTemplate(mock(NetworkTemplate.class)));
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@@ -188,5 +213,19 @@ public class NetworkCycleDataLoaderTest {
|
||||
List<NetworkCycleData> getCycleUsage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addBucket(NetworkStats.Bucket bucket) {
|
||||
mMockedBuckets.add(bucket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNextBucket(@NonNull NetworkStats unused) {
|
||||
return !mMockedBuckets.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkStats.Bucket getNextBucket(@NonNull NetworkStats unused) {
|
||||
return mMockedBuckets.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user