From 27c8a07be62321f2c724c6b5a01e82bdf2e76bfd Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 9 Mar 2016 16:40:15 -0700 Subject: [PATCH] Restrict TrafficStats due to privacy concerns. Granular per-UID network statistics can be used to infer user behavior over time, so they fall under the umbrella of the PACKAGE_USAGE_STATS permission. Since we can't check app-ops based permissions in the kernel, the best we can do is redirect users to the NetworkStatsManager class, which offers a much more robust historical data set. Bug: 27577101 Change-Id: I696bdc5e0b3d7e24acf35f388d0ab13617ed8af3 --- core/java/android/net/TrafficStats.java | 75 ++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index ba8bd34bfc..95ffb44d22 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -19,6 +19,7 @@ package android.net; import android.annotation.SystemApi; import android.app.DownloadManager; import android.app.backup.BackupManager; +import android.app.usage.NetworkStatsManager; import android.content.Context; import android.media.MediaPlayer; import android.os.RemoteException; @@ -33,12 +34,16 @@ import java.net.Socket; import java.net.SocketException; /** - * Class that provides network traffic statistics. These statistics include + * Class that provides network traffic statistics. These statistics include * bytes transmitted and received and network packets transmitted and received, * over all interfaces, over the mobile interface, and on a per-UID basis. *

- * These statistics may not be available on all platforms. If the statistics - * are not supported by this device, {@link #UNSUPPORTED} will be returned. + * These statistics may not be available on all platforms. If the statistics are + * not supported by this device, {@link #UNSUPPORTED} will be returned. + *

+ * Note that the statistics returned by this class reset and start from zero + * after every reboot. To access more robust historical network statistics data, + * use {@link NetworkStatsManager} instead. */ public class TrafficStats { /** @@ -497,14 +502,27 @@ public class TrafficStats { * monotonically since device boot. Statistics are measured at the network * layer, so they include both TCP and UDP usage. *

- * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return - * {@link #UNSUPPORTED} on devices where statistics aren't available. + * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may + * return {@link #UNSUPPORTED} on devices where statistics aren't available. + *

+ * Starting in {@link android.os.Build.VERSION_CODES#N} this will only + * report traffic statistics for the calling UID. It will return + * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access + * historical network statistics belonging to other UIDs, use + * {@link NetworkStatsManager}. * * @see android.os.Process#myUid() * @see android.content.pm.ApplicationInfo#uid */ public static long getUidTxBytes(int uid) { - return nativeGetUidStat(uid, TYPE_TX_BYTES); + // This isn't actually enforcing any security; it just returns the + // unsupported value. The real filtering is done at the kernel level. + final int callingUid = android.os.Process.myUid(); + if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { + return nativeGetUidStat(uid, TYPE_TX_BYTES); + } else { + return UNSUPPORTED; + } } /** @@ -515,12 +533,25 @@ public class TrafficStats { *

* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return * {@link #UNSUPPORTED} on devices where statistics aren't available. + *

+ * Starting in {@link android.os.Build.VERSION_CODES#N} this will only + * report traffic statistics for the calling UID. It will return + * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access + * historical network statistics belonging to other UIDs, use + * {@link NetworkStatsManager}. * * @see android.os.Process#myUid() * @see android.content.pm.ApplicationInfo#uid */ public static long getUidRxBytes(int uid) { - return nativeGetUidStat(uid, TYPE_RX_BYTES); + // This isn't actually enforcing any security; it just returns the + // unsupported value. The real filtering is done at the kernel level. + final int callingUid = android.os.Process.myUid(); + if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { + return nativeGetUidStat(uid, TYPE_RX_BYTES); + } else { + return UNSUPPORTED; + } } /** @@ -531,12 +562,25 @@ public class TrafficStats { *

* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return * {@link #UNSUPPORTED} on devices where statistics aren't available. + *

+ * Starting in {@link android.os.Build.VERSION_CODES#N} this will only + * report traffic statistics for the calling UID. It will return + * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access + * historical network statistics belonging to other UIDs, use + * {@link NetworkStatsManager}. * * @see android.os.Process#myUid() * @see android.content.pm.ApplicationInfo#uid */ public static long getUidTxPackets(int uid) { - return nativeGetUidStat(uid, TYPE_TX_PACKETS); + // This isn't actually enforcing any security; it just returns the + // unsupported value. The real filtering is done at the kernel level. + final int callingUid = android.os.Process.myUid(); + if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { + return nativeGetUidStat(uid, TYPE_TX_PACKETS); + } else { + return UNSUPPORTED; + } } /** @@ -547,12 +591,25 @@ public class TrafficStats { *

* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return * {@link #UNSUPPORTED} on devices where statistics aren't available. + *

+ * Starting in {@link android.os.Build.VERSION_CODES#N} this will only + * report traffic statistics for the calling UID. It will return + * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access + * historical network statistics belonging to other UIDs, use + * {@link NetworkStatsManager}. * * @see android.os.Process#myUid() * @see android.content.pm.ApplicationInfo#uid */ public static long getUidRxPackets(int uid) { - return nativeGetUidStat(uid, TYPE_RX_PACKETS); + // This isn't actually enforcing any security; it just returns the + // unsupported value. The real filtering is done at the kernel level. + final int callingUid = android.os.Process.myUid(); + if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { + return nativeGetUidStat(uid, TYPE_RX_PACKETS); + } else { + return UNSUPPORTED; + } } /**