Augment network stats based on SubscriptionPlan.

When a carrier provides an "anchor" of data usage at a specific
moment in time, augment the network statistics used by warning/limit
thresholds and Settings UI.  For example, if the OS measured 500MB
of usage, but the carrier says only 400MB has been used, we "squish"
down the OS measured usage to match that anchor.

Callers using the hidden API will have their data augmented by
default, and the public API offers a way to opt-into augmentation.

Thorough testing to verify behavior.

Test: bit FrameworksNetTests:android.net.,com.android.server.net.
Test: cts-tradefed run commandAndExit cts-dev -m CtsUsageStatsTestCases -t android.app.usage.cts.NetworkUsageStatsTest
Bug: 64534190
Change-Id: Id3d4d7625bbf04f57643e51dbf376e3fa0ea8eca
This commit is contained in:
Jeff Sharkey
2017-08-29 15:32:13 -06:00
parent 4a46108d0f
commit 3c8f96ef4a
3 changed files with 302 additions and 55 deletions

View File

@@ -485,6 +485,21 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START + 1));
}
public void testSetValues() throws Exception {
stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
stats.recordData(TEST_START, TEST_START + 1,
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
assertEquals(1024L + 2048L, stats.getTotalBytes());
final NetworkStatsHistory.Entry entry = stats.getValues(0, null);
entry.rxBytes /= 2;
entry.txBytes *= 2;
stats.setValues(0, entry);
assertEquals(512L + 4096L, stats.getTotalBytes());
}
private static void assertIndexBeforeAfter(
NetworkStatsHistory stats, int before, int after, long time) {
assertEquals("unexpected before", before, stats.getIndexBefore(time));

View File

@@ -17,26 +17,35 @@
package com.android.server.net;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.NetworkStats.SET_ALL;
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.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.os.Process.myUid;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import android.content.res.Resources;
import android.net.NetworkIdentity;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.os.Process;
import android.os.UserHandle;
import android.telephony.SubscriptionPlan;
import android.telephony.TelephonyManager;
import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.format.DateUtils;
import com.android.frameworks.tests.net.R;
import libcore.io.IoUtils;
import libcore.io.Streams;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
@@ -44,9 +53,9 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import libcore.io.IoUtils;
import libcore.io.Streams;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
/**
* Tests for {@link NetworkStatsCollection}.
@@ -57,6 +66,10 @@ public class NetworkStatsCollectionTest extends AndroidTestCase {
private static final String TEST_FILE = "test.bin";
private static final String TEST_IMSI = "310260000000000";
private static final long TIME_A = 1326088800000L; // UTC: Monday 9th January 2012 06:00:00 AM
private static final long TIME_B = 1326110400000L; // UTC: Monday 9th January 2012 12:00:00 PM
private static final long TIME_C = 1326132000000L; // UTC: Monday 9th January 2012 06:00:00 PM
@Override
public void setUp() throws Exception {
super.setUp();
@@ -198,11 +211,11 @@ public class NetworkStatsCollectionTest extends AndroidTestCase {
collection.getRelevantUids(NetworkStatsAccess.Level.DEVICE));
// Verify security check in getHistory.
assertNotNull(collection.getHistory(buildTemplateMobileAll(TEST_IMSI), myUid, SET_DEFAULT,
TAG_NONE, 0, NetworkStatsAccess.Level.DEFAULT));
assertNotNull(collection.getHistory(buildTemplateMobileAll(TEST_IMSI), null, myUid, SET_DEFAULT,
TAG_NONE, 0, 0L, 0L, NetworkStatsAccess.Level.DEFAULT, myUid));
try {
collection.getHistory(buildTemplateMobileAll(TEST_IMSI), otherUidInSameUser,
SET_DEFAULT, TAG_NONE, 0, NetworkStatsAccess.Level.DEFAULT);
collection.getHistory(buildTemplateMobileAll(TEST_IMSI), null, otherUidInSameUser,
SET_DEFAULT, TAG_NONE, 0, 0L, 0L, NetworkStatsAccess.Level.DEFAULT, myUid);
fail("Should have thrown SecurityException for accessing different UID");
} catch (SecurityException e) {
// expected
@@ -217,6 +230,213 @@ public class NetworkStatsCollectionTest extends AndroidTestCase {
0, NetworkStatsAccess.Level.DEVICE);
}
public void testAugmentPlan() throws Exception {
final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
stageFile(R.raw.netstats_v1, testFile);
final NetworkStatsCollection emptyCollection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
collection.readLegacyNetwork(testFile);
// Test a bunch of plans that should result in no augmentation
final List<SubscriptionPlan> plans = new ArrayList<>();
// No plan
plans.add(null);
// No usage anchor
plans.add(SubscriptionPlan.Builder
.createRecurringMonthly(ZonedDateTime.parse("2011-01-14T00:00:00.00Z")).build());
// Usage anchor far in past
plans.add(SubscriptionPlan.Builder
.createRecurringMonthly(ZonedDateTime.parse("2011-01-14T00:00:00.00Z"))
.setDataUsage(1000L, TIME_A - DateUtils.YEAR_IN_MILLIS).build());
// Usage anchor far in future
plans.add(SubscriptionPlan.Builder
.createRecurringMonthly(ZonedDateTime.parse("2011-01-14T00:00:00.00Z"))
.setDataUsage(1000L, TIME_A + DateUtils.YEAR_IN_MILLIS).build());
// Usage anchor near but outside cycle
plans.add(SubscriptionPlan.Builder
.createNonrecurring(ZonedDateTime.parse("2012-01-09T09:00:00.00Z"),
ZonedDateTime.parse("2012-01-09T15:00:00.00Z"))
.setDataUsage(1000L, TIME_C).build());
for (SubscriptionPlan plan : plans) {
int i;
NetworkStatsHistory history;
// Empty collection should be untouched
history = getHistory(emptyCollection, plan, TIME_A, TIME_C);
assertEquals(0L, history.getTotalBytes());
// Normal collection should be untouched
history = getHistory(collection, plan, TIME_A, TIME_C); i = 0;
assertEntry(100647, 197, 23649, 185, history.getValues(i++, null));
assertEntry(100647, 196, 23648, 185, history.getValues(i++, null));
assertEntry(18323, 76, 15032, 76, history.getValues(i++, null));
assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
assertEntry(10747, 50, 16838, 55, history.getValues(i++, null));
assertEntry(10747, 49, 16838, 54, history.getValues(i++, null));
assertEntry(89191, 151, 18021, 140, history.getValues(i++, null));
assertEntry(89190, 150, 18020, 139, history.getValues(i++, null));
assertEntry(3821, 22, 4525, 26, history.getValues(i++, null));
assertEntry(3820, 22, 4524, 26, history.getValues(i++, null));
assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
assertEntry(11378, 49, 9261, 49, history.getValues(i++, null));
assertEntry(11377, 48, 9261, 49, history.getValues(i++, null));
assertEntry(201765, 328, 41808, 291, history.getValues(i++, null));
assertEntry(201765, 328, 41807, 290, history.getValues(i++, null));
assertEntry(106106, 218, 39917, 201, history.getValues(i++, null));
assertEntry(106105, 217, 39917, 201, history.getValues(i++, null));
assertEquals(history.size(), i);
// Slice from middle should be untouched
history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
TIME_B + HOUR_IN_MILLIS); i = 0;
assertEntry(3821, 22, 4525, 26, history.getValues(i++, null));
assertEntry(3820, 22, 4524, 26, history.getValues(i++, null));
assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
assertEquals(history.size(), i);
}
// Lower anchor in the middle of plan
{
int i;
NetworkStatsHistory history;
final SubscriptionPlan plan = SubscriptionPlan.Builder
.createNonrecurring(ZonedDateTime.parse("2012-01-09T09:00:00.00Z"),
ZonedDateTime.parse("2012-01-09T15:00:00.00Z"))
.setDataUsage(200000L, TIME_B).build();
// Empty collection should be augmented
history = getHistory(emptyCollection, plan, TIME_A, TIME_C);
assertEquals(200000L, history.getTotalBytes());
// Normal collection should be augmented
history = getHistory(collection, plan, TIME_A, TIME_C); i = 0;
assertEntry(100647, 197, 23649, 185, history.getValues(i++, null));
assertEntry(100647, 196, 23648, 185, history.getValues(i++, null));
assertEntry(18323, 76, 15032, 76, history.getValues(i++, null));
assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
// Cycle point; start data normalization
assertEntry(7507, 0, 11763, 0, history.getValues(i++, null));
assertEntry(7507, 0, 11763, 0, history.getValues(i++, null));
assertEntry(62309, 0, 12589, 0, history.getValues(i++, null));
assertEntry(62309, 0, 12588, 0, history.getValues(i++, null));
assertEntry(2669, 0, 3161, 0, history.getValues(i++, null));
assertEntry(2668, 0, 3160, 0, history.getValues(i++, null));
// Anchor point; end data normalization
assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
// Cycle point
assertEntry(11378, 49, 9261, 49, history.getValues(i++, null));
assertEntry(11377, 48, 9261, 49, history.getValues(i++, null));
assertEntry(201765, 328, 41808, 291, history.getValues(i++, null));
assertEntry(201765, 328, 41807, 290, history.getValues(i++, null));
assertEntry(106106, 218, 39917, 201, history.getValues(i++, null));
assertEntry(106105, 217, 39917, 201, history.getValues(i++, null));
assertEquals(history.size(), i);
// Slice from middle should be augmented
history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
TIME_B + HOUR_IN_MILLIS); i = 0;
assertEntry(2669, 0, 3161, 0, history.getValues(i++, null));
assertEntry(2668, 0, 3160, 0, history.getValues(i++, null));
assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
assertEquals(history.size(), i);
}
// Higher anchor in the middle of plan
{
int i;
NetworkStatsHistory history;
final SubscriptionPlan plan = SubscriptionPlan.Builder
.createNonrecurring(ZonedDateTime.parse("2012-01-09T09:00:00.00Z"),
ZonedDateTime.parse("2012-01-09T15:00:00.00Z"))
.setDataUsage(400000L, TIME_B + MINUTE_IN_MILLIS).build();
// Empty collection should be augmented
history = getHistory(emptyCollection, plan, TIME_A, TIME_C);
assertEquals(400000L, history.getTotalBytes());
// Normal collection should be augmented
history = getHistory(collection, plan, TIME_A, TIME_C); i = 0;
assertEntry(100647, 197, 23649, 185, history.getValues(i++, null));
assertEntry(100647, 196, 23648, 185, history.getValues(i++, null));
assertEntry(18323, 76, 15032, 76, history.getValues(i++, null));
assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
// Cycle point; start data normalization
assertEntry(15015, 0, 23526, 0, history.getValues(i++, null));
assertEntry(15015, 0, 23526, 0, history.getValues(i++, null));
assertEntry(124619, 0, 25179, 0, history.getValues(i++, null));
assertEntry(124618, 0, 25177, 0, history.getValues(i++, null));
assertEntry(5338, 0, 6322, 0, history.getValues(i++, null));
assertEntry(5337, 0, 6320, 0, history.getValues(i++, null));
// Anchor point; end data normalization
assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
// Cycle point
assertEntry(11378, 49, 9261, 49, history.getValues(i++, null));
assertEntry(11377, 48, 9261, 49, history.getValues(i++, null));
assertEntry(201765, 328, 41808, 291, history.getValues(i++, null));
assertEntry(201765, 328, 41807, 290, history.getValues(i++, null));
assertEntry(106106, 218, 39917, 201, history.getValues(i++, null));
assertEntry(106105, 217, 39917, 201, history.getValues(i++, null));
// Slice from middle should be augmented
history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
TIME_B + HOUR_IN_MILLIS); i = 0;
assertEntry(5338, 0, 6322, 0, history.getValues(i++, null));
assertEntry(5337, 0, 6320, 0, history.getValues(i++, null));
assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
assertEquals(history.size(), i);
}
}
public void testRounding() throws Exception {
final NetworkStatsCollection coll = new NetworkStatsCollection(HOUR_IN_MILLIS);
// Special values should remain unchanged
for (long time : new long[] {
Long.MIN_VALUE, Long.MAX_VALUE, SubscriptionPlan.TIME_UNKNOWN
}) {
assertEquals(time, coll.roundUp(time));
assertEquals(time, coll.roundDown(time));
}
assertEquals(TIME_A, coll.roundUp(TIME_A));
assertEquals(TIME_A, coll.roundDown(TIME_A));
assertEquals(TIME_A + HOUR_IN_MILLIS, coll.roundUp(TIME_A + 1));
assertEquals(TIME_A, coll.roundDown(TIME_A + 1));
assertEquals(TIME_A, coll.roundUp(TIME_A - 1));
assertEquals(TIME_A - HOUR_IN_MILLIS, coll.roundDown(TIME_A - 1));
}
/**
* Copy a {@link Resources#openRawResource(int)} into {@link File} for
* testing purposes.
@@ -235,28 +455,50 @@ public class NetworkStatsCollectionTest extends AndroidTestCase {
}
}
private static NetworkStatsHistory getHistory(NetworkStatsCollection collection,
SubscriptionPlan augmentPlan, long start, long end) {
return collection.getHistory(buildTemplateMobileAll(TEST_IMSI), augmentPlan, UID_ALL,
SET_ALL, TAG_NONE, FIELD_ALL, start, end, NetworkStatsAccess.Level.DEVICE, myUid());
}
private static void assertSummaryTotal(NetworkStatsCollection collection,
NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets,
@NetworkStatsAccess.Level int accessLevel) {
final NetworkStats.Entry entry = collection.getSummary(
template, Long.MIN_VALUE, Long.MAX_VALUE, accessLevel)
final NetworkStats.Entry actual = collection.getSummary(
template, Long.MIN_VALUE, Long.MAX_VALUE, accessLevel, myUid())
.getTotal(null);
assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets);
assertEntry(rxBytes, rxPackets, txBytes, txPackets, actual);
}
private static void assertSummaryTotalIncludingTags(NetworkStatsCollection collection,
NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) {
final NetworkStats.Entry entry = collection.getSummary(
template, Long.MIN_VALUE, Long.MAX_VALUE, NetworkStatsAccess.Level.DEVICE)
final NetworkStats.Entry actual = collection.getSummary(
template, Long.MIN_VALUE, Long.MAX_VALUE, NetworkStatsAccess.Level.DEVICE, myUid())
.getTotalIncludingTags(null);
assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets);
assertEntry(rxBytes, rxPackets, txBytes, txPackets, actual);
}
private static void assertEntry(
NetworkStats.Entry entry, long rxBytes, long rxPackets, long txBytes, long txPackets) {
assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
assertEquals("unexpected txPackets", txPackets, entry.txPackets);
private static void assertEntry(long rxBytes, long rxPackets, long txBytes, long txPackets,
NetworkStats.Entry actual) {
assertEntry(new NetworkStats.Entry(rxBytes, rxPackets, txBytes, txPackets, 0L), actual);
}
private static void assertEntry(long rxBytes, long rxPackets, long txBytes, long txPackets,
NetworkStatsHistory.Entry actual) {
assertEntry(new NetworkStats.Entry(rxBytes, rxPackets, txBytes, txPackets, 0L), actual);
}
private static void assertEntry(NetworkStats.Entry expected,
NetworkStatsHistory.Entry actual) {
assertEntry(expected, new NetworkStats.Entry(actual.rxBytes, actual.rxPackets,
actual.txBytes, actual.txPackets, 0L));
}
private static void assertEntry(NetworkStats.Entry expected,
NetworkStats.Entry actual) {
assertEquals("unexpected rxBytes", expected.rxBytes, actual.rxBytes);
assertEquals("unexpected rxPackets", expected.rxPackets, actual.rxPackets);
assertEquals("unexpected txBytes", expected.txBytes, actual.txBytes);
assertEquals("unexpected txPackets", expected.txPackets, actual.txPackets);
}
}

View File

@@ -46,19 +46,17 @@ import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
import static com.android.internal.util.TestUtils.waitForIdleHandler;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.when;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.AlarmManager;
import android.app.usage.NetworkStatsManager;
@@ -79,24 +77,21 @@ import android.net.NetworkTemplate;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.INetworkManagementService;
import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Messenger;
import android.os.MessageQueue;
import android.os.MessageQueue.IdleHandler;
import android.os.Message;
import android.os.Messenger;
import android.os.PowerManager;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import android.util.TrustedTime;
import com.android.internal.net.VpnInfo;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.server.net.NetworkStatsService;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
@@ -112,9 +107,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.File;
import java.util.ArrayList;
import java.util.Objects;
import java.util.List;
/**
* Tests for {@link NetworkStatsService}.
@@ -983,7 +976,7 @@ public class NetworkStatsServiceTest {
// verify summary API
final NetworkStats stats = mSession.getSummaryForNetwork(template, start, end);
assertValues(stats, IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO,
assertValues(stats, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
rxBytes, rxPackets, txBytes, txPackets, operations);
}
@@ -1107,28 +1100,25 @@ public class NetworkStatsServiceTest {
int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes,
long txPackets, int operations) {
final NetworkStats.Entry entry = new NetworkStats.Entry();
List<Integer> sets = new ArrayList<>();
if (set == SET_DEFAULT || set == SET_ALL) {
sets.add(SET_DEFAULT);
}
if (set == SET_FOREGROUND || set == SET_ALL) {
sets.add(SET_FOREGROUND);
final int[] sets;
if (set == SET_ALL) {
sets = new int[] { SET_ALL, SET_DEFAULT, SET_FOREGROUND };
} else {
sets = new int[] { set };
}
List<Integer> roamings = new ArrayList<>();
if (roaming == ROAMING_NO || roaming == ROAMING_ALL) {
roamings.add(ROAMING_NO);
}
if (roaming == ROAMING_YES || roaming == ROAMING_ALL) {
roamings.add(ROAMING_YES);
final int[] roamings;
if (roaming == ROAMING_ALL) {
roamings = new int[] { ROAMING_ALL, ROAMING_YES, ROAMING_NO };
} else {
roamings = new int[] { roaming };
}
List<Integer> meterings = new ArrayList<>();
if (metered == METERED_NO || metered == METERED_ALL) {
meterings.add(METERED_NO);
}
if (metered == METERED_YES || metered == METERED_ALL) {
meterings.add(METERED_YES);
final int[] meterings;
if (metered == METERED_ALL) {
meterings = new int[] { METERED_ALL, METERED_YES, METERED_NO };
} else {
meterings = new int[] { metered };
}
for (int s : sets) {