Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70df7223 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "More knobs for connectivity experiments." into pi-dev

parents cfa439f0 36b414bc
Loading
Loading
Loading
Loading
+14 −0
Original line number Original line Diff line number Diff line
@@ -8930,6 +8930,20 @@ public final class Settings {
       /** {@hide} */
       /** {@hide} */
       public static final String NETSTATS_UID_TAG_DELETE_AGE = "netstats_uid_tag_delete_age";
       public static final String NETSTATS_UID_TAG_DELETE_AGE = "netstats_uid_tag_delete_age";


       /** {@hide} */
       public static final String NETPOLICY_QUOTA_ENABLED = "netpolicy_quota_enabled";
       /** {@hide} */
       public static final String NETPOLICY_QUOTA_UNLIMITED = "netpolicy_quota_unlimited";
       /** {@hide} */
       public static final String NETPOLICY_QUOTA_LIMITED = "netpolicy_quota_limited";
       /** {@hide} */
       public static final String NETPOLICY_QUOTA_FRAC_JOBS = "netpolicy_quota_frac_jobs";
       /** {@hide} */
       public static final String NETPOLICY_QUOTA_FRAC_MULTIPATH = "netpolicy_quota_frac_multipath";

       /** {@hide} */
       public static final String NETPOLICY_OVERRIDE_ENABLED = "netpolicy_override_enabled";

       /**
       /**
        * User preference for which network(s) should be used. Only the
        * User preference for which network(s) should be used. Only the
        * connectivity service should touch this.
        * connectivity service should touch this.
+6 −0
Original line number Original line Diff line number Diff line
@@ -302,6 +302,12 @@ public class SettingsBackupTest {
                    Settings.Global.NETSTATS_UID_TAG_DELETE_AGE,
                    Settings.Global.NETSTATS_UID_TAG_DELETE_AGE,
                    Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES,
                    Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES,
                    Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE,
                    Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE,
                    Settings.Global.NETPOLICY_QUOTA_ENABLED,
                    Settings.Global.NETPOLICY_QUOTA_UNLIMITED,
                    Settings.Global.NETPOLICY_QUOTA_LIMITED,
                    Settings.Global.NETPOLICY_QUOTA_FRAC_JOBS,
                    Settings.Global.NETPOLICY_QUOTA_FRAC_MULTIPATH,
                    Settings.Global.NETPOLICY_OVERRIDE_ENABLED,
                    Settings.Global.NETWORK_AVOID_BAD_WIFI,
                    Settings.Global.NETWORK_AVOID_BAD_WIFI,
                    Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES,
                    Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES,
                    Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE,
                    Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE,
+49 −10
Original line number Original line Diff line number Diff line
@@ -70,6 +70,12 @@ import static android.net.NetworkTemplate.MATCH_MOBILE;
import static android.net.NetworkTemplate.MATCH_WIFI;
import static android.net.NetworkTemplate.MATCH_WIFI;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.provider.Settings.Global.NETPOLICY_OVERRIDE_ENABLED;
import static android.provider.Settings.Global.NETPOLICY_QUOTA_ENABLED;
import static android.provider.Settings.Global.NETPOLICY_QUOTA_FRAC_JOBS;
import static android.provider.Settings.Global.NETPOLICY_QUOTA_FRAC_MULTIPATH;
import static android.provider.Settings.Global.NETPOLICY_QUOTA_LIMITED;
import static android.provider.Settings.Global.NETPOLICY_QUOTA_UNLIMITED;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
@@ -115,6 +121,7 @@ import android.app.PendingIntent;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter;
@@ -351,6 +358,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
     */
     */
    private static final long WAIT_FOR_ADMIN_DATA_TIMEOUT_MS = 10_000;
    private static final long WAIT_FOR_ADMIN_DATA_TIMEOUT_MS = 10_000;


    private static final long QUOTA_UNLIMITED_DEFAULT = DataUnit.MEBIBYTES.toBytes(20);
    private static final float QUOTA_LIMITED_DEFAULT = 0.1f;
    private static final float QUOTA_FRAC_JOBS_DEFAULT = 0.5f;
    private static final float QUOTA_FRAC_MULTIPATH_DEFAULT = 0.5f;

    private static final int MSG_RULES_CHANGED = 1;
    private static final int MSG_RULES_CHANGED = 1;
    private static final int MSG_METERED_IFACES_CHANGED = 2;
    private static final int MSG_METERED_IFACES_CHANGED = 2;
    private static final int MSG_LIMIT_REACHED = 5;
    private static final int MSG_LIMIT_REACHED = 5;
@@ -1739,10 +1751,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        }
        }
        mMeteredIfaces = newMeteredIfaces;
        mMeteredIfaces = newMeteredIfaces;


        final ContentResolver cr = mContext.getContentResolver();
        final boolean quotaEnabled = Settings.Global.getInt(cr,
                NETPOLICY_QUOTA_ENABLED, 1) != 0;
        final long quotaUnlimited = Settings.Global.getLong(cr,
                NETPOLICY_QUOTA_UNLIMITED, QUOTA_UNLIMITED_DEFAULT);
        final float quotaLimited = Settings.Global.getFloat(cr,
                NETPOLICY_QUOTA_LIMITED, QUOTA_LIMITED_DEFAULT);

        // Finally, calculate our opportunistic quotas
        // Finally, calculate our opportunistic quotas
        // TODO: add experiments support to disable or tweak ratios
        mSubscriptionOpportunisticQuota.clear();
        mSubscriptionOpportunisticQuota.clear();
        for (NetworkState state : states) {
        for (NetworkState state : states) {
            if (!quotaEnabled) continue;
            if (state.network == null) continue;
            if (state.network == null) continue;
            final int subId = getSubIdLocked(state.network);
            final int subId = getSubIdLocked(state.network);
            final SubscriptionPlan plan = getPrimarySubscriptionPlanLocked(subId);
            final SubscriptionPlan plan = getPrimarySubscriptionPlanLocked(subId);
@@ -1754,7 +1774,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                quotaBytes = OPPORTUNISTIC_QUOTA_UNKNOWN;
                quotaBytes = OPPORTUNISTIC_QUOTA_UNKNOWN;
            } else if (limitBytes == SubscriptionPlan.BYTES_UNLIMITED) {
            } else if (limitBytes == SubscriptionPlan.BYTES_UNLIMITED) {
                // Unlimited data; let's use 20MiB/day (600MiB/month)
                // Unlimited data; let's use 20MiB/day (600MiB/month)
                quotaBytes = DataUnit.MEBIBYTES.toBytes(20);
                quotaBytes = quotaUnlimited;
            } else {
            } else {
                // Limited data; let's only use 10% of remaining budget
                // Limited data; let's only use 10% of remaining budget
                final Pair<ZonedDateTime, ZonedDateTime> cycle = plan.cycleIterator().next();
                final Pair<ZonedDateTime, ZonedDateTime> cycle = plan.cycleIterator().next();
@@ -1772,7 +1792,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                final long remainingDays =
                final long remainingDays =
                        1 + ((end - now.toEpochMilli() - 1) / TimeUnit.DAYS.toMillis(1));
                        1 + ((end - now.toEpochMilli() - 1) / TimeUnit.DAYS.toMillis(1));


                quotaBytes = Math.max(0, (remainingBytes / remainingDays) / 10);
                quotaBytes = Math.max(0, (long) ((remainingBytes / remainingDays) * quotaLimited));
            }
            }


            mSubscriptionOpportunisticQuota.put(subId, quotaBytes);
            mSubscriptionOpportunisticQuota.put(subId, quotaBytes);
@@ -3048,6 +3068,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            }
            }
        }
        }


        // Only allow overrides when feature is enabled. However, we always
        // allow disabling of overrides for safety reasons.
        final boolean overrideEnabled = Settings.Global.getInt(mContext.getContentResolver(),
                NETPOLICY_OVERRIDE_ENABLED, 1) != 0;
        if (overrideEnabled || overrideValue == 0) {
            mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE,
            mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE,
                    overrideMask, overrideValue, subId));
                    overrideMask, overrideValue, subId));
            if (timeoutMillis > 0) {
            if (timeoutMillis > 0) {
@@ -3055,6 +3080,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                        overrideMask, 0, subId), timeoutMillis);
                        overrideMask, 0, subId), timeoutMillis);
            }
            }
        }
        }
    }


    @Override
    @Override
    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
@@ -4695,11 +4721,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {


        @Override
        @Override
        public long getSubscriptionOpportunisticQuota(Network network, int quotaType) {
        public long getSubscriptionOpportunisticQuota(Network network, int quotaType) {
            final long quotaBytes;
            synchronized (mNetworkPoliciesSecondLock) {
            synchronized (mNetworkPoliciesSecondLock) {
                // TODO: handle splitting quota between use-cases
                quotaBytes = mSubscriptionOpportunisticQuota.get(getSubIdLocked(network),
                return mSubscriptionOpportunisticQuota.get(getSubIdLocked(network),
                        OPPORTUNISTIC_QUOTA_UNKNOWN);
                        OPPORTUNISTIC_QUOTA_UNKNOWN);
            }
            }
            if (quotaBytes == OPPORTUNISTIC_QUOTA_UNKNOWN) {
                return OPPORTUNISTIC_QUOTA_UNKNOWN;
            }

            if (quotaType == QUOTA_TYPE_JOBS) {
                return (long) (quotaBytes * Settings.Global.getFloat(mContext.getContentResolver(),
                        NETPOLICY_QUOTA_FRAC_JOBS, QUOTA_FRAC_JOBS_DEFAULT));
            } else if (quotaType == QUOTA_TYPE_MULTIPATH) {
                return (long) (quotaBytes * Settings.Global.getFloat(mContext.getContentResolver(),
                        NETPOLICY_QUOTA_FRAC_MULTIPATH, QUOTA_FRAC_MULTIPATH_DEFAULT));
            } else {
                return OPPORTUNISTIC_QUOTA_UNKNOWN;
            }
        }
        }


        @Override
        @Override
+99 −0
Original line number Original line Diff line number Diff line
@@ -37,9 +37,12 @@ import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEF
import static android.telephony.CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG;
import static android.telephony.CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG;
import static android.telephony.CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG;
import static android.telephony.CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG;
import static android.telephony.CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT;
import static android.telephony.CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT;
import static android.telephony.SubscriptionPlan.BYTES_UNLIMITED;
import static android.telephony.SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED;
import static android.telephony.SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED;
import static android.text.format.Time.TIMEZONE_UTC;
import static android.text.format.Time.TIMEZONE_UTC;


import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_JOBS;
import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_RAPID;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_RAPID;
@@ -1484,6 +1487,102 @@ public class NetworkPolicyManagerServiceTest {
                true);
                true);
    }
    }


    @Test
    public void testOpportunisticQuota() throws Exception {
        final Network net = new Network(TEST_NET_ID);
        final NetworkPolicyManagerInternal internal = LocalServices
                .getService(NetworkPolicyManagerInternal.class);

        // Create a place to store fake usage
        final NetworkStatsHistory history = new NetworkStatsHistory(TimeUnit.HOURS.toMillis(1));
        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
        when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
                .thenAnswer(new Answer<Long>() {
                    @Override
                    public Long answer(InvocationOnMock invocation) throws Throwable {
                        final NetworkStatsHistory.Entry entry = history.getValues(
                                invocation.getArgument(1), invocation.getArgument(2), null);
                        return entry.rxBytes + entry.txBytes;
                    }
                });
        when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
                .thenAnswer(new Answer<NetworkStats>() {
                    @Override
                    public NetworkStats answer(InvocationOnMock invocation) throws Throwable {
                        return stats;
                    }
                });

        // Get active mobile network in place
        expectMobileDefaults();
        mService.updateNetworks();

        // We're 20% through the month (6 days)
        final long start = parseTime("2015-11-01T00:00Z");
        final long end = parseTime("2015-11-07T00:00Z");
        setCurrentTimeMillis(end);

        // Get some data usage in place
        history.clear();
        history.recordData(start, end,
                new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(360), 0L, 0L, 0L, 0));

        // No data plan
        {
            reset(mTelephonyManager, mNetworkManager, mNotifManager);
            expectMobileDefaults();

            mService.updateNetworks();

            // No quotas
            assertEquals(-1, internal.getSubscriptionOpportunisticQuota(net, QUOTA_TYPE_JOBS));
            assertEquals(-1, internal.getSubscriptionOpportunisticQuota(net, QUOTA_TYPE_MULTIPATH));
        }

        // Limited data plan
        {
            final SubscriptionPlan plan = SubscriptionPlan.Builder
                    .createRecurringMonthly(ZonedDateTime.parse("2015-11-01T00:00:00.00Z"))
                    .setDataLimit(DataUnit.MEGABYTES.toBytes(1800), LIMIT_BEHAVIOR_DISABLED)
                    .build();
            mService.setSubscriptionPlans(TEST_SUB_ID, new SubscriptionPlan[] { plan },
                    mServiceContext.getOpPackageName());

            reset(mTelephonyManager, mNetworkManager, mNotifManager);
            expectMobileDefaults();

            mService.updateNetworks();

            // We have 1440MB and 24 days left, which is 60MB/day; assuming 10%
            // for quota split equally between two types gives 3MB.
            assertEquals(DataUnit.MEGABYTES.toBytes(3),
                    internal.getSubscriptionOpportunisticQuota(net, QUOTA_TYPE_JOBS));
            assertEquals(DataUnit.MEGABYTES.toBytes(3),
                    internal.getSubscriptionOpportunisticQuota(net, QUOTA_TYPE_MULTIPATH));
        }

        // Unlimited data plan
        {
            final SubscriptionPlan plan = SubscriptionPlan.Builder
                    .createRecurringMonthly(ZonedDateTime.parse("2015-11-01T00:00:00.00Z"))
                    .setDataLimit(BYTES_UNLIMITED, LIMIT_BEHAVIOR_DISABLED)
                    .build();
            mService.setSubscriptionPlans(TEST_SUB_ID, new SubscriptionPlan[] { plan },
                    mServiceContext.getOpPackageName());

            reset(mTelephonyManager, mNetworkManager, mNotifManager);
            expectMobileDefaults();

            mService.updateNetworks();

            // 20MB/day, split equally between two types gives 10MB.
            assertEquals(DataUnit.MEBIBYTES.toBytes(10),
                    internal.getSubscriptionOpportunisticQuota(net, QUOTA_TYPE_JOBS));
            assertEquals(DataUnit.MEBIBYTES.toBytes(10),
                    internal.getSubscriptionOpportunisticQuota(net, QUOTA_TYPE_MULTIPATH));
        }
    }

    private ApplicationInfo buildApplicationInfo(String label) {
    private ApplicationInfo buildApplicationInfo(String label) {
        final ApplicationInfo ai = new ApplicationInfo();
        final ApplicationInfo ai = new ApplicationInfo();
        ai.nonLocalizedLabel = label;
        ai.nonLocalizedLabel = label;