From e0ec992630dbcb39776cf42d1489745abdd4b1d0 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 29 Mar 2018 16:17:19 +0900 Subject: [PATCH] Add settings to configure default multipath quota. Bug: 72631572 Test: Tests in go/ag/3828171 pass Change-Id: I795debd0328ea7cad32c968cb4b407928e054528 --- core/java/android/provider/Settings.java | 9 ++ core/res/res/values/config.xml | 7 ++ core/res/res/values/symbols.xml | 1 + .../android/provider/SettingsBackupTest.java | 1 + .../connectivity/MultipathPolicyTracker.java | 92 +++++++++++++++++-- 5 files changed, 100 insertions(+), 10 deletions(-) diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 70f343ee5f57b..b4016cef3c9a6 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9300,6 +9300,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 diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index a52a089dca650..776f9a7f11754 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -328,6 +328,13 @@ This is the default value of that setting. --> 0 + + 2500000 + diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 03acd5c3beb6c..ee7f8fbe7e4f0 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1914,6 +1914,7 @@ + diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 2a3fcadb51445..7908ea9009a7f 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -300,6 +300,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, diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java index 53a954444ca4c..3868ea6a1056a 100644 --- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java +++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java @@ -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 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:");