summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Doris Ling <dling@google.com> 2018-09-19 13:25:37 -0700
committer Doris Ling <dling@google.com> 2018-09-26 13:28:50 -0700
commit0d8e4b43a3520f1a0b890cfa7f78558c0054461a (patch)
treedce8cd760a6d16dbce52081c3e0b50bbe19e8eca
parent16cd61459c97d8456d77da18cae947af46f73887 (diff)
Add loader for netork cycle data.
- Add the loader to retrieve usage data for each billing cycle. - Rename NetworkStatsSummaryLoader and change its param from subscription id to subscriber id. Bug: 111751694 Test: make RunSettingsLibRoboTests Change-Id: I0b68a0805222098bd6d52e762887cef2fcea667a
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleData.java69
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java219
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java (renamed from packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsDetailLoader.java)23
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java123
5 files changed, 425 insertions, 14 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java
index c3241bbd2123..74bd97f40ff7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java
@@ -36,7 +36,12 @@ import com.android.settingslib.AppItem;
/**
* Loader for historical chart data for both network and UID details.
+ *
+ * Deprecated in favor of {@link NetworkCycleDataLoader}
+ *
+ * @deprecated
*/
+@Deprecated
public class ChartDataLoaderCompat extends AsyncTaskLoader<ChartData> {
private static final String KEY_TEMPLATE = "template";
private static final String KEY_APP = "app";
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleData.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleData.java
new file mode 100644
index 000000000000..2d8c0de42ba4
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleData.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.net;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Data structure representing usage data in a billing cycle.
+ */
+public class NetworkCycleData {
+ public static final long BUCKET_DURATION_MS = TimeUnit.DAYS.toMillis(1);
+ public long startTime;
+ public long endTime;
+ public long totalUsage;
+ public List<NetworkCycleData> usageBuckets;
+
+ private NetworkCycleData(Builder builder) {
+ startTime = builder.mStart;
+ endTime = builder.mEnd;
+ totalUsage = builder.mTotalUsage;
+ usageBuckets = builder.mUsageBuckets;
+ }
+
+ public static class Builder {
+ private long mStart;
+ private long mEnd;
+ private long mTotalUsage;
+ private List<NetworkCycleData> mUsageBuckets;
+
+ public Builder setStartTime(long start) {
+ mStart = start;
+ return this;
+ }
+
+ public Builder setEndTime(long end) {
+ mEnd = end;
+ return this;
+ }
+
+ public Builder setTotalUsage(long total) {
+ mTotalUsage = total;
+ return this;
+ }
+
+ public Builder setUsageBuckets(List<NetworkCycleData> buckets) {
+ mUsageBuckets = buckets;
+ return this;
+ }
+
+ public NetworkCycleData build() {
+ return new NetworkCycleData(this);
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
new file mode 100644
index 000000000000..80e13563d74b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.net;
+
+import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
+import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
+
+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.Log;
+import android.util.Pair;
+
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.loader.content.AsyncTaskLoader;
+
+/**
+ * Loader for network data usage history. It returns a list of usage data per billing cycle.
+ */
+public class NetworkCycleDataLoader extends AsyncTaskLoader<List<NetworkCycleData>> {
+ private static final String TAG = "CycleDataSummaryLoader";
+ private final NetworkStatsManager mNetworkStatsManager;
+ private final String mSubId;
+ private final int mNetworkType;
+ private final NetworkPolicy mPolicy;
+ private final NetworkTemplate mNetworkTemplate;
+ @VisibleForTesting
+ final INetworkStatsService mNetworkStatsService;
+
+ private NetworkCycleDataLoader(Builder builder) {
+ super(builder.mContext);
+ mPolicy = builder.mPolicy;
+ mSubId = builder.mSubId;
+ mNetworkType = builder.mNetworkType;
+ mNetworkTemplate = builder.mNetworkTemplate;
+ mNetworkStatsManager = (NetworkStatsManager)
+ builder.mContext.getSystemService(Context.NETWORK_STATS_SERVICE);
+ mNetworkStatsService = INetworkStatsService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+ }
+
+ @Override
+ protected void onStartLoading() {
+ super.onStartLoading();
+ forceLoad();
+ }
+
+ @Override
+ public List<NetworkCycleData> loadInBackground() {
+ if (mPolicy == null) {
+ return loadFourWeeksData();
+ }
+ final List<NetworkCycleData> data = new ArrayList<>();
+ final Iterator<Pair<ZonedDateTime, ZonedDateTime>> iterator = NetworkPolicyManager
+ .cycleIterator(mPolicy);
+ while (iterator.hasNext()) {
+ final Pair<ZonedDateTime, ZonedDateTime> cycle = iterator.next();
+ final long cycleStart = cycle.first.toInstant().toEpochMilli();
+ final long cycleEnd = cycle.second.toInstant().toEpochMilli();
+ getUsage(cycleStart, cycleEnd, data);
+ }
+ return data;
+ }
+
+ @Override
+ protected void onStopLoading() {
+ super.onStopLoading();
+ cancelLoad();
+ }
+
+ @Override
+ protected void onReset() {
+ super.onReset();
+ cancelLoad();
+ }
+
+ @VisibleForTesting
+ List<NetworkCycleData> loadFourWeeksData() {
+ final List<NetworkCycleData> data = new ArrayList<>();
+ 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();
+
+ long cycleEnd = historyEnd;
+ while (cycleEnd > historyStart) {
+ final long cycleStart = cycleEnd - (DateUtils.WEEK_IN_MILLIS * 4);
+ getUsage(cycleStart, cycleEnd, data);
+ cycleEnd = cycleStart;
+ }
+
+ TrafficStats.closeQuietly(networkSession);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ return data;
+ }
+
+ @VisibleForTesting
+ void getUsage(long start, long end, @NonNull List<NetworkCycleData> data) {
+ try {
+ final NetworkStats stats = mNetworkStatsManager.querySummary(
+ mNetworkType, mSubId, start, end);
+ final long total = getTotalUsage(stats);
+ if (total > 0L) {
+ data.add(new NetworkCycleData.Builder()
+ .setStartTime(start)
+ .setEndTime(end)
+ .setTotalUsage(total)
+ .setUsageBuckets(getUsageBuckets(start, end))
+ .build());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception querying network detail.", e);
+ }
+ }
+
+ private long getTotalUsage(NetworkStats stats) {
+ long bytes = 0L;
+ if (stats != null) {
+ final NetworkStats.Bucket bucket = new NetworkStats.Bucket();
+ while (stats.hasNextBucket() && stats.getNextBucket(bucket)) {
+ bytes += bucket.getRxBytes() + bucket.getTxBytes();
+ }
+ stats.close();
+ }
+ return bytes;
+ }
+
+ private List<NetworkCycleData> getUsageBuckets(long start, long end) {
+ final List<NetworkCycleData> data = new ArrayList<>();
+ long bucketStart = start;
+ long bucketEnd = start + NetworkCycleData.BUCKET_DURATION_MS;
+ while (bucketEnd <= end) {
+ long usage = 0L;
+ try {
+ final NetworkStats stats = mNetworkStatsManager.querySummary(
+ mNetworkType, mSubId, bucketStart, bucketEnd);
+ usage = getTotalUsage(stats);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception querying network detail.", e);
+ }
+ data.add(new NetworkCycleData.Builder()
+ .setStartTime(bucketStart).setEndTime(bucketEnd).setTotalUsage(usage).build());
+ bucketStart = bucketEnd;
+ bucketEnd += NetworkCycleData.BUCKET_DURATION_MS;
+ }
+ return data;
+ }
+
+ public static class Builder {
+ private final Context mContext;
+ private NetworkPolicy mPolicy;
+ private String mSubId;
+ private int mNetworkType;
+ private NetworkTemplate mNetworkTemplate;
+
+ public Builder(Context context) {
+ mContext = context;
+ }
+
+ public Builder setNetworkPolicy(NetworkPolicy policy) {
+ mPolicy = policy;
+ return this;
+ }
+
+ public Builder setSubscriberId(String subId) {
+ mSubId = subId;
+ return this;
+ }
+
+ public Builder setNetworkType(int networkType) {
+ mNetworkType = networkType;
+ return this;
+ }
+
+ public Builder setNetworkTemplate(NetworkTemplate template) {
+ mNetworkTemplate = template;
+ return this;
+ }
+
+ public NetworkCycleDataLoader build() {
+ return new NetworkCycleDataLoader(this);
+ }
+ }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsDetailLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
index a070b2a5f768..34e6097ea46e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsDetailLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
@@ -20,25 +20,23 @@ import android.app.usage.NetworkStatsManager;
import android.app.usage.NetworkStats;
import android.content.Context;
import android.os.RemoteException;
-import android.telephony.TelephonyManager;
import android.util.Log;
import androidx.loader.content.AsyncTaskLoader;
/**
- * Loader for retrieving the network stats details for all UIDs.
+ * Loader for retrieving the network stats summary for all UIDs.
*/
-public class NetworkStatsDetailLoader extends AsyncTaskLoader<NetworkStats> {
+public class NetworkStatsSummaryLoader extends AsyncTaskLoader<NetworkStats> {
private static final String TAG = "NetworkDetailLoader";
private final NetworkStatsManager mNetworkStatsManager;
- private final TelephonyManager mTelephonyManager;
private final long mStart;
private final long mEnd;
- private final int mSubId;
+ private final String mSubId;
private final int mNetworkType;
- private NetworkStatsDetailLoader(Builder builder) {
+ private NetworkStatsSummaryLoader(Builder builder) {
super(builder.mContext);
mStart = builder.mStart;
mEnd = builder.mEnd;
@@ -46,8 +44,6 @@ public class NetworkStatsDetailLoader extends AsyncTaskLoader<NetworkStats> {
mNetworkType = builder.mNetworkType;
mNetworkStatsManager = (NetworkStatsManager)
builder.mContext.getSystemService(Context.NETWORK_STATS_SERVICE);
- mTelephonyManager =
- (TelephonyManager) builder.mContext.getSystemService(Context.TELEPHONY_SERVICE);
}
@Override
@@ -59,8 +55,7 @@ public class NetworkStatsDetailLoader extends AsyncTaskLoader<NetworkStats> {
@Override
public NetworkStats loadInBackground() {
try {
- return mNetworkStatsManager.queryDetails(
- mNetworkType, mTelephonyManager.getSubscriberId(mSubId), mStart, mEnd);
+ return mNetworkStatsManager.querySummary(mNetworkType, mSubId, mStart, mEnd);
} catch (RemoteException e) {
Log.e(TAG, "Exception querying network detail.", e);
return null;
@@ -83,7 +78,7 @@ public class NetworkStatsDetailLoader extends AsyncTaskLoader<NetworkStats> {
private final Context mContext;
private long mStart;
private long mEnd;
- private int mSubId;
+ private String mSubId;
private int mNetworkType;
public Builder(Context context) {
@@ -100,7 +95,7 @@ public class NetworkStatsDetailLoader extends AsyncTaskLoader<NetworkStats> {
return this;
}
- public Builder setSubscriptionId(int subId) {
+ public Builder setSubscriberId(String subId) {
mSubId = subId;
return this;
}
@@ -110,8 +105,8 @@ public class NetworkStatsDetailLoader extends AsyncTaskLoader<NetworkStats> {
return this;
}
- public NetworkStatsDetailLoader build() {
- return new NetworkStatsDetailLoader(this);
+ public NetworkStatsSummaryLoader build() {
+ return new NetworkStatsSummaryLoader(this);
}
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
new file mode 100644
index 000000000000..4c4207b23cab
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.net;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.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.Matchers.nullable;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+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.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+import android.os.RemoteException;
+import android.text.format.DateUtils;
+import android.util.Range;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.time.ZonedDateTime;
+import java.util.Iterator;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class NetworkCycleDataLoaderTest {
+
+ @Mock
+ private NetworkStatsManager mNetworkStatsManager;
+ @Mock
+ private Context mContext;
+ @Mock
+ private NetworkPolicy mPolicy;
+ @Mock
+ private Iterator<Range<ZonedDateTime>> mIterator;
+ @Mock
+ private INetworkStatsService mNetworkStatsService;
+
+ private NetworkCycleDataLoader mLoader;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(Context.NETWORK_STATS_SERVICE))
+ .thenReturn(mNetworkStatsManager);
+ when(mPolicy.cycleIterator()).thenReturn(mIterator);
+ }
+
+ @Test
+ public void loadInBackground_noNetworkPolicy_shouldLoad4WeeksData() {
+ mLoader = spy(new NetworkCycleDataLoader.Builder(mContext).build());
+ doReturn(null).when(mLoader).loadFourWeeksData();
+
+ mLoader.loadInBackground();
+
+ verify(mLoader).loadFourWeeksData();
+ }
+
+ @Test
+ public void loadInBackground_shouldQueryNetworkSummary() throws RemoteException {
+ final int networkType = ConnectivityManager.TYPE_MOBILE;
+ final String subId = "TestSubscriber";
+ final ZonedDateTime now = ZonedDateTime.now();
+ final Range<ZonedDateTime> cycle = new Range<>(now, now);
+ // mock 1 cycle data.
+ // hasNext() will be called internally in next(), hence setting it to return true twice.
+ when(mIterator.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
+ when(mIterator.next()).thenReturn(cycle);
+ mLoader = new NetworkCycleDataLoader.Builder(mContext)
+ .setNetworkPolicy(mPolicy).setNetworkType(networkType).setSubscriberId(subId).build();
+
+ mLoader.loadInBackground();
+
+ verify(mNetworkStatsManager).querySummary(eq(networkType), eq(subId), anyLong(), anyLong());
+ }
+
+ @Test
+ public void loadFourWeeksData_shouldGetUsageForLast4Weeks() throws RemoteException {
+ mLoader = spy(new NetworkCycleDataLoader.Builder(mContext).build());
+ 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);
+ when(networkHistory.getStart()).thenReturn(fourWeeksAgo);
+ when(networkHistory.getEnd()).thenReturn(now);
+
+ mLoader.loadFourWeeksData();
+
+ verify(mLoader).getUsage(eq(fourWeeksAgo), eq(now), any());
+ }
+}