Fix spamming of network stats updated intent

While the reason of triggering frequently polls is still unknown
(b/343844995), this commit prevents the spamming of network stats
update intents by sending broadcast messages at intervals of at
least one second. It also ensures that update requests experience
a delay of no more than one second. This is safe since
NETWORK_STATS_UPDATED intent is only use for signaling updated
of NetworkStats, which is stateless and not very time sensitive.
A kill-switch flag is included for rollback if needed.

However, while the intent was not be able to deprecated, all
callers should migrate to use registerDataUsageCallback
with proper threshold instead.

Test: atest FrameworksNetTests:android.net.connectivity.com.android.\
	server.net.NetworkStatsServiceTest\
	#testNetworkStatsUpdatedIntentSpam_rateLimitOn
Test: atest FrameworksNetTests:android.net.connectivity.com.android.\
	server.net.NetworkStatsServiceTest\
	#testNetworkStatsUpdatedIntentSpam_rateLimitOff
Bug: 343844995
Change-Id: I972f0778b823ed0dc1f35b1b011f1ad225ca020c
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 114cf2e..9e1f105 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -257,6 +257,12 @@
      */
     private static final int DEFAULT_PERFORM_POLL_DELAY_MS = 1000;
 
+    /**
+     * The delay time between to network stats update intents.
+     * Added to fix intent spams (b/3115462)
+     */
+    private static final int BROADCAST_NETWORK_STATS_UPDATED_DELAY_MS = 1000;
+
     private static final String TAG_NETSTATS_ERROR = "netstats_error";
 
     /**
@@ -469,15 +475,31 @@
 
     private long mLastStatsSessionPoll;
 
+    /**
+     * The latest time of broadcasting network stats updated message.
+     * Note that this time could be in the past for already done broadcasts,
+     * or in the future for scheduled broadcasts. This record is needed for
+     * rate limiting intents to prevent intent spams (b/3115462)
+     */
+    @GuardedBy("mStatsLock")
+    private long mLatestNetworkStatsUpdatedBroadcastScheduledTime = -1;
+
+
     private final TrafficStatsRateLimitCache mTrafficStatsTotalCache;
     private final TrafficStatsRateLimitCache mTrafficStatsIfaceCache;
     private final TrafficStatsRateLimitCache mTrafficStatsUidCache;
     static final String TRAFFICSTATS_RATE_LIMIT_CACHE_ENABLED_FLAG =
             "trafficstats_rate_limit_cache_enabled_flag";
+    static final String BROADCAST_NETWORK_STATS_UPDATED_RATE_LIMIT_ENABLED_FLAG =
+            "broadcast_network_stats_updated_rate_limit_enabled_flag";
     private final boolean mAlwaysUseTrafficStatsRateLimitCache;
     private final int mTrafficStatsRateLimitCacheExpiryDuration;
     private final int mTrafficStatsRateLimitCacheMaxEntries;
 
+    private final boolean mBroadcastNetworkStatsUpdatedRateLimitEnabled;
+
+
+
     private final Object mOpenSessionCallsLock = new Object();
 
     /**
@@ -669,6 +691,8 @@
 
         mAlwaysUseTrafficStatsRateLimitCache =
                 mDeps.alwaysUseTrafficStatsRateLimitCache(mContext);
+        mBroadcastNetworkStatsUpdatedRateLimitEnabled =
+                mDeps.enabledBroadcastNetworkStatsUpdatedRateLimiting(mContext);
         mTrafficStatsRateLimitCacheExpiryDuration =
                 mDeps.getTrafficStatsRateLimitCacheExpiryDuration();
         mTrafficStatsRateLimitCacheMaxEntries =
@@ -927,6 +951,17 @@
         }
 
         /**
+         * Get whether broadcast network stats update rate limiting is enabled.
+         *
+         * This method should only be called once in the constructor,
+         * to ensure that the code does not need to deal with flag values changing at runtime.
+         */
+        public boolean enabledBroadcastNetworkStatsUpdatedRateLimiting(Context ctx) {
+            return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(
+                    ctx, BROADCAST_NETWORK_STATS_UPDATED_RATE_LIMIT_ENABLED_FLAG);
+        }
+
+        /**
          * Get whether TrafficStats rate-limit cache is always applied.
          *
          * This method should only be called once in the constructor,
@@ -2645,8 +2680,20 @@
             performSampleLocked();
         }
 
-        // finally, dispatch updated event to any listeners
-        mHandler.sendMessage(mHandler.obtainMessage(MSG_BROADCAST_NETWORK_STATS_UPDATED));
+        // Dispatch updated event to listeners, preventing intent spamming
+        // (b/343844995) possibly from abnormal modem RAT changes or misbehaving
+        // app calls (see NetworkStatsEventLogger#POLL_REASON_* for possible reasons).
+        // If no broadcasts are scheduled, use the time of the last broadcast
+        // to schedule the next one ASAP.
+        if (!mBroadcastNetworkStatsUpdatedRateLimitEnabled) {
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_BROADCAST_NETWORK_STATS_UPDATED));
+        } else if (mLatestNetworkStatsUpdatedBroadcastScheduledTime < SystemClock.uptimeMillis()) {
+            mLatestNetworkStatsUpdatedBroadcastScheduledTime = Math.max(SystemClock.uptimeMillis(),
+                    mLatestNetworkStatsUpdatedBroadcastScheduledTime
+                    + BROADCAST_NETWORK_STATS_UPDATED_DELAY_MS);
+            mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_BROADCAST_NETWORK_STATS_UPDATED),
+                    mLatestNetworkStatsUpdatedBroadcastScheduledTime);
+        }
 
         Trace.traceEnd(TRACE_TAG_NETWORK);
     }