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

Commit 1a6c9e60 authored by Remi NGUYEN VAN's avatar Remi NGUYEN VAN Committed by android-build-merger
Browse files

Merge "Add settings to configure default multipath quota." into pi-dev

am: 9ab1da20

Change-Id: I01e25079def030c43b0800d610590a3a6a5ac1be
parents e12daed0 9ab1da20
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -9316,6 +9316,15 @@ public final class Settings {
       public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
               "network_metered_multipath_preference";

        /**
         * Default daily multipath budget used by ConnectivityManager.getMultipathPreference()
         * on metered networks. This default quota is only used if quota could not be determined
         * from data plan or data limit/warning set by the user.
         * @hide
         */
        public static final String NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES =
                "network_default_daily_multipath_quota_bytes";

        /**
         * Network watchlist last report time.
         * @hide
+7 −0
Original line number Diff line number Diff line
@@ -327,6 +327,13 @@
         This is the default value of that setting. -->
    <integer translatable="false" name="config_networkMeteredMultipathPreference">0</integer>

    <!-- Default daily multipath budget used by ConnectivityManager.getMultipathPreference()
         on metered networks. This default quota only used if quota could not be determined from
         data plan or data limit/warning set by the user. The value that is actually used is
         controlled by Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES. This is the
         default value of that setting. -->
    <integer translatable="false" name="config_networkDefaultDailyMultipathQuotaBytes">2500000</integer>

    <!-- List of regexpressions describing the interface (if any) that represent tetherable
         USB interfaces.  If the device doesn't want to support tethering over USB this should
         be empty.  An example would be "usb.*" -->
+1 −0
Original line number Diff line number Diff line
@@ -1922,6 +1922,7 @@
  <java-symbol type="integer" name="config_networkWakeupPacketMask" />
  <java-symbol type="bool" name="config_apfDrop802_3Frames" />
  <java-symbol type="array" name="config_apfEthTypeBlackList" />
  <java-symbol type="integer" name="config_networkDefaultDailyMultipathQuotaBytes" />
  <java-symbol type="integer" name="config_networkMeteredMultipathPreference" />
  <java-symbol type="integer" name="config_notificationsBatteryFullARGB" />
  <java-symbol type="integer" name="config_notificationsBatteryLedOff" />
+1 −0
Original line number Diff line number Diff line
@@ -302,6 +302,7 @@ public class SettingsBackupTest {
                    Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES,
                    Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE,
                    Settings.Global.NETWORK_AVOID_BAD_WIFI,
                    Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES,
                    Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE,
                    Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME,
                    Settings.Global.NETWORK_PREFERENCE,
+82 −10
Original line number Diff line number Diff line
@@ -24,13 +24,19 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES;

import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH;
import static com.android.server.net.NetworkPolicyManagerService.OPPORTUNISTIC_QUOTA_UNKNOWN;

import android.app.usage.NetworkStatsManager;
import android.app.usage.NetworkStatsManager.UsageCallback;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
@@ -45,11 +51,15 @@ import android.net.StringNetworkSpecifier;
import android.os.BestClock;
import android.os.Handler;
import android.os.SystemClock;
import android.net.Uri;
import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.DebugUtils;
import android.util.Pair;
import android.util.Slog;

import com.android.internal.R;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.net.NetworkPolicyManagerInternal;
@@ -60,7 +70,6 @@ import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@@ -85,6 +94,9 @@ public class MultipathPolicyTracker {
    private final Handler mHandler;
    private final Clock mClock;
    private final Dependencies mDeps;
    private final ContentResolver mResolver;
    private final SettingsObserver mSettingsObserver;
    private final ConfigChangeReceiver mConfigChangeReceiver;

    private ConnectivityManager mCM;
    private NetworkPolicyManager mNPM;
@@ -93,8 +105,6 @@ public class MultipathPolicyTracker {
    private NetworkCallback mMobileNetworkCallback;
    private NetworkPolicyManager.Listener mPolicyListener;

    // STOPSHIP: replace this with a configurable mechanism.
    private static final long DEFAULT_DAILY_MULTIPATH_QUOTA = 2_500_000;

    /**
     * Divider to calculate opportunistic quota from user-set data limit or warning: 5% of user-set
@@ -118,6 +128,9 @@ public class MultipathPolicyTracker {
        mHandler = handler;
        mClock = deps.getClock();
        mDeps = deps;
        mResolver = mContext.getContentResolver();
        mSettingsObserver = new SettingsObserver(mHandler);
        mConfigChangeReceiver = new ConfigChangeReceiver();
        // Because we are initialized by the ConnectivityService constructor, we can't touch any
        // connectivity APIs. Service initialization is done in start().
    }
@@ -129,6 +142,14 @@ public class MultipathPolicyTracker {

        registerTrackMobileCallback();
        registerNetworkPolicyListener();
        final Uri defaultSettingUri =
                Settings.Global.getUriFor(NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES);
        mResolver.registerContentObserver(defaultSettingUri, false, mSettingsObserver);

        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
        mContext.registerReceiverAsUser(
                mConfigChangeReceiver, UserHandle.ALL, intentFilter, null, mHandler);
    }

    public void shutdown() {
@@ -138,6 +159,8 @@ public class MultipathPolicyTracker {
            t.shutdown();
        }
        mMultipathTrackers.clear();
        mResolver.unregisterContentObserver(mSettingsObserver);
        mContext.unregisterReceiver(mConfigChangeReceiver);
    }

    // Called on an arbitrary binder thread.
@@ -292,11 +315,11 @@ public class MultipathPolicyTracker {
            // Fallback to user settings-based quota if not available from phone plan
            if (quota == OPPORTUNISTIC_QUOTA_UNKNOWN) {
                quota = getUserPolicyOpportunisticQuotaBytes();
                if (DBG) Slog.d(TAG, "Opportunistic quota from user policy: " + quota + " bytes");
            }

            if (quota == OPPORTUNISTIC_QUOTA_UNKNOWN) {
                // STOPSHIP: replace this with a configurable mechanism.
                quota = DEFAULT_DAILY_MULTIPATH_QUOTA;
                quota = getDefaultDailyMultipathQuotaBytes();
                if (DBG) Slog.d(TAG, "Setting quota: " + quota + " bytes");
            }

@@ -374,6 +397,21 @@ public class MultipathPolicyTracker {
    private final ConcurrentHashMap <Network, MultipathTracker> mMultipathTrackers =
            new ConcurrentHashMap<>();

    private long getDefaultDailyMultipathQuotaBytes() {
        final String setting = Settings.Global.getString(mContext.getContentResolver(),
                NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES);
        if (setting != null) {
            try {
                return Long.parseLong(setting);
            } catch(NumberFormatException e) {
                // fall through
            }
        }

        return mContext.getResources().getInteger(
                R.integer.config_networkDefaultDailyMultipathQuotaBytes);
    }

    // TODO: this races with app code that might respond to onAvailable() by immediately calling
    // getMultipathPreference. Fix this by adding to ConnectivityService the ability to directly
    // invoke NetworkCallbacks on tightly-coupled classes such as this one which run on its
@@ -415,6 +453,15 @@ public class MultipathPolicyTracker {
        mCM.registerNetworkCallback(request, mMobileNetworkCallback, mHandler);
    }

    /**
     * Update multipath budgets for all trackers. To be called on the mHandler thread.
     */
    private void updateAllMultipathBudgets() {
        for (MultipathTracker t : mMultipathTrackers.values()) {
            t.updateMultipathBudget();
        }
    }

    private void maybeUnregisterTrackMobileCallback() {
        if (mMobileNetworkCallback != null) {
            mCM.unregisterNetworkCallback(mMobileNetworkCallback);
@@ -427,11 +474,7 @@ public class MultipathPolicyTracker {
            @Override
            public void onMeteredIfacesChanged(String[] meteredIfaces) {
                // Dispatched every time opportunistic quota is recalculated.
                mHandler.post(() -> {
                    for (MultipathTracker t : mMultipathTrackers.values()) {
                        t.updateMultipathBudget();
                    }
                });
                mHandler.post(() -> updateAllMultipathBudgets());
            }
        };
        mNPM.registerListener(mPolicyListener);
@@ -441,6 +484,35 @@ public class MultipathPolicyTracker {
        mNPM.unregisterListener(mPolicyListener);
    }

    private final class SettingsObserver extends ContentObserver {
        public SettingsObserver(Handler handler) {
            super(handler);
        }

        @Override
        public void onChange(boolean selfChange) {
            Slog.wtf(TAG, "Should never be reached.");
        }

        @Override
        public void onChange(boolean selfChange, Uri uri) {
            if (!Settings.Global.getUriFor(NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES)
                    .equals(uri)) {
                Slog.wtf(TAG, "Unexpected settings observation: " + uri);
            }
            if (DBG) Slog.d(TAG, "Settings change: updating budgets.");
            updateAllMultipathBudgets();
        }
    }

    private final class ConfigChangeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (DBG) Slog.d(TAG, "Configuration change: updating budgets.");
            updateAllMultipathBudgets();
        }
    }

    public void dump(IndentingPrintWriter pw) {
        // Do not use in production. Access to class data is only safe on the handler thrad.
        pw.println("MultipathPolicyTracker:");