Merge "Collect and persist tethering stats." into ics-factoryrom

This commit is contained in:
Jeff Sharkey
2011-09-18 16:15:51 -07:00
committed by Android (Google) Code Review
7 changed files with 186 additions and 10 deletions

View File

@@ -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();

View File

@@ -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);

View File

@@ -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.
*/

View File

@@ -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();

View File

@@ -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");

View File

@@ -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) {

View File

@@ -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}.
*/