Exclude PID for rate-limited
rate-limited would include PID in current design, which means that
an app can ignore the rate-limits by creating a process (a new PID)
every time. Thus, maintain mOpenSessionCallsPerUid for rate-limits
and OpenSessionKey for debugging.
Also, there's no rate-limit for SYSTEM_UID so if the uid is SYSTEM_UID,
the mLastStatsSessionPoll should not be updated. Otherwise, it may
cause an app to be rate-limited to do a query after a system user
polled.
Test: adb shell dumpsys netstats and check the output
Bug: 228081549
Change-Id: I69cc1f3990c9960347691256ed4cb500f9bb48b2
(cherry picked from commit 8d5907fc13bd6238a2eaa56c1d80488c42a2d564)
Merged-In: I69cc1f3990c9960347691256ed4cb500f9bb48b2
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 391356c..05e8fe6 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -377,8 +377,18 @@
private long mLastStatsSessionPoll;
- /** Map from key {@code OpenSessionKey} to count of opened sessions */
- @GuardedBy("mOpenSessionCallsPerCaller")
+ private final Object mOpenSessionCallsLock = new Object();
+ /**
+ * Map from UID to number of opened sessions. This is used for rate-limt an app to open
+ * session frequently
+ */
+ @GuardedBy("mOpenSessionCallsLock")
+ private final SparseIntArray mOpenSessionCallsPerUid = new SparseIntArray();
+ /**
+ * Map from key {@code OpenSessionKey} to count of opened sessions. This is for recording
+ * the caller of open session and it is only for debugging.
+ */
+ @GuardedBy("mOpenSessionCallsLock")
private final HashMap<OpenSessionKey, Integer> mOpenSessionCallsPerCaller = new HashMap<>();
private final static int DUMP_STATS_SESSION_COUNT = 20;
@@ -415,23 +425,20 @@
* the caller.
*/
private static class OpenSessionKey {
- public final int mPid;
- public final int mUid;
- public final String mPackage;
+ public final int uid;
+ public final String packageName;
- OpenSessionKey(int pid, int uid, @NonNull String packageName) {
- mPid = pid;
- mUid = uid;
- mPackage = packageName;
+ OpenSessionKey(int uid, @NonNull String packageName) {
+ this.uid = uid;
+ this.packageName = packageName;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("{");
- sb.append("pid=").append(mPid).append(",");
- sb.append("uid=").append(mUid).append(",");
- sb.append("package=").append(mPackage);
+ sb.append("uid=").append(uid).append(",");
+ sb.append("package=").append(packageName);
sb.append("}");
return sb.toString();
}
@@ -442,13 +449,12 @@
if (o.getClass() != getClass()) return false;
final OpenSessionKey key = (OpenSessionKey) o;
- return mPid == key.mPid && mUid == key.mUid
- && TextUtils.equals(mPackage, key.mPackage);
+ return this.uid == key.uid && TextUtils.equals(this.packageName, key.packageName);
}
@Override
public int hashCode() {
- return Objects.hash(mPid, mUid, mPackage);
+ return Objects.hash(uid, packageName);
}
}
@@ -843,21 +849,27 @@
final long lastCallTime;
final long now = SystemClock.elapsedRealtime();
- synchronized (mOpenSessionCallsPerCaller) {
- Integer calls = mOpenSessionCallsPerCaller.get(key);
- if (calls == null) {
+ synchronized (mOpenSessionCallsLock) {
+ Integer callsPerCaller = mOpenSessionCallsPerCaller.get(key);
+ if (callsPerCaller == null) {
mOpenSessionCallsPerCaller.put((key), 1);
} else {
- mOpenSessionCallsPerCaller.put(key, Integer.sum(calls, 1));
+ mOpenSessionCallsPerCaller.put(key, Integer.sum(callsPerCaller, 1));
}
+
+ int callsPerUid = mOpenSessionCallsPerUid.get(key.uid, 0);
+ mOpenSessionCallsPerUid.put(key.uid, callsPerUid + 1);
+
+ if (key.uid == android.os.Process.SYSTEM_UID) {
+ return false;
+ }
+
+ // To avoid a non-system user to be rate-limited after system users open sessions,
+ // so update mLastStatsSessionPoll after checked if the uid is SYSTEM_UID.
lastCallTime = mLastStatsSessionPoll;
mLastStatsSessionPoll = now;
}
- if (key.mUid == android.os.Process.SYSTEM_UID) {
- return false;
- }
-
return now - lastCallTime < POLL_RATE_LIMIT_MS;
}
@@ -870,9 +882,8 @@
flags |= NetworkStatsManager.FLAG_POLL_ON_OPEN;
}
// Non-system uids are rate limited for POLL_ON_OPEN.
- final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
- final OpenSessionKey key = new OpenSessionKey(callingPid, callingUid, callingPackage);
+ final OpenSessionKey key = new OpenSessionKey(callingUid, callingPackage);
flags = isRateLimitedForPoll(key)
? flags & (~NetworkStatsManager.FLAG_POLL_ON_OPEN)
: flags;
@@ -1989,6 +2000,9 @@
for (int uid : uids) {
deleteKernelTagData(uid);
}
+
+ // TODO: Remove the UID's entries from mOpenSessionCallsPerUid and
+ // mOpenSessionCallsPerCaller
}
/**
@@ -2113,7 +2127,7 @@
// Get the top openSession callers
final HashMap calls;
- synchronized (mOpenSessionCallsPerCaller) {
+ synchronized (mOpenSessionCallsLock) {
calls = new HashMap<>(mOpenSessionCallsPerCaller);
}
final List<Map.Entry<OpenSessionKey, Integer>> list = new ArrayList<>(calls.entrySet());