Merge "Collect and persist tethering stats." into ics-factoryrom
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -52,26 +52,34 @@ 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);
|
||||
|
||||
@@ -230,6 +230,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.
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
@@ -848,6 +881,38 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
mOperations = new NetworkStats(0L, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user