Merge changes from topic "cherrypicker-L63700000954424743:N16900001262878041" into tm-dev
* changes:
Exclude PID for rate-limited
Improve count of openSession callers in dumpsys
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 217a9a6..b2d8b5e 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -159,8 +159,11 @@
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
@@ -374,9 +377,19 @@
private long mLastStatsSessionPoll;
- /** Map from UID to number of opened sessions */
- @GuardedBy("mOpenSessionCallsPerUid")
+ 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;
@@ -407,6 +420,44 @@
Clock.systemUTC());
}
+ /**
+ * This class is a key that used in {@code mOpenSessionCallsPerCaller} to identify the count of
+ * the caller.
+ */
+ private static class OpenSessionKey {
+ public final int uid;
+ public final String 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("uid=").append(uid).append(",");
+ sb.append("package=").append(packageName);
+ sb.append("}");
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(@NonNull Object o) {
+ if (this == o) return true;
+ if (o.getClass() != getClass()) return false;
+
+ final OpenSessionKey key = (OpenSessionKey) o;
+ return this.uid == key.uid && TextUtils.equals(this.packageName, key.packageName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(uid, packageName);
+ }
+ }
+
private final class NetworkStatsHandler extends Handler {
NetworkStatsHandler(@NonNull Looper looper) {
super(looper);
@@ -794,16 +845,27 @@
return openSessionInternal(flags, callingPackage);
}
- private boolean isRateLimitedForPoll(int callingUid) {
- if (callingUid == android.os.Process.SYSTEM_UID) {
- return false;
- }
-
+ private boolean isRateLimitedForPoll(@NonNull OpenSessionKey key) {
final long lastCallTime;
final long now = SystemClock.elapsedRealtime();
- synchronized (mOpenSessionCallsPerUid) {
- int calls = mOpenSessionCallsPerUid.get(callingUid, 0);
- mOpenSessionCallsPerUid.put(callingUid, calls + 1);
+
+ synchronized (mOpenSessionCallsLock) {
+ Integer callsPerCaller = mOpenSessionCallsPerCaller.get(key);
+ if (callsPerCaller == null) {
+ mOpenSessionCallsPerCaller.put((key), 1);
+ } else {
+ 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;
}
@@ -811,7 +873,7 @@
return now - lastCallTime < POLL_RATE_LIMIT_MS;
}
- private int restrictFlagsForCaller(int flags) {
+ private int restrictFlagsForCaller(int flags, @NonNull String callingPackage) {
// All non-privileged callers are not allowed to turn off POLL_ON_OPEN.
final boolean isPrivileged = PermissionUtils.checkAnyPermissionOf(mContext,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
@@ -821,14 +883,15 @@
}
// Non-system uids are rate limited for POLL_ON_OPEN.
final int callingUid = Binder.getCallingUid();
- flags = isRateLimitedForPoll(callingUid)
+ final OpenSessionKey key = new OpenSessionKey(callingUid, callingPackage);
+ flags = isRateLimitedForPoll(key)
? flags & (~NetworkStatsManager.FLAG_POLL_ON_OPEN)
: flags;
return flags;
}
private INetworkStatsSession openSessionInternal(final int flags, final String callingPackage) {
- final int restrictedFlags = restrictFlagsForCaller(flags);
+ final int restrictedFlags = restrictFlagsForCaller(flags, callingPackage);
if ((restrictedFlags & (NetworkStatsManager.FLAG_POLL_ON_OPEN
| NetworkStatsManager.FLAG_POLL_FORCE)) != 0) {
final long ident = Binder.clearCallingIdentity();
@@ -1938,6 +2001,9 @@
for (int uid : uids) {
deleteKernelTagData(uid);
}
+
+ // TODO: Remove the UID's entries from mOpenSessionCallsPerUid and
+ // mOpenSessionCallsPerCaller
}
/**
@@ -2061,25 +2127,21 @@
pw.decreaseIndent();
// Get the top openSession callers
- final SparseIntArray calls;
- synchronized (mOpenSessionCallsPerUid) {
- calls = mOpenSessionCallsPerUid.clone();
+ final HashMap calls;
+ synchronized (mOpenSessionCallsLock) {
+ calls = new HashMap<>(mOpenSessionCallsPerCaller);
}
-
- final int N = calls.size();
- final long[] values = new long[N];
- for (int j = 0; j < N; j++) {
- values[j] = ((long) calls.valueAt(j) << 32) | calls.keyAt(j);
- }
- Arrays.sort(values);
-
- pw.println("Top openSession callers (uid=count):");
+ final List<Map.Entry<OpenSessionKey, Integer>> list = new ArrayList<>(calls.entrySet());
+ Collections.sort(list,
+ (left, right) -> Integer.compare(left.getValue(), right.getValue()));
+ final int num = list.size();
+ final int end = Math.max(0, num - DUMP_STATS_SESSION_COUNT);
+ pw.println("Top openSession callers:");
pw.increaseIndent();
- final int end = Math.max(0, N - DUMP_STATS_SESSION_COUNT);
- for (int j = N - 1; j >= end; j--) {
- final int uid = (int) (values[j] & 0xffffffff);
- final int count = (int) (values[j] >> 32);
- pw.print(uid); pw.print("="); pw.println(count);
+ for (int j = num - 1; j >= end; j--) {
+ final Map.Entry<OpenSessionKey, Integer> entry = list.get(j);
+ pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue());
+
}
pw.decreaseIndent();
pw.println();