summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/net/IConnectivityManager.aidl6
-rw-r--r--core/java/android/net/TrafficStats.java18
-rw-r--r--core/java/android/os/INetworkManagementService.aidl7
-rw-r--r--services/java/com/android/server/ConnectivityService.java6
-rw-r--r--services/java/com/android/server/NetworkManagementService.java69
-rw-r--r--services/java/com/android/server/connectivity/Tethering.java21
-rw-r--r--services/java/com/android/server/net/NetworkStatsService.java69
7 files changed, 186 insertions, 10 deletions
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index eef658e..7046008 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -83,6 +83,12 @@ interface IConnectivityManager
String[] getTetheredIfaces();
+ /**
+ * Return list of interface pairs that are actively tethered. Even indexes are
+ * remote interface, and odd indexes are corresponding local interfaces.
+ */
+ String[] getTetheredIfacePairs();
+
String[] getTetheringErroredIfaces();
String[] getTetherableUsbRegexs();
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 47cfa73..18eb9f6 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -53,25 +53,33 @@ public class TrafficStats {
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 = 0xFFFF0001;
+ public static final int TAG_SYSTEM_DOWNLOAD = 0xFFFFFF01;
/**
* Default tag value for {@link MediaPlayer} traffic.
*
* @hide
*/
- public static final int TAG_SYSTEM_MEDIA = 0xFFFF0002;
+ public static final int TAG_SYSTEM_MEDIA = 0xFFFFFF02;
/**
* Default tag value for {@link BackupManager} traffic.
*
* @hide
*/
- public static final int TAG_SYSTEM_BACKUP = 0xFFFF0003;
+ public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03;
/**
* Snapshot of {@link NetworkStats} when the currently active profiling
@@ -90,6 +98,10 @@ public class TrafficStats {
* <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.
*/
public static void setThreadStatsTag(int tag) {
NetworkManagementSocketTagger.setThreadSocketStatsTag(tag);
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 4e5645d..66373fe 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -231,6 +231,13 @@ interface INetworkManagementService
NetworkStats getNetworkStatsUidDetail(int uid);
/**
+ * Return summary of network statistics for the requested pairs of
+ * tethering interfaces. Even indexes are remote interface, and odd
+ * indexes are corresponding local interfaces.
+ */
+ NetworkStats getNetworkStatsTethering(in String[] ifacePairs);
+
+ /**
* Set quota for an interface.
*/
void setInterfaceQuota(String iface, long quotaBytes);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 2348d76..e0a2adc 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -2394,6 +2394,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return mTethering.getTetheredIfaces();
}
+ @Override
+ public String[] getTetheredIfacePairs() {
+ enforceTetherAccessPermission();
+ return mTethering.getTetheredIfacePairs();
+ }
+
public String[] getTetheringErroredIfaces() {
enforceTetherAccessPermission();
return mTethering.getErroredIfaces();
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index c517965..0cffb15 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -123,6 +123,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public static final int InterfaceTxCounterResult = 217;
public static final int InterfaceRxThrottleResult = 218;
public static final int InterfaceTxThrottleResult = 219;
+ public static final int QuotaCounterResult = 220;
+ public static final int TetheringStatsResult = 221;
public static final int InterfaceChange = 600;
public static final int BandwidthControl = 601;
@@ -1443,6 +1445,73 @@ public class NetworkManagementService extends INetworkManagementService.Stub
return stats;
}
+ @Override
+ public NetworkStats getNetworkStatsTethering(String[] ifacePairs) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+ if (ifacePairs.length % 2 != 0) {
+ throw new IllegalArgumentException(
+ "unexpected ifacePairs; length=" + ifacePairs.length);
+ }
+
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
+ for (int i = 0; i < ifacePairs.length; i += 2) {
+ final String ifaceIn = ifacePairs[i];
+ final String ifaceOut = ifacePairs[i + 1];
+ if (ifaceIn != null && ifaceOut != null) {
+ stats.combineValues(getNetworkStatsTethering(ifaceIn, ifaceOut));
+ }
+ }
+ return stats;
+ }
+
+ private NetworkStats.Entry getNetworkStatsTethering(String ifaceIn, String ifaceOut) {
+ final StringBuilder command = new StringBuilder();
+ command.append("bandwidth gettetherstats ").append(ifaceIn).append(" ").append(ifaceOut);
+
+ final String rsp;
+ try {
+ rsp = mConnector.doCommand(command.toString()).get(0);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon", e);
+ }
+
+ final String[] tok = rsp.split(" ");
+ /* Expecting: "code ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets" */
+ if (tok.length != 7) {
+ throw new IllegalStateException("Native daemon returned unexpected result: " + rsp);
+ }
+
+ final int code;
+ try {
+ code = Integer.parseInt(tok[0]);
+ } catch (NumberFormatException e) {
+ throw new IllegalStateException(
+ "Failed to parse native daemon return code for " + ifaceIn + " " + ifaceOut);
+ }
+ if (code != NetdResponseCode.TetheringStatsResult) {
+ throw new IllegalStateException(
+ "Unexpected return code from native daemon for " + ifaceIn + " " + ifaceOut);
+ }
+
+ try {
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
+ entry.iface = ifaceIn;
+ entry.uid = UID_ALL;
+ entry.set = SET_DEFAULT;
+ entry.tag = TAG_NONE;
+ entry.rxBytes = Long.parseLong(tok[3]);
+ entry.rxPackets = Long.parseLong(tok[4]);
+ entry.txBytes = Long.parseLong(tok[5]);
+ entry.txPackets = Long.parseLong(tok[6]);
+ return entry;
+ } catch (NumberFormatException e) {
+ throw new IllegalStateException(
+ "problem parsing tethering stats for " + ifaceIn + " " + ifaceOut + ": " + e);
+ }
+ }
+
public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index ae8b89d..5286824 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -19,7 +19,6 @@ package com.android.server.connectivity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.bluetooth.BluetoothPan;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -28,15 +27,14 @@ import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
-import android.net.InterfaceConfiguration;
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
+import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.NetworkUtils;
import android.os.Binder;
-import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.INetworkManagementService;
@@ -51,6 +49,7 @@ import com.android.internal.telephony.Phone;
import com.android.internal.util.IState;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
+import com.google.android.collect.Lists;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -59,8 +58,8 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.Set;
+
/**
* @hide
*
@@ -68,7 +67,6 @@ import java.util.Set;
*
* TODO - look for parent classes and code sharing
*/
-
public class Tethering extends INetworkManagementEventObserver.Stub {
private Context mContext;
@@ -629,6 +627,19 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
return retVal;
}
+ public String[] getTetheredIfacePairs() {
+ final ArrayList<String> list = Lists.newArrayList();
+ synchronized (mIfaces) {
+ for (TetherInterfaceSM sm : mIfaces.values()) {
+ if (sm.isTethered()) {
+ list.add(sm.mMyUpstreamIfaceName);
+ list.add(sm.mIfaceName);
+ }
+ }
+ }
+ return list.toArray(new String[list.size()]);
+ }
+
public String[] getTetherableIfaces() {
ArrayList<String> list = new ArrayList<String>();
synchronized (mIfaces) {
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 3673eab..c180b72 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -25,6 +25,7 @@ import static android.content.Intent.ACTION_SHUTDOWN;
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
+import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.SET_DEFAULT;
@@ -34,6 +35,7 @@ import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.NetworkTemplate.buildTemplateWifi;
import static android.net.TrafficStats.UID_REMOVED;
+import static android.net.TrafficStats.UID_TETHERING;
import static android.provider.Settings.Secure.NETSTATS_FORCE_COMPLETE_POLL;
import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
@@ -68,6 +70,7 @@ import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
+import android.net.TrafficStats;
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
@@ -89,6 +92,7 @@ import android.util.TrustedTime;
import com.android.internal.os.AtomicFile;
import com.android.internal.util.Objects;
import com.android.server.EventLogTags;
+import com.android.server.connectivity.Tethering;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import com.google.android.collect.Sets;
@@ -134,11 +138,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
/** Flags to control detail level of poll event. */
private static final int FLAG_POLL_NETWORK = 0x1;
private static final int FLAG_POLL_UID = 0x2;
+ private static final int FLAG_POLL_TETHER = 0x3;
private static final int FLAG_PERSIST_NETWORK = 0x10;
private static final int FLAG_PERSIST_UID = 0x20;
private static final int FLAG_FORCE_PERSIST = 0x100;
- private static final int FLAG_POLL_ALL = FLAG_POLL_NETWORK | FLAG_POLL_UID;
+ private static final int FLAG_POLL_ALL = FLAG_POLL_NETWORK | FLAG_POLL_UID | FLAG_POLL_TETHER;
private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID;
private final Context mContext;
@@ -195,6 +200,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private NetworkStats mLastPollNetworkSnapshot;
private NetworkStats mLastPollUidSnapshot;
private NetworkStats mLastPollOperationsSnapshot;
+ private NetworkStats mLastPollTetherSnapshot;
private NetworkStats mLastPersistNetworkSnapshot;
private NetworkStats mLastPersistUidSnapshot;
@@ -258,6 +264,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE);
mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
+ // watch for tethering changes
+ final IntentFilter tetherFilter = new IntentFilter(ACTION_TETHER_STATE_CHANGED);
+ mContext.registerReceiver(mTetherReceiver, tetherFilter, CONNECTIVITY_INTERNAL, mHandler);
+
// listen for periodic polling events
final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL);
mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
@@ -543,6 +553,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
};
+ /**
+ * Receiver that watches for {@link Tethering} to claim interface pairs.
+ */
+ private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // on background handler thread, and verified CONNECTIVITY_INTERNAL
+ // permission above.
+ performPoll(FLAG_POLL_TETHER);
+ }
+ };
+
private BroadcastReceiver mPollReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -686,12 +708,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
boolean pollNetwork = (flags & FLAG_POLL_NETWORK) != 0;
boolean pollUid = (flags & FLAG_POLL_UID) != 0;
+ boolean pollTether = (flags & FLAG_POLL_TETHER) != 0;
// when complete poll requested, any partial poll enables everything
final boolean forceCompletePoll = mSettings.getForceCompletePoll();
- if (forceCompletePoll && (pollNetwork || pollUid)) {
+ if (forceCompletePoll && (pollNetwork || pollUid || pollTether)) {
pollNetwork = true;
pollUid = true;
+ pollTether = true;
}
final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0;
@@ -723,6 +747,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
}
+ if (pollTether) {
+ final String[] ifacePairs = mConnManager.getTetheredIfacePairs();
+ final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering(
+ ifacePairs);
+ performTetherPollLocked(tetherSnapshot, currentTime);
+
+ // persisted during normal UID cycle below
+ }
+
if (pollUid) {
final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
performUidPollLocked(uidSnapshot, currentTime);
@@ -849,6 +882,38 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
/**
+ * Update {@link #mUidStats} historical usage for
+ * {@link TrafficStats#UID_TETHERING} based on tethering statistics.
+ */
+ private void performTetherPollLocked(NetworkStats tetherSnapshot, long currentTime) {
+ ensureUidStatsLoadedLocked();
+
+ final NetworkStats delta = computeStatsDelta(
+ mLastPollTetherSnapshot, tetherSnapshot, false);
+ final long timeStart = currentTime - delta.getElapsedRealtime();
+
+ NetworkStats.Entry entry = null;
+ for (int i = 0; i < delta.size(); i++) {
+ entry = delta.getValues(i, entry);
+ final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
+ if (ident == null) {
+ if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0
+ || entry.txPackets > 0) {
+ Log.w(TAG, "dropping tether delta from unknown iface: " + entry);
+ }
+ continue;
+ }
+
+ final NetworkStatsHistory history = findOrCreateUidStatsLocked(
+ ident, UID_TETHERING, SET_DEFAULT, TAG_NONE);
+ history.recordData(timeStart, currentTime, entry);
+ }
+
+ // normal UID poll will trim any history beyond max
+ mLastPollTetherSnapshot = tetherSnapshot;
+ }
+
+ /**
* Sample recent statistics summary into {@link EventLog}.
*/
private void performSample() {