diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 6bf14257c7..8071e8b837 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1772,14 +1772,8 @@ public class ConnectivityManager { // ignored } - /** - * Return quota status for the current active network, or {@code null} if no - * network is active. Quota status can change rapidly, so these values - * shouldn't be cached. - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + /** {@hide} */ + @Deprecated public NetworkQuotaInfo getActiveNetworkQuotaInfo() { try { return mService.getActiveNetworkQuotaInfo(); diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index ee75fd4430..761c033660 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -899,7 +899,9 @@ public final class NetworkCapabilities implements Parcelable { // Ignore NOT_METERED being added or removed as it is effectively dynamic. http://b/63326103 // TODO: properly support NOT_METERED as a mutable and requestable capability. - final long mask = ~MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_NOT_METERED); + // Ignore DUN being added or removed. http://b/65257223. + final long mask = ~MUTABLE_CAPABILITIES + & ~(1 << NET_CAPABILITY_NOT_METERED) & ~(1 << NET_CAPABILITY_DUN); long oldImmutableCapabilities = this.mNetworkCapabilities & mask; long newImmutableCapabilities = that.mNetworkCapabilities & mask; if (oldImmutableCapabilities != newImmutableCapabilities) { diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index d554938775..e6ad89a20b 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -16,8 +16,8 @@ package android.net; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; import com.android.internal.annotations.VisibleForTesting; @@ -121,7 +121,6 @@ public class NetworkInfo implements Parcelable { private boolean mIsFailover; private boolean mIsAvailable; private boolean mIsRoaming; - private boolean mIsMetered; /** * @hide @@ -154,7 +153,6 @@ public class NetworkInfo implements Parcelable { mIsFailover = source.mIsFailover; mIsAvailable = source.mIsAvailable; mIsRoaming = source.mIsRoaming; - mIsMetered = source.mIsMetered; } } } @@ -333,31 +331,6 @@ public class NetworkInfo implements Parcelable { } } - /** - * Returns if this network is metered. A network is classified as metered - * when the user is sensitive to heavy data usage on that connection due to - * monetary costs, data limitations or battery/performance issues. You - * should check this before doing large data transfers, and warn the user or - * delay the operation until another network is available. - * - * @return {@code true} if large transfers should be avoided, otherwise - * {@code false}. - * @hide - */ - public boolean isMetered() { - synchronized (this) { - return mIsMetered; - } - } - - /** {@hide} */ - @VisibleForTesting - public void setMetered(boolean isMetered) { - synchronized (this) { - mIsMetered = isMetered; - } - } - /** * Reports the current coarse-grained state of the network. * @return the coarse-grained state @@ -441,7 +414,6 @@ public class NetworkInfo implements Parcelable { append(", failover: ").append(mIsFailover). append(", available: ").append(mIsAvailable). append(", roaming: ").append(mIsRoaming). - append(", metered: ").append(mIsMetered). append("]"); return builder.toString(); } @@ -464,7 +436,6 @@ public class NetworkInfo implements Parcelable { dest.writeInt(mIsFailover ? 1 : 0); dest.writeInt(mIsAvailable ? 1 : 0); dest.writeInt(mIsRoaming ? 1 : 0); - dest.writeInt(mIsMetered ? 1 : 0); dest.writeString(mReason); dest.writeString(mExtraInfo); } @@ -483,7 +454,6 @@ public class NetworkInfo implements Parcelable { netInfo.mIsFailover = in.readInt() != 0; netInfo.mIsAvailable = in.readInt() != 0; netInfo.mIsRoaming = in.readInt() != 0; - netInfo.mIsMetered = in.readInt() != 0; netInfo.mReason = in.readString(); netInfo.mExtraInfo = in.readString(); return netInfo; diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 664c2abdff..9bc92fde22 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -44,7 +44,6 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.PackageManager; import android.content.res.Configuration; import android.database.ContentObserver; import android.net.ConnectivityManager; @@ -129,7 +128,6 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; import com.android.internal.util.WakeupMessage; import com.android.internal.util.XmlUtils; -import com.android.server.LocalServices; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.IpConnectivityMetrics; @@ -1053,8 +1051,7 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Apply any relevant filters to {@link NetworkState} for the given UID. For * example, this may mark the network as {@link DetailedState#BLOCKED} based - * on {@link #isNetworkWithLinkPropertiesBlocked}, or - * {@link NetworkInfo#isMetered()} based on network policies. + * on {@link #isNetworkWithLinkPropertiesBlocked}. */ private void filterNetworkStateForUid(NetworkState state, int uid, boolean ignoreBlocked) { if (state == null || state.networkInfo == null || state.linkProperties == null) return; @@ -1065,15 +1062,6 @@ public class ConnectivityService extends IConnectivityManager.Stub if (mLockdownTracker != null) { mLockdownTracker.augmentNetworkInfo(state.networkInfo); } - - // TODO: apply metered state closer to NetworkAgentInfo - final long token = Binder.clearCallingIdentity(); - try { - state.networkInfo.setMetered(mPolicyManager.isNetworkMetered(state)); - } catch (RemoteException e) { - } finally { - Binder.restoreCallingIdentity(token); - } } /** @@ -1343,30 +1331,24 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override + @Deprecated public NetworkQuotaInfo getActiveNetworkQuotaInfo() { - enforceAccessPermission(); - final int uid = Binder.getCallingUid(); - final long token = Binder.clearCallingIdentity(); - try { - final NetworkState state = getUnfilteredActiveNetworkState(uid); - if (state.networkInfo != null) { - try { - return mPolicyManager.getNetworkQuotaInfo(state); - } catch (RemoteException e) { - } - } - return null; - } finally { - Binder.restoreCallingIdentity(token); - } + Log.w(TAG, "Shame on UID " + Binder.getCallingUid() + + " for calling the hidden API getNetworkQuotaInfo(). Shame!"); + return new NetworkQuotaInfo(); } @Override public boolean isActiveNetworkMetered() { enforceAccessPermission(); - final NetworkInfo info = getActiveNetworkInfo(); - return (info != null) ? info.isMetered() : false; + final NetworkCapabilities caps = getNetworkCapabilities(getActiveNetwork()); + if (caps != null) { + return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + } else { + // Always return the most conservative value + return true; + } } private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() { @@ -2787,7 +2769,8 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceAccessPermission(); NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); - if (nai != null && !nai.networkInfo.isMetered()) { + if (nai != null && nai.networkCapabilities + .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)) { return ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED; } diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java index cd2d0985c7..e6170cb42c 100644 --- a/tests/net/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java @@ -18,6 +18,7 @@ package android.net; import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; @@ -143,6 +144,14 @@ public class NetworkCapabilitiesTest { assertEquals("", nc1.describeImmutableDifferences(nc2)); assertEquals("", nc1.describeImmutableDifferences(nc1)); + // DUN changing (http://b/65257223) + nc1 = new NetworkCapabilities() + .addCapability(NET_CAPABILITY_DUN) + .addCapability(NET_CAPABILITY_INTERNET); + nc2 = new NetworkCapabilities().addCapability(NET_CAPABILITY_INTERNET); + assertEquals("", nc1.describeImmutableDifferences(nc2)); + assertEquals("", nc1.describeImmutableDifferences(nc1)); + // Immutable capability changing nc1 = new NetworkCapabilities() .addCapability(NET_CAPABILITY_INTERNET) diff --git a/tests/net/java/android/net/NetworkStatsHistoryTest.java b/tests/net/java/android/net/NetworkStatsHistoryTest.java index e7b91b568d..1c0c14eac0 100644 --- a/tests/net/java/android/net/NetworkStatsHistoryTest.java +++ b/tests/net/java/android/net/NetworkStatsHistoryTest.java @@ -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)); diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java index 2a32b73d56..9c10264656 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java @@ -17,26 +17,39 @@ 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 static com.android.server.net.NetworkStatsCollection.multiplySafe; + import android.content.res.Resources; +import android.net.ConnectivityManager; 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 android.util.RecurrenceRule; 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 +57,12 @@ 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.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.List; /** * Tests for {@link NetworkStatsCollection}. @@ -57,14 +73,31 @@ 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 + + private static Clock sOriginalClock; + @Override public void setUp() throws Exception { super.setUp(); + sOriginalClock = RecurrenceRule.sClock; // ignore any device overlay while testing NetworkTemplate.forceAllNetworkTypes(); } + @Override + protected void tearDown() throws Exception { + super.tearDown(); + RecurrenceRule.sClock = sOriginalClock; + } + + private void setClock(Instant instant) { + RecurrenceRule.sClock = Clock.fixed(instant, ZoneId.systemDefault()); + } + public void testReadLegacyNetwork() throws Exception { final File testFile = new File(getContext().getFilesDir(), TEST_FILE); stageFile(R.raw.netstats_v1, testFile); @@ -198,11 +231,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 +250,257 @@ 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); + + // We're in the future, but not that far off + setClock(Instant.parse("2012-06-01T00:00:00.00Z")); + + // Test a bunch of plans that should result in no augmentation + final List 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 testAugmentPlanGigantic() throws Exception { + // We're in the future, but not that far off + setClock(Instant.parse("2012-06-01T00:00:00.00Z")); + + // Create a simple history with a ton of measured usage + final NetworkStatsCollection large = new NetworkStatsCollection(HOUR_IN_MILLIS); + final NetworkIdentitySet ident = new NetworkIdentitySet(); + ident.add(new NetworkIdentity(ConnectivityManager.TYPE_MOBILE, -1, TEST_IMSI, null, + false, true)); + large.recordData(ident, UID_ALL, SET_ALL, TAG_NONE, TIME_A, TIME_B, + new NetworkStats.Entry(12_730_893_164L, 1, 0, 0, 0)); + + // Verify untouched total + assertEquals(12_730_893_164L, getHistory(large, null, TIME_A, TIME_C).getTotalBytes()); + + // Verify anchor that might cause overflows + final SubscriptionPlan plan = SubscriptionPlan.Builder + .createRecurringMonthly(ZonedDateTime.parse("2012-01-09T00:00:00.00Z")) + .setDataUsage(4_939_212_390L, TIME_B).build(); + assertEquals(4_939_212_386L, getHistory(large, plan, TIME_A, TIME_C).getTotalBytes()); + } + + 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)); + } + + public void testMultiplySafe() { + assertEquals(25, multiplySafe(50, 1, 2)); + assertEquals(100, multiplySafe(50, 2, 1)); + + assertEquals(-10, multiplySafe(30, -1, 3)); + assertEquals(0, multiplySafe(30, 0, 3)); + assertEquals(10, multiplySafe(30, 1, 3)); + assertEquals(20, multiplySafe(30, 2, 3)); + assertEquals(30, multiplySafe(30, 3, 3)); + assertEquals(40, multiplySafe(30, 4, 3)); + + assertEquals(100_000_000_000L, + multiplySafe(300_000_000_000L, 10_000_000_000L, 30_000_000_000L)); + assertEquals(100_000_000_010L, + multiplySafe(300_000_000_000L, 10_000_000_001L, 30_000_000_000L)); + assertEquals(823_202_048L, + multiplySafe(4_939_212_288L, 2_121_815_528L, 12_730_893_165L)); + } + /** * Copy a {@link Resources#openRawResource(int)} into {@link File} for * testing purposes. @@ -235,28 +519,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); } } diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index 375b418bea..ecc99323d7 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -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 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 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 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) {