blob: bb08be2e3b25724f8df28e03f4c37cc5e9644fcf [file] [log] [blame]
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import android.annotation.SystemApi;
import android.app.DownloadManager;
import android.app.backup.BackupManager;
import android.content.Context;
import android.media.MediaPlayer;
import android.os.RemoteException;
import android.os.ServiceManager;
import com.android.server.NetworkManagementSocketTagger;
import dalvik.system.SocketTagger;
import java.net.Socket;
import java.net.SocketException;
/**
* 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.
* <p>
* These statistics may not be available on all platforms. If the statistics
* are not supported by this device, {@link #UNSUPPORTED} will be returned.
*/
public class TrafficStats {
/**
* The return value to indicate that the device does not support the statistic.
*/
public final static int UNSUPPORTED = -1;
/** @hide */
public static final long KB_IN_BYTES = 1024;
/** @hide */
public static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
/** @hide */
public static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
/** @hide */
public static final long TB_IN_BYTES = GB_IN_BYTES * 1024;
/** @hide */
public static final long PB_IN_BYTES = TB_IN_BYTES * 1024;
/**
* Special UID value used when collecting {@link NetworkStatsHistory} for
* removed applications.
*
* @hide
*/
public static final int UID_REMOVED = -4;
/**
* Special UID value used when collecting {@link NetworkStatsHistory} for
* tethering traffic.
*
* @hide
*/
public static final int UID_TETHERING = -5;
/**
* Default tag value for {@link DownloadManager} traffic.
*
* @hide
*/
public static final int TAG_SYSTEM_DOWNLOAD = 0xFFFFFF01;
/**
* Default tag value for {@link MediaPlayer} traffic.
*
* @hide
*/
public static final int TAG_SYSTEM_MEDIA = 0xFFFFFF02;
/**
* Default tag value for {@link BackupManager} traffic.
*
* @hide
*/
public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03;
private static INetworkStatsService sStatsService;
private synchronized static INetworkStatsService getStatsService() {
if (sStatsService == null) {
sStatsService = INetworkStatsService.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
}
return sStatsService;
}
/**
* Snapshot of {@link NetworkStats} when the currently active profiling
* session started, or {@code null} if no session active.
*
* @see #startDataProfiling(Context)
* @see #stopDataProfiling(Context)
*/
private static NetworkStats sActiveProfilingStart;
private static Object sProfilingLock = new Object();
/**
* Set active tag to use when accounting {@link Socket} traffic originating
* from the current thread. Only one active tag per thread is supported.
* <p>
* Changes only take effect during subsequent calls to
* {@link #tagSocket(Socket)}.
* <p>
* Tags between {@code 0xFFFFFF00} and {@code 0xFFFFFFFF} are reserved and
* used internally by system services like {@link DownloadManager} when
* performing traffic on behalf of an application.
*
* @see #clearThreadStatsTag()
*/
public static void setThreadStatsTag(int tag) {
NetworkManagementSocketTagger.setThreadSocketStatsTag(tag);
}
/**
* System API for backup-related support components to tag network traffic
* appropriately.
* @hide
*/
@SystemApi
public static void setThreadStatsTagBackup() {
setThreadStatsTag(TAG_SYSTEM_BACKUP);
}
/**
* Get the active tag used when accounting {@link Socket} traffic originating
* from the current thread. Only one active tag per thread is supported.
* {@link #tagSocket(Socket)}.
*
* @see #setThreadStatsTag(int)
*/
public static int getThreadStatsTag() {
return NetworkManagementSocketTagger.getThreadSocketStatsTag();
}
/**
* Clear any active tag set to account {@link Socket} traffic originating
* from the current thread.
*
* @see #setThreadStatsTag(int)
*/
public static void clearThreadStatsTag() {
NetworkManagementSocketTagger.setThreadSocketStatsTag(-1);
}
/**
* Set specific UID to use when accounting {@link Socket} traffic
* originating from the current thread. Designed for use when performing an
* operation on behalf of another application.
* <p>
* Changes only take effect during subsequent calls to
* {@link #tagSocket(Socket)}.
* <p>
* To take effect, caller must hold
* {@link android.Manifest.permission#UPDATE_DEVICE_STATS} permission.
*
* @hide
*/
@SystemApi
public static void setThreadStatsUid(int uid) {
NetworkManagementSocketTagger.setThreadSocketStatsUid(uid);
}
/** {@hide} */
@SystemApi
public static void clearThreadStatsUid() {
NetworkManagementSocketTagger.setThreadSocketStatsUid(-1);
}
/**
* Tag the given {@link Socket} with any statistics parameters active for
* the current thread. Subsequent calls always replace any existing
* parameters. When finished, call {@link #untagSocket(Socket)} to remove
* statistics parameters.
*
* @see #setThreadStatsTag(int)
* @see #setThreadStatsUid(int)
*/
public static void tagSocket(Socket socket) throws SocketException {
SocketTagger.get().tag(socket);
}
/**
* Remove any statistics parameters from the given {@link Socket}.
*/
public static void untagSocket(Socket socket) throws SocketException {
SocketTagger.get().untag(socket);
}
/**
* Start profiling data usage for current UID. Only one profiling session
* can be active at a time.
*
* @hide
*/
public static void startDataProfiling(Context context) {
synchronized (sProfilingLock) {
if (sActiveProfilingStart != null) {
throw new IllegalStateException("already profiling data");
}
// take snapshot in time; we calculate delta later
sActiveProfilingStart = getDataLayerSnapshotForUid(context);
}
}
/**
* Stop profiling data usage for current UID.
*
* @return Detailed {@link NetworkStats} of data that occurred since last
* {@link #startDataProfiling(Context)} call.
* @hide
*/
public static NetworkStats stopDataProfiling(Context context) {
synchronized (sProfilingLock) {
if (sActiveProfilingStart == null) {
throw new IllegalStateException("not profiling data");
}
// subtract starting values and return delta
final NetworkStats profilingStop = getDataLayerSnapshotForUid(context);
final NetworkStats profilingDelta = NetworkStats.subtract(
profilingStop, sActiveProfilingStart, null, null);
sActiveProfilingStart = null;
return profilingDelta;
}
}
/**
* Increment count of network operations performed under the accounting tag
* currently active on the calling thread. This can be used to derive
* bytes-per-operation.
*
* @param operationCount Number of operations to increment count by.
*/
public static void incrementOperationCount(int operationCount) {
final int tag = getThreadStatsTag();
incrementOperationCount(tag, operationCount);
}
/**
* Increment count of network operations performed under the given
* accounting tag. This can be used to derive bytes-per-operation.
*
* @param tag Accounting tag used in {@link #setThreadStatsTag(int)}.
* @param operationCount Number of operations to increment count by.
*/
public static void incrementOperationCount(int tag, int operationCount) {
final int uid = android.os.Process.myUid();
try {
getStatsService().incrementOperationCount(uid, tag, operationCount);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
/** {@hide} */
public static void closeQuietly(INetworkStatsSession session) {
// TODO: move to NetworkStatsService once it exists
if (session != null) {
try {
session.close();
} catch (RuntimeException rethrown) {
throw rethrown;
} catch (Exception ignored) {
}
}
}
/**
* Return number of packets transmitted across mobile networks since device
* boot. Counts packets across all mobile network interfaces, and always
* increases monotonically since device boot. Statistics are measured at the
* network layer, so they include both TCP and UDP usage.
* <p>
* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
* return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/
public static long getMobileTxPackets() {
long total = 0;
for (String iface : getMobileIfaces()) {
total += getTxPackets(iface);
}
return total;
}
/**
* Return number of packets received across mobile networks since device
* boot. Counts packets across all mobile network interfaces, and always
* increases monotonically since device boot. Statistics are measured at the
* network layer, so they include both TCP and UDP usage.
* <p>
* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
* return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/
public static long getMobileRxPackets() {
long total = 0;
for (String iface : getMobileIfaces()) {
total += getRxPackets(iface);
}
return total;
}
/**
* Return number of bytes transmitted across mobile networks since device
* boot. Counts packets across all mobile network interfaces, and always
* increases monotonically since device boot. Statistics are measured at the
* network layer, so they include both TCP and UDP usage.
* <p>
* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
* return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/
public static long getMobileTxBytes() {
long total = 0;
for (String iface : getMobileIfaces()) {
total += getTxBytes(iface);
}
return total;
}
/**
* Return number of bytes received across mobile networks since device boot.
* Counts packets across all mobile network interfaces, and always increases
* monotonically since device boot. Statistics are measured at the network
* layer, so they include both TCP and UDP usage.
* <p>
* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
* return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/
public static long getMobileRxBytes() {
long total = 0;
for (String iface : getMobileIfaces()) {
total += getRxBytes(iface);
}
return total;
}
/** {@hide} */
public static long getMobileTcpRxPackets() {
long total = 0;
for (String iface : getMobileIfaces()) {
final long stat = nativeGetIfaceStat(iface, TYPE_TCP_RX_PACKETS);
if (stat != UNSUPPORTED) {
total += stat;
}
}
return total;
}
/** {@hide} */
public static long getMobileTcpTxPackets() {
long total = 0;
for (String iface : getMobileIfaces()) {
final long stat = nativeGetIfaceStat(iface, TYPE_TCP_TX_PACKETS);
if (stat != UNSUPPORTED) {
total += stat;
}
}
return total;
}
/** {@hide} */
public static long getTxPackets(String iface) {
return nativeGetIfaceStat(iface, TYPE_TX_PACKETS);
}
/** {@hide} */
public static long getRxPackets(String iface) {
return nativeGetIfaceStat(iface, TYPE_RX_PACKETS);
}
/** {@hide} */
public static long getTxBytes(String iface) {
return nativeGetIfaceStat(iface, TYPE_TX_BYTES);
}
/** {@hide} */
public static long getRxBytes(String iface) {
return nativeGetIfaceStat(iface, TYPE_RX_BYTES);
}
/**
* Return number of packets transmitted since device boot. Counts packets
* across all network interfaces, and always increases monotonically since
* device boot. Statistics are measured at the network layer, so they
* include both TCP and UDP usage.
* <p>
* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
* return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/
public static long getTotalTxPackets() {
return nativeGetTotalStat(TYPE_TX_PACKETS);
}
/**
* Return number of packets received since device boot. Counts packets
* across all network interfaces, and always increases monotonically since
* device boot. Statistics are measured at the network layer, so they
* include both TCP and UDP usage.
* <p>
* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
* return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/
public static long getTotalRxPackets() {
return nativeGetTotalStat(TYPE_RX_PACKETS);
}
/**
* Return number of bytes transmitted since device boot. Counts packets
* across all network interfaces, and always increases monotonically since
* device boot. Statistics are measured at the network layer, so they
* include both TCP and UDP usage.
* <p>
* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
* return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/
public static long getTotalTxBytes() {
return nativeGetTotalStat(TYPE_TX_BYTES);
}
/**
* Return number of bytes received since device boot. Counts packets across
* all network interfaces, and always increases monotonically since device
* boot. Statistics are measured at the network layer, so they include both
* TCP and UDP usage.
* <p>
* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
* return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/
public static long getTotalRxBytes() {
return nativeGetTotalStat(TYPE_RX_BYTES);
}
/**
* Return number of bytes transmitted by the given UID since device boot.
* Counts packets across all network interfaces, and always increases
* monotonically since device boot. Statistics are measured at the network
* layer, so they include both TCP and UDP usage.
* <p>
* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
* {@link #UNSUPPORTED} on devices where statistics aren't available.
*
* @see android.os.Process#myUid()
* @see android.content.pm.ApplicationInfo#uid
*/
public static long getUidTxBytes(int uid) {
return nativeGetUidStat(uid, TYPE_TX_BYTES);
}
/**
* Return number of bytes received by the given UID since device boot.
* Counts packets across all network interfaces, and always increases
* monotonically since device boot. Statistics are measured at the network
* layer, so they include both TCP and UDP usage.
* <p>
* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
* {@link #UNSUPPORTED} on devices where statistics aren't available.
*
* @see android.os.Process#myUid()
* @see android.content.pm.ApplicationInfo#uid
*/
public static long getUidRxBytes(int uid) {
return nativeGetUidStat(uid, TYPE_RX_BYTES);
}
/**
* Return number of packets transmitted by the given UID since device boot.
* Counts packets across all network interfaces, and always increases
* monotonically since device boot. Statistics are measured at the network
* layer, so they include both TCP and UDP usage.
* <p>
* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
* {@link #UNSUPPORTED} on devices where statistics aren't available.
*
* @see android.os.Process#myUid()
* @see android.content.pm.ApplicationInfo#uid
*/
public static long getUidTxPackets(int uid) {
return nativeGetUidStat(uid, TYPE_TX_PACKETS);
}
/**
* Return number of packets received by the given UID since device boot.
* Counts packets across all network interfaces, and always increases
* monotonically since device boot. Statistics are measured at the network
* layer, so they include both TCP and UDP usage.
* <p>
* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
* {@link #UNSUPPORTED} on devices where statistics aren't available.
*
* @see android.os.Process#myUid()
* @see android.content.pm.ApplicationInfo#uid
*/
public static long getUidRxPackets(int uid) {
return nativeGetUidStat(uid, TYPE_RX_PACKETS);
}
/**
* @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
* transport layer statistics are no longer available, and will
* always return {@link #UNSUPPORTED}.
* @see #getUidTxBytes(int)
*/
@Deprecated
public static long getUidTcpTxBytes(int uid) {
return UNSUPPORTED;
}
/**
* @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
* transport layer statistics are no longer available, and will
* always return {@link #UNSUPPORTED}.
* @see #getUidRxBytes(int)
*/
@Deprecated
public static long getUidTcpRxBytes(int uid) {
return UNSUPPORTED;
}
/**
* @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
* transport layer statistics are no longer available, and will
* always return {@link #UNSUPPORTED}.
* @see #getUidTxBytes(int)
*/
@Deprecated
public static long getUidUdpTxBytes(int uid) {
return UNSUPPORTED;
}
/**
* @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
* transport layer statistics are no longer available, and will
* always return {@link #UNSUPPORTED}.
* @see #getUidRxBytes(int)
*/
@Deprecated
public static long getUidUdpRxBytes(int uid) {
return UNSUPPORTED;
}
/**
* @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
* transport layer statistics are no longer available, and will
* always return {@link #UNSUPPORTED}.
* @see #getUidTxPackets(int)
*/
@Deprecated
public static long getUidTcpTxSegments(int uid) {
return UNSUPPORTED;
}
/**
* @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
* transport layer statistics are no longer available, and will
* always return {@link #UNSUPPORTED}.
* @see #getUidRxPackets(int)
*/
@Deprecated
public static long getUidTcpRxSegments(int uid) {
return UNSUPPORTED;
}
/**
* @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
* transport layer statistics are no longer available, and will
* always return {@link #UNSUPPORTED}.
* @see #getUidTxPackets(int)
*/
@Deprecated
public static long getUidUdpTxPackets(int uid) {
return UNSUPPORTED;
}
/**
* @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
* transport layer statistics are no longer available, and will
* always return {@link #UNSUPPORTED}.
* @see #getUidRxPackets(int)
*/
@Deprecated
public static long getUidUdpRxPackets(int uid) {
return UNSUPPORTED;
}
/**
* Return detailed {@link NetworkStats} for the current UID. Requires no
* special permission.
*/
private static NetworkStats getDataLayerSnapshotForUid(Context context) {
// TODO: take snapshot locally, since proc file is now visible
final int uid = android.os.Process.myUid();
try {
return getStatsService().getDataLayerSnapshotForUid(uid);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
/**
* Return set of any ifaces associated with mobile networks since boot.
* Interfaces are never removed from this list, so counters should always be
* monotonic.
*/
private static String[] getMobileIfaces() {
try {
return getStatsService().getMobileIfaces();
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
// NOTE: keep these in sync with android_net_TrafficStats.cpp
private static final int TYPE_RX_BYTES = 0;
private static final int TYPE_RX_PACKETS = 1;
private static final int TYPE_TX_BYTES = 2;
private static final int TYPE_TX_PACKETS = 3;
private static final int TYPE_TCP_RX_PACKETS = 4;
private static final int TYPE_TCP_TX_PACKETS = 5;
private static native long nativeGetTotalStat(int type);
private static native long nativeGetIfaceStat(String iface, int type);
private static native long nativeGetUidStat(int uid, int type);
}