Skip to content

Commit daa57e8

Browse files
committed
Migrate network stats from removed users.
When a user is removed, migrate all network stats belonging to that user into special UID_REMOVED bucket. Also removes those stats from kernel to avoid double-counting if another user is created. Bug: 7194784 Change-Id: I03f1d660fe3754566326b7749cae8068fc224ea9
1 parent 4046e01 commit daa57e8

File tree

5 files changed

+86
-24
lines changed

5 files changed

+86
-24
lines changed

core/java/android/net/NetworkStats.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import android.os.SystemClock;
2222
import android.util.SparseBooleanArray;
2323

24+
import com.android.internal.util.ArrayUtils;
2425
import com.android.internal.util.Objects;
2526

2627
import java.io.CharArrayWriter;
@@ -608,13 +609,13 @@ public NetworkStats groupedByUid() {
608609
* Return all rows except those attributed to the requested UID; doesn't
609610
* mutate the original structure.
610611
*/
611-
public NetworkStats withoutUid(int uid) {
612+
public NetworkStats withoutUids(int[] uids) {
612613
final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
613614

614615
Entry entry = new Entry();
615616
for (int i = 0; i < size; i++) {
616617
entry = getValues(i, entry);
617-
if (entry.uid != uid) {
618+
if (!ArrayUtils.contains(uids, entry.uid)) {
618619
stats.addValues(entry);
619620
}
620621
}

core/tests/coretests/src/android/net/NetworkStatsTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ public void testWithoutUid() throws Exception {
287287
.addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L)
288288
.addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 128L, 8L, 0L, 0L, 0L);
289289

290-
final NetworkStats after = before.withoutUid(100);
290+
final NetworkStats after = before.withoutUids(new int[] { 100 });
291291
assertEquals(6, before.size());
292292
assertEquals(2, after.size());
293293
assertValues(after, 0, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L);

services/java/com/android/server/net/NetworkStatsCollection.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import android.text.format.DateUtils;
3232
import android.util.AtomicFile;
3333

34+
import com.android.internal.util.ArrayUtils;
3435
import com.android.internal.util.FileRotator;
3536
import com.android.internal.util.IndentingPrintWriter;
3637
import com.android.internal.util.Objects;
@@ -431,13 +432,13 @@ public void readLegacyUid(File file, boolean onlyTags) throws IOException {
431432
* moving any {@link NetworkStats#TAG_NONE} series to
432433
* {@link TrafficStats#UID_REMOVED}.
433434
*/
434-
public void removeUid(int uid) {
435+
public void removeUids(int[] uids) {
435436
final ArrayList<Key> knownKeys = Lists.newArrayList();
436437
knownKeys.addAll(mStats.keySet());
437438

438439
// migrate all UID stats into special "removed" bucket
439440
for (Key key : knownKeys) {
440-
if (key.uid == uid) {
441+
if (ArrayUtils.contains(uids, key.uid)) {
441442
// only migrate combined TAG_NONE history
442443
if (key.tag == TAG_NONE) {
443444
final NetworkStatsHistory uidHistory = mStats.get(key);

services/java/com/android/server/net/NetworkStatsRecorder.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import java.io.InputStream;
4343
import java.io.OutputStream;
4444
import java.lang.ref.WeakReference;
45+
import java.util.Arrays;
4546
import java.util.HashSet;
4647
import java.util.Map;
4748

@@ -233,23 +234,27 @@ public void forcePersistLocked(long currentTimeMillis) {
233234
* Remove the given UID from all {@link FileRotator} history, migrating it
234235
* to {@link TrafficStats#UID_REMOVED}.
235236
*/
236-
public void removeUidLocked(int uid) {
237+
public void removeUidsLocked(int[] uids) {
237238
try {
238-
// process all existing data to migrate uid
239-
mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uid));
239+
// Rewrite all persisted data to migrate UID stats
240+
mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids));
240241
} catch (IOException e) {
241-
Log.wtf(TAG, "problem removing UID " + uid, e);
242+
Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
242243
recoverFromWtf();
243244
}
244245

245-
// clear UID from current stats snapshot
246+
// Remove any pending stats
247+
mPending.removeUids(uids);
248+
mSinceBoot.removeUids(uids);
249+
250+
// Clear UID from current stats snapshot
246251
if (mLastSnapshot != null) {
247-
mLastSnapshot = mLastSnapshot.withoutUid(uid);
252+
mLastSnapshot = mLastSnapshot.withoutUids(uids);
248253
}
249254

250255
final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
251256
if (complete != null) {
252-
complete.removeUid(uid);
257+
complete.removeUids(uids);
253258
}
254259
}
255260

@@ -293,11 +298,11 @@ public void write(OutputStream out) throws IOException {
293298
*/
294299
public static class RemoveUidRewriter implements FileRotator.Rewriter {
295300
private final NetworkStatsCollection mTemp;
296-
private final int mUid;
301+
private final int[] mUids;
297302

298-
public RemoveUidRewriter(long bucketDuration, int uid) {
303+
public RemoveUidRewriter(long bucketDuration, int[] uids) {
299304
mTemp = new NetworkStatsCollection(bucketDuration);
300-
mUid = uid;
305+
mUids = uids;
301306
}
302307

303308
@Override
@@ -309,7 +314,7 @@ public void reset() {
309314
public void read(InputStream in) throws IOException {
310315
mTemp.read(in);
311316
mTemp.clearDirty();
312-
mTemp.removeUid(mUid);
317+
mTemp.removeUids(mUids);
313318
}
314319

315320
@Override

services/java/com/android/server/net/NetworkStatsService.java

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
2424
import static android.content.Intent.ACTION_SHUTDOWN;
2525
import static android.content.Intent.ACTION_UID_REMOVED;
26+
import static android.content.Intent.ACTION_USER_REMOVED;
2627
import static android.content.Intent.EXTRA_UID;
2728
import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
2829
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
@@ -76,6 +77,8 @@
7677
import android.content.Context;
7778
import android.content.Intent;
7879
import android.content.IntentFilter;
80+
import android.content.pm.ApplicationInfo;
81+
import android.content.pm.PackageManager;
7982
import android.net.IConnectivityManager;
8083
import android.net.INetworkManagementEventObserver;
8184
import android.net.INetworkStatsService;
@@ -112,6 +115,7 @@
112115
import android.util.SparseIntArray;
113116
import android.util.TrustedTime;
114117

118+
import com.android.internal.util.ArrayUtils;
115119
import com.android.internal.util.FileRotator;
116120
import com.android.internal.util.IndentingPrintWriter;
117121
import com.android.server.EventLogTags;
@@ -122,8 +126,10 @@
122126
import java.io.FileDescriptor;
123127
import java.io.IOException;
124128
import java.io.PrintWriter;
129+
import java.util.Arrays;
125130
import java.util.HashMap;
126131
import java.util.HashSet;
132+
import java.util.List;
127133

128134
/**
129135
* Collect and persist detailed network statistics, and provide this data to
@@ -322,6 +328,10 @@ public void systemReady() {
322328
final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
323329
mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
324330

331+
// listen for user changes to clean stats
332+
final IntentFilter userFilter = new IntentFilter(ACTION_USER_REMOVED);
333+
mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
334+
325335
// persist stats during clean shutdown
326336
final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN);
327337
mContext.registerReceiver(mShutdownReceiver, shutdownFilter);
@@ -739,11 +749,34 @@ public void onReceive(Context context, Intent intent) {
739749
public void onReceive(Context context, Intent intent) {
740750
// on background handler thread, and UID_REMOVED is protected
741751
// broadcast.
742-
final int uid = intent.getIntExtra(EXTRA_UID, 0);
752+
753+
final int uid = intent.getIntExtra(EXTRA_UID, -1);
754+
if (uid == -1) return;
755+
756+
synchronized (mStatsLock) {
757+
mWakeLock.acquire();
758+
try {
759+
removeUidsLocked(uid);
760+
} finally {
761+
mWakeLock.release();
762+
}
763+
}
764+
}
765+
};
766+
767+
private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
768+
@Override
769+
public void onReceive(Context context, Intent intent) {
770+
// On background handler thread, and USER_REMOVED is protected
771+
// broadcast.
772+
773+
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
774+
if (userId == -1) return;
775+
743776
synchronized (mStatsLock) {
744777
mWakeLock.acquire();
745778
try {
746-
removeUidLocked(uid);
779+
removeUserLocked(userId);
747780
} finally {
748781
mWakeLock.release();
749782
}
@@ -1034,15 +1067,37 @@ private void performSampleLocked() {
10341067
/**
10351068
* Clean up {@link #mUidRecorder} after UID is removed.
10361069
*/
1037-
private void removeUidLocked(int uid) {
1038-
// perform one last poll before removing
1070+
private void removeUidsLocked(int... uids) {
1071+
if (LOGV) Slog.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids));
1072+
1073+
// Perform one last poll before removing
10391074
performPollLocked(FLAG_PERSIST_ALL);
10401075

1041-
mUidRecorder.removeUidLocked(uid);
1042-
mUidTagRecorder.removeUidLocked(uid);
1076+
mUidRecorder.removeUidsLocked(uids);
1077+
mUidTagRecorder.removeUidsLocked(uids);
1078+
1079+
// Clear kernel stats associated with UID
1080+
for (int uid : uids) {
1081+
resetKernelUidStats(uid);
1082+
}
1083+
}
1084+
1085+
/**
1086+
* Clean up {@link #mUidRecorder} after user is removed.
1087+
*/
1088+
private void removeUserLocked(int userId) {
1089+
if (LOGV) Slog.v(TAG, "removeUserLocked() for userId=" + userId);
1090+
1091+
// Build list of UIDs that we should clean up
1092+
int[] uids = new int[0];
1093+
final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
1094+
PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS);
1095+
for (ApplicationInfo app : apps) {
1096+
final int uid = UserHandle.getUid(userId, app.uid);
1097+
uids = ArrayUtils.appendInt(uids, uid);
1098+
}
10431099

1044-
// clear kernel stats associated with UID
1045-
resetKernelUidStats(uid);
1100+
removeUidsLocked(uids);
10461101
}
10471102

10481103
@Override

0 commit comments

Comments
 (0)