diff options
author | Jeff Sharkey <jsharkey@android.com> | 2012-09-19 14:10:39 -0700 |
---|---|---|
committer | Jeff Sharkey <jsharkey@android.com> | 2012-09-19 14:54:05 -0700 |
commit | daa57e8d1866fe4579c280c41604f3660db7cd01 (patch) | |
tree | 2632d5d3c145ea83595bc0bb9b944839cccdfcb3 /services | |
parent | 4046e012887fff1f36dfd3eddc6f354d4c2497fc (diff) | |
download | frameworks_base-daa57e8d1866fe4579c280c41604f3660db7cd01.zip frameworks_base-daa57e8d1866fe4579c280c41604f3660db7cd01.tar.gz frameworks_base-daa57e8d1866fe4579c280c41604f3660db7cd01.tar.bz2 |
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
Diffstat (limited to 'services')
3 files changed, 82 insertions, 21 deletions
diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java index 60666b4..3169035 100644 --- a/services/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/java/com/android/server/net/NetworkStatsCollection.java @@ -31,6 +31,7 @@ import android.net.TrafficStats; import android.text.format.DateUtils; import android.util.AtomicFile; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Objects; @@ -431,13 +432,13 @@ public class NetworkStatsCollection implements FileRotator.Reader { * moving any {@link NetworkStats#TAG_NONE} series to * {@link TrafficStats#UID_REMOVED}. */ - public void removeUid(int uid) { + public void removeUids(int[] uids) { final ArrayList<Key> knownKeys = Lists.newArrayList(); knownKeys.addAll(mStats.keySet()); // migrate all UID stats into special "removed" bucket for (Key key : knownKeys) { - if (key.uid == uid) { + if (ArrayUtils.contains(uids, key.uid)) { // only migrate combined TAG_NONE history if (key.tag == TAG_NONE) { final NetworkStatsHistory uidHistory = mStats.get(key); diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java index c3ecf54..2b32b41 100644 --- a/services/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/java/com/android/server/net/NetworkStatsRecorder.java @@ -42,6 +42,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.ref.WeakReference; +import java.util.Arrays; import java.util.HashSet; import java.util.Map; @@ -233,23 +234,27 @@ public class NetworkStatsRecorder { * Remove the given UID from all {@link FileRotator} history, migrating it * to {@link TrafficStats#UID_REMOVED}. */ - public void removeUidLocked(int uid) { + public void removeUidsLocked(int[] uids) { try { - // process all existing data to migrate uid - mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uid)); + // Rewrite all persisted data to migrate UID stats + mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids)); } catch (IOException e) { - Log.wtf(TAG, "problem removing UID " + uid, e); + Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e); recoverFromWtf(); } - // clear UID from current stats snapshot + // Remove any pending stats + mPending.removeUids(uids); + mSinceBoot.removeUids(uids); + + // Clear UID from current stats snapshot if (mLastSnapshot != null) { - mLastSnapshot = mLastSnapshot.withoutUid(uid); + mLastSnapshot = mLastSnapshot.withoutUids(uids); } final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; if (complete != null) { - complete.removeUid(uid); + complete.removeUids(uids); } } @@ -293,11 +298,11 @@ public class NetworkStatsRecorder { */ public static class RemoveUidRewriter implements FileRotator.Rewriter { private final NetworkStatsCollection mTemp; - private final int mUid; + private final int[] mUids; - public RemoveUidRewriter(long bucketDuration, int uid) { + public RemoveUidRewriter(long bucketDuration, int[] uids) { mTemp = new NetworkStatsCollection(bucketDuration); - mUid = uid; + mUids = uids; } @Override @@ -309,7 +314,7 @@ public class NetworkStatsRecorder { public void read(InputStream in) throws IOException { mTemp.read(in); mTemp.clearDirty(); - mTemp.removeUid(mUid); + mTemp.removeUids(mUids); } @Override diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 3a593e4..f2748a3 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -23,6 +23,7 @@ import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; +import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; @@ -76,6 +77,8 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; @@ -112,6 +115,7 @@ import android.util.Slog; import android.util.SparseIntArray; import android.util.TrustedTime; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; @@ -122,8 +126,10 @@ import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; /** * Collect and persist detailed network statistics, and provide this data to @@ -322,6 +328,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED); mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler); + // listen for user changes to clean stats + final IntentFilter userFilter = new IntentFilter(ACTION_USER_REMOVED); + mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler); + // persist stats during clean shutdown final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN); mContext.registerReceiver(mShutdownReceiver, shutdownFilter); @@ -739,11 +749,34 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // on background handler thread, and UID_REMOVED is protected // broadcast. - final int uid = intent.getIntExtra(EXTRA_UID, 0); + + final int uid = intent.getIntExtra(EXTRA_UID, -1); + if (uid == -1) return; + + synchronized (mStatsLock) { + mWakeLock.acquire(); + try { + removeUidsLocked(uid); + } finally { + mWakeLock.release(); + } + } + } + }; + + private BroadcastReceiver mUserReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + // On background handler thread, and USER_REMOVED is protected + // broadcast. + + final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + if (userId == -1) return; + synchronized (mStatsLock) { mWakeLock.acquire(); try { - removeUidLocked(uid); + removeUserLocked(userId); } finally { mWakeLock.release(); } @@ -1034,15 +1067,37 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Clean up {@link #mUidRecorder} after UID is removed. */ - private void removeUidLocked(int uid) { - // perform one last poll before removing + private void removeUidsLocked(int... uids) { + if (LOGV) Slog.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids)); + + // Perform one last poll before removing performPollLocked(FLAG_PERSIST_ALL); - mUidRecorder.removeUidLocked(uid); - mUidTagRecorder.removeUidLocked(uid); + mUidRecorder.removeUidsLocked(uids); + mUidTagRecorder.removeUidsLocked(uids); + + // Clear kernel stats associated with UID + for (int uid : uids) { + resetKernelUidStats(uid); + } + } + + /** + * Clean up {@link #mUidRecorder} after user is removed. + */ + private void removeUserLocked(int userId) { + if (LOGV) Slog.v(TAG, "removeUserLocked() for userId=" + userId); + + // Build list of UIDs that we should clean up + int[] uids = new int[0]; + final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications( + PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS); + for (ApplicationInfo app : apps) { + final int uid = UserHandle.getUid(userId, app.uid); + uids = ArrayUtils.appendInt(uids, uid); + } - // clear kernel stats associated with UID - resetKernelUidStats(uid); + removeUidsLocked(uids); } @Override |