Update network rules on meteredness changes.
The CONFIGURED_NETWORKS_CHANGED_ACTION broadcast can be dispatched
before WifiStateMachine has a chance to update NetworkCapabilities,
resulting in a race condition. To fix this, update network rules
whenever we actually notice a meteredness change take place.
Test: builds, boots
Bug: 64274313
Change-Id: I490eaa789fc0754e4c1c413b6606378ef6f90662
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 07ab417..9fd54ec 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -113,16 +113,20 @@
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.NetworkIdentity;
import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.net.NetworkQuotaInfo;
+import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.NetworkTemplate;
import android.net.TrafficStats;
@@ -444,6 +448,10 @@
@GuardedBy("mUidRulesFirstLock")
final SparseIntArray mUidState = new SparseIntArray();
+ /** Map from network ID to last observed meteredness state */
+ @GuardedBy("mNetworkPoliciesSecondLock")
+ private final SparseBooleanArray mNetworkMetered = new SparseBooleanArray();
+
private final RemoteCallbackList<INetworkPolicyListener>
mListeners = new RemoteCallbackList<>();
@@ -782,6 +790,10 @@
ACTION_CARRIER_CONFIG_CHANGED);
mContext.registerReceiver(mCarrierConfigReceiver, carrierConfigFilter, null, mHandler);
+ // listen for meteredness changes
+ mContext.getSystemService(ConnectivityManager.class).registerNetworkCallback(
+ new NetworkRequest.Builder().build(), mNetworkCallback);
+
mUsageStats.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
// tell systemReady() that the service has been initialized
initCompleteSignal.countDown();
@@ -981,6 +993,26 @@
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
upgradeWifiMeteredOverrideAL();
+ }
+ }
+ // Only need to perform upgrade logic once
+ mContext.unregisterReceiver(this);
+ }
+ };
+
+ private final NetworkCallback mNetworkCallback = new NetworkCallback() {
+ @Override
+ public void onCapabilitiesChanged(Network network,
+ NetworkCapabilities networkCapabilities) {
+ if (network == null || networkCapabilities == null) return;
+
+ synchronized (mNetworkPoliciesSecondLock) {
+ final boolean oldMetered = mNetworkMetered.get(network.netId, false);
+ final boolean newMetered = !networkCapabilities
+ .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+
+ if ((oldMetered != newMetered) || mNetworkMetered.indexOfKey(network.netId) < 0) {
+ mNetworkMetered.put(network.netId, newMetered);
updateNetworkRulesNL();
}
}