summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2011-06-28 18:02:12 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-06-28 18:02:12 -0700
commit8994730fe39570c7807561de38407a8b22230e8a (patch)
tree0154a39d8c1b08efb8d5291b8ff940cee9997e4c
parenteb8283d4b3eda3e1b9e670e0de615ac7605208e3 (diff)
parent4414cea13908b8230640f84ef39603d68ff9c377 (diff)
downloadframeworks_base-8994730fe39570c7807561de38407a8b22230e8a.zip
frameworks_base-8994730fe39570c7807561de38407a8b22230e8a.tar.gz
frameworks_base-8994730fe39570c7807561de38407a8b22230e8a.tar.bz2
Merge "Better network stats parsing, integer tags, async."
-rw-r--r--api/current.txt3
-rw-r--r--core/java/android/net/NetworkPolicyManager.java38
-rw-r--r--core/java/android/net/TrafficStats.java38
-rw-r--r--services/java/com/android/server/NetworkManagementService.java99
-rw-r--r--services/java/com/android/server/net/NetworkPolicyManagerService.java106
-rw-r--r--services/java/com/android/server/net/NetworkStatsService.java7
-rw-r--r--services/tests/servicestests/res/raw/xt_qtaguid_extended3
-rw-r--r--services/tests/servicestests/res/raw/xt_qtaguid_typical32
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java121
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java124
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java5
11 files changed, 462 insertions, 114 deletions
diff --git a/api/current.txt b/api/current.txt
index 9273b71..6693647 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11240,7 +11240,8 @@ package android.net {
method public static long getUidUdpRxPackets(int);
method public static long getUidUdpTxBytes(int);
method public static long getUidUdpTxPackets(int);
- method public static void setThreadStatsTag(java.lang.String);
+ method public static void setThreadStatsTag(int);
+ method public static deprecated void setThreadStatsTag(java.lang.String);
method public static void tagSocket(java.net.Socket) throws java.net.SocketException;
method public static void untagSocket(java.net.Socket) throws java.net.SocketException;
field public static final int UNSUPPORTED = -1; // 0xffffffff
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 91af16d..21fad2c 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -16,14 +16,21 @@
package android.net;
+import static android.content.pm.PackageManager.GET_SIGNATURES;
import static android.text.format.Time.MONTH_DAY;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.Signature;
import android.os.RemoteException;
import android.text.format.Time;
+import com.google.android.collect.Sets;
+
import java.io.PrintWriter;
+import java.util.HashSet;
/**
* Manager for creating and modifying network policy rules.
@@ -210,8 +217,35 @@ public class NetworkPolicyManager {
* usually to protect critical system services.
*/
public static boolean isUidValidForPolicy(Context context, int uid) {
- return (uid >= android.os.Process.FIRST_APPLICATION_UID
- && uid <= android.os.Process.LAST_APPLICATION_UID);
+ // first, quick-reject non-applications
+ if (uid < android.os.Process.FIRST_APPLICATION_UID
+ || uid > android.os.Process.LAST_APPLICATION_UID) {
+ return false;
+ }
+
+ final PackageManager pm = context.getPackageManager();
+ final HashSet<Signature> systemSignature;
+ try {
+ systemSignature = Sets.newHashSet(
+ pm.getPackageInfo("android", GET_SIGNATURES).signatures);
+ } catch (NameNotFoundException e) {
+ throw new RuntimeException("problem finding system signature", e);
+ }
+
+ try {
+ // reject apps signed with system cert
+ for (String packageName : pm.getPackagesForUid(uid)) {
+ final HashSet<Signature> packageSignature = Sets.newHashSet(
+ pm.getPackageInfo(packageName, GET_SIGNATURES).signatures);
+ if (packageSignature.containsAll(systemSignature)) {
+ return false;
+ }
+ }
+ } catch (NameNotFoundException e) {
+ }
+
+ // nothing found above; we can apply policy to UID
+ return true;
}
/** {@hide} */
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index cb47193..040489e 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -16,7 +16,10 @@
package android.net;
+import android.app.DownloadManager;
+import android.app.backup.BackupManager;
import android.content.Context;
+import android.media.MediaPlayer;
import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.RemoteException;
@@ -50,6 +53,27 @@ public class TrafficStats {
public static final int UID_REMOVED = -4;
/**
+ * Default tag value for {@link DownloadManager} traffic.
+ *
+ * @hide
+ */
+ public static final int TAG_SYSTEM_DOWNLOAD = 0xFFFF0001;
+
+ /**
+ * Default tag value for {@link MediaPlayer} traffic.
+ *
+ * @hide
+ */
+ public static final int TAG_SYSTEM_MEDIA = 0xFFFF0002;
+
+ /**
+ * Default tag value for {@link BackupManager} traffic.
+ *
+ * @hide
+ */
+ public static final int TAG_SYSTEM_BACKUP = 0xFFFF0003;
+
+ /**
* Snapshot of {@link NetworkStats} when the currently active profiling
* session started, or {@code null} if no session active.
*
@@ -67,12 +91,20 @@ public class TrafficStats {
* Changes only take effect during subsequent calls to
* {@link #tagSocket(Socket)}.
*/
- public static void setThreadStatsTag(String tag) {
+ public static void setThreadStatsTag(int tag) {
BlockGuard.setThreadSocketStatsTag(tag);
}
+ /**
+ * @deprecated unsupported, will eventually be removed
+ */
+ @Deprecated
+ public static void setThreadStatsTag(String tag) {
+ setThreadStatsTag(tag.hashCode());
+ }
+
public static void clearThreadStatsTag() {
- BlockGuard.setThreadSocketStatsTag(null);
+ BlockGuard.setThreadSocketStatsTag(-1);
}
/**
@@ -103,7 +135,7 @@ public class TrafficStats {
* parameters. When finished, call {@link #untagSocket(Socket)} to remove
* statistics parameters.
*
- * @see #setThreadStatsTag(String)
+ * @see #setThreadStatsTag(int)
* @see #setThreadStatsUid(int)
*/
public static void tagSocket(Socket socket) throws SocketException {
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index e730d0d..630aaf9 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -38,6 +38,11 @@ import android.os.SystemProperties;
import android.util.Log;
import android.util.Slog;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import dalvik.system.BlockGuard;
+
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
@@ -48,6 +53,7 @@ import java.io.InputStreamReader;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.concurrent.CountDownLatch;
@@ -65,9 +71,18 @@ class NetworkManagementService extends INetworkManagementService.Stub {
private static final int ADD = 1;
private static final int REMOVE = 2;
+ /** Path to {@code /proc/uid_stat}. */
@Deprecated
- private static final File STATS_UIDSTAT = new File("/proc/uid_stat");
- private static final File STATS_NETFILTER = new File("/proc/net/xt_qtaguid/stats");
+ private final File mProcStatsUidstat;
+ /** Path to {@code /proc/net/xt_qtaguid/stats}. */
+ private final File mProcStatsNetfilter;
+
+ /** {@link #mProcStatsNetfilter} headers. */
+ private static final String KEY_IFACE = "iface";
+ private static final String KEY_TAG_HEX = "acct_tag_hex";
+ private static final String KEY_UID = "uid_tag_int";
+ private static final String KEY_RX = "rx_bytes";
+ private static final String KEY_TX = "tx_bytes";
class NetdResponseCode {
public static final int InterfaceListResult = 110;
@@ -107,10 +122,13 @@ class NetworkManagementService extends INetworkManagementService.Stub {
*
* @param context Binder context for this service
*/
- private NetworkManagementService(Context context) {
+ private NetworkManagementService(Context context, File procRoot) {
mContext = context;
mObservers = new ArrayList<INetworkManagementEventObserver>();
+ mProcStatsUidstat = new File(procRoot, "uid_stat");
+ mProcStatsNetfilter = new File(procRoot, "net/xt_qtaguid/stats");
+
if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
return;
}
@@ -121,7 +139,8 @@ class NetworkManagementService extends INetworkManagementService.Stub {
}
public static NetworkManagementService create(Context context) throws InterruptedException {
- NetworkManagementService service = new NetworkManagementService(context);
+ NetworkManagementService service = new NetworkManagementService(
+ context, new File("/proc/"));
if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
service.mThread.start();
if (DBG) Slog.d(TAG, "Awaiting socket connection");
@@ -130,6 +149,12 @@ class NetworkManagementService extends INetworkManagementService.Stub {
return service;
}
+ // @VisibleForTesting
+ public static NetworkManagementService createForTest(Context context, File procRoot) {
+ // TODO: eventually connect with mock netd
+ return new NetworkManagementService(context, procRoot);
+ }
+
public void registerObserver(INetworkManagementEventObserver obs) {
Slog.d(TAG, "Registering observer");
mObservers.add(obs);
@@ -888,7 +913,7 @@ class NetworkManagementService extends INetworkManagementService.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
- if (STATS_NETFILTER.exists()) {
+ if (mProcStatsNetfilter.exists()) {
return getNetworkStatsDetailNetfilter(UID_ALL);
} else {
return getNetworkStatsDetailUidstat(UID_ALL);
@@ -902,7 +927,7 @@ class NetworkManagementService extends INetworkManagementService.Stub {
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
}
- if (STATS_NETFILTER.exists()) {
+ if (mProcStatsNetfilter.exists()) {
return getNetworkStatsDetailNetfilter(uid);
} else {
return getNetworkStatsDetailUidstat(uid);
@@ -914,35 +939,35 @@ class NetworkManagementService extends INetworkManagementService.Stub {
*/
private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
+ final ArrayList<String> keys = Lists.newArrayList();
+ final ArrayList<String> values = Lists.newArrayList();
+ final HashMap<String, String> parsed = Maps.newHashMap();
BufferedReader reader = null;
try {
- reader = new BufferedReader(new FileReader(STATS_NETFILTER));
+ reader = new BufferedReader(new FileReader(mProcStatsNetfilter));
- // assumes format from kernel:
- // idx iface acct_tag_hex uid_tag_int rx_bytes tx_bytes
-
- // skip first line, which is legend
+ // parse first line as header
String line = reader.readLine();
- while ((line = reader.readLine()) != null) {
- final StringTokenizer t = new StringTokenizer(line);
+ splitLine(line, keys);
- final String idx = t.nextToken();
- final String iface = t.nextToken();
+ // parse remaining lines
+ while ((line = reader.readLine()) != null) {
+ splitLine(line, values);
+ parseLine(keys, values, parsed);
try {
- // TODO: kernel currently emits tag in upper half of long;
- // eventually switch to directly using int.
- final int tag = (int) (Long.parseLong(t.nextToken().substring(2), 16) >> 32);
- final int uid = Integer.parseInt(t.nextToken());
- final long rx = Long.parseLong(t.nextToken());
- final long tx = Long.parseLong(t.nextToken());
+ final String iface = parsed.get(KEY_IFACE);
+ final int tag = BlockGuard.kernelToTag(parsed.get(KEY_TAG_HEX));
+ final int uid = Integer.parseInt(parsed.get(KEY_UID));
+ final long rx = Long.parseLong(parsed.get(KEY_RX));
+ final long tx = Long.parseLong(parsed.get(KEY_TX));
if (limitUid == UID_ALL || limitUid == uid) {
stats.addEntry(iface, uid, tag, rx, tx);
}
} catch (NumberFormatException e) {
- Slog.w(TAG, "problem parsing stats for idx " + idx + ": " + e);
+ Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
}
}
} catch (IOException e) {
@@ -964,7 +989,7 @@ class NetworkManagementService extends INetworkManagementService.Stub {
private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
final String[] knownUids;
if (limitUid == UID_ALL) {
- knownUids = STATS_UIDSTAT.list();
+ knownUids = mProcStatsUidstat.list();
} else {
knownUids = new String[] { String.valueOf(limitUid) };
}
@@ -973,7 +998,7 @@ class NetworkManagementService extends INetworkManagementService.Stub {
SystemClock.elapsedRealtime(), knownUids.length);
for (String uid : knownUids) {
final int uidInt = Integer.parseInt(uid);
- final File uidPath = new File(STATS_UIDSTAT, uid);
+ final File uidPath = new File(mProcStatsUidstat, uid);
final long rx = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
final long tx = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
stats.addEntry(IFACE_ALL, uidInt, TAG_NONE, rx, tx);
@@ -1048,6 +1073,32 @@ class NetworkManagementService extends INetworkManagementService.Stub {
}
/**
+ * Split given line into {@link ArrayList}.
+ */
+ private static void splitLine(String line, ArrayList<String> outSplit) {
+ outSplit.clear();
+
+ final StringTokenizer t = new StringTokenizer(line);
+ while (t.hasMoreTokens()) {
+ outSplit.add(t.nextToken());
+ }
+ }
+
+ /**
+ * Zip the two given {@link ArrayList} as key and value pairs into
+ * {@link HashMap}.
+ */
+ private static void parseLine(
+ ArrayList<String> keys, ArrayList<String> values, HashMap<String, String> outParsed) {
+ outParsed.clear();
+
+ final int size = Math.min(keys.size(), values.size());
+ for (int i = 0; i < size; i++) {
+ outParsed.put(keys.get(i), values.get(i));
+ }
+ }
+
+ /**
* Utility method to read a single plain-text {@link Long} from the given
* {@link File}, usually from a {@code /proc/} filesystem.
*/
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 584cd03..12d3ed8 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -72,6 +72,7 @@ import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IPowerManager;
+import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.telephony.TelephonyManager;
@@ -148,6 +149,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
+ private static final int MSG_RULES_CHANGED = 0x1;
+ private static final int MSG_METERED_IFACES_CHANGED = 0x2;
+
private final Context mContext;
private final IActivityManager mActivityManager;
private final IPowerManager mPowerManager;
@@ -210,7 +214,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
+ mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
}
@@ -269,9 +273,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// only someone like AMS should only be calling us
mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
- // skip when UID couldn't have any policy
- if (!isUidValidForPolicy(mContext, uid)) return;
-
synchronized (mRulesLock) {
// because a uid can have multiple pids running inside, we need to
// remember all pid states and summarize foreground at uid level.
@@ -292,9 +293,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// only someone like AMS should only be calling us
mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
- // skip when UID couldn't have any policy
- if (!isUidValidForPolicy(mContext, uid)) return;
-
synchronized (mRulesLock) {
// clear records and recompute, when they exist
final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
@@ -599,20 +597,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- // dispatch changed rule to existing listeners
- // TODO: dispatch outside of holding lock
final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
- final int length = mListeners.beginBroadcast();
- for (int i = 0; i < length; i++) {
- final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
- if (listener != null) {
- try {
- listener.onMeteredIfacesChanged(meteredIfaces);
- } catch (RemoteException e) {
- }
- }
- }
- mListeners.finishBroadcast();
+ mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
}
/**
@@ -804,32 +790,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mListeners.register(listener);
- synchronized (mRulesLock) {
- // dispatch any existing rules to new listeners
- // TODO: dispatch outside of holding lock
- final int size = mUidRules.size();
- for (int i = 0; i < size; i++) {
- final int uid = mUidRules.keyAt(i);
- final int uidRules = mUidRules.valueAt(i);
- if (uidRules != RULE_ALLOW_ALL) {
- try {
- listener.onUidRulesChanged(uid, uidRules);
- } catch (RemoteException e) {
- }
- }
- }
-
- // dispatch any metered ifaces to new listeners
- // TODO: dispatch outside of holding lock
- if (mMeteredIfaces.size() > 0) {
- final String[] meteredIfaces = mMeteredIfaces.toArray(
- new String[mMeteredIfaces.size()]);
- try {
- listener.onMeteredIfacesChanged(meteredIfaces);
- } catch (RemoteException e) {
- }
- }
- }
+ // TODO: consider dispatching existing rules to new listeners
}
@Override
@@ -978,8 +939,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
private void updateRulesForUidLocked(int uid) {
- if (!isUidValidForPolicy(mContext, uid)) return;
-
final int uidPolicy = getUidPolicy(uid);
final boolean uidForeground = isUidForeground(uid);
@@ -999,19 +958,50 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
//kernelSetUidRejectPaid(uid, rejectPaid);
// dispatch changed rule to existing listeners
- // TODO: dispatch outside of holding lock
- final int length = mListeners.beginBroadcast();
- for (int i = 0; i < length; i++) {
- final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
- if (listener != null) {
- try {
- listener.onUidRulesChanged(uid, uidRules);
- } catch (RemoteException e) {
+ mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
+ }
+
+ private Handler.Callback mHandlerCallback = new Handler.Callback() {
+ /** {@inheritDoc} */
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_RULES_CHANGED: {
+ final int uid = msg.arg1;
+ final int uidRules = msg.arg2;
+ final int length = mListeners.beginBroadcast();
+ for (int i = 0; i < length; i++) {
+ final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
+ if (listener != null) {
+ try {
+ listener.onUidRulesChanged(uid, uidRules);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ mListeners.finishBroadcast();
+ return true;
+ }
+ case MSG_METERED_IFACES_CHANGED: {
+ final String[] meteredIfaces = (String[]) msg.obj;
+ final int length = mListeners.beginBroadcast();
+ for (int i = 0; i < length; i++) {
+ final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
+ if (listener != null) {
+ try {
+ listener.onMeteredIfacesChanged(meteredIfaces);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ mListeners.finishBroadcast();
+ return true;
+ }
+ default: {
+ return false;
}
}
}
- mListeners.finishBroadcast();
- }
+ };
private String getActiveSubscriberId() {
final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService(
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 4a79d17..7610a11 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -124,8 +124,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private PendingIntent mPollIntent;
// TODO: listen for kernel push events through netd instead of polling
- // TODO: watch for UID uninstall, and transfer stats into single bucket
-
// TODO: trim empty history objects entirely
private static final long KB_IN_BYTES = 1024;
@@ -506,8 +504,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
try {
networkSnapshot = mNetworkManager.getNetworkStatsSummary();
uidSnapshot = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null;
+ } catch (IllegalStateException e) {
+ Slog.w(TAG, "problem reading network stats: " + e);
+ return;
} catch (RemoteException e) {
- Slog.w(TAG, "problem reading network stats");
+ Slog.w(TAG, "problem reading network stats: " + e);
return;
}
diff --git a/services/tests/servicestests/res/raw/xt_qtaguid_extended b/services/tests/servicestests/res/raw/xt_qtaguid_extended
new file mode 100644
index 0000000..5bef3dd
--- /dev/null
+++ b/services/tests/servicestests/res/raw/xt_qtaguid_extended
@@ -0,0 +1,3 @@
+acct_tag_hex uid_tag_int iface rx_bytes rx_packets tx_bytes tx_packets teleported_goats
+0x0 1000 test0 1024 10 2048 20 2716057
+0x0000F00D00000000 1000 test0 512 5 512 5 3370318
diff --git a/services/tests/servicestests/res/raw/xt_qtaguid_typical b/services/tests/servicestests/res/raw/xt_qtaguid_typical
new file mode 100644
index 0000000..7c4f04e
--- /dev/null
+++ b/services/tests/servicestests/res/raw/xt_qtaguid_typical
@@ -0,0 +1,32 @@
+idx iface acct_tag_hex uid_tag_int rx_bytes tx_bytes
+1 wlan0 0x0 0 14615 4270
+2 wlan0 0x0 1000 5175 915
+3 wlan0 0x0 1021 3381 903
+4 wlan0 0x0 10004 333821 53558
+5 wlan0 0x0 10010 4888 37363
+6 wlan0 0x0 10013 52 104
+7 wlan0 0x74182ada00000000 10004 18725 1066
+8 rmnet0 0x0 0 301274 30244
+9 rmnet0 0x0 1000 304 441
+10 rmnet0 0x0 1013 2880 2272
+11 rmnet0 0x0 1021 31407 8430
+12 rmnet0 0x0 10003 32665 3814
+13 rmnet0 0x0 10004 2373141 420112
+14 rmnet0 0x0 10010 870370 1111727
+15 rmnet0 0x0 10013 240 240
+16 rmnet0 0x0 10016 16703 13512
+17 rmnet0 0x0 10017 3990 3269
+18 rmnet0 0x0 10018 474504 14516062
+19 rmnet0 0x0 10019 782804 71077
+20 rmnet0 0x0 10022 70671 49684
+21 rmnet0 0x0 10029 5785354 397159
+22 rmnet0 0x0 10033 2102 1686
+23 rmnet0 0x0 10034 15495464 227694
+24 rmnet0 0x0 10037 31184994 684122
+25 rmnet0 0x0 10051 298687 113485
+26 rmnet0 0x0 10056 29504 20669
+27 rmnet0 0x0 10069 683 596
+28 rmnet0 0x0 10072 34051 12453
+29 rmnet0 0x0 10077 7025393 213866
+30 rmnet0 0x0 10081 354 1178
+31 rmnet0 0x74182ada00000000 10037 28507378 437004
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
new file mode 100644
index 0000000..8b752ee
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2011 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 com.android.server;
+
+import static dalvik.system.BlockGuard.kernelToTag;
+import static dalvik.system.BlockGuard.tagToKernel;
+
+import android.content.res.Resources;
+import android.net.NetworkStats;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.android.frameworks.servicestests.R;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+/**
+ * Tests for {@link NetworkManagementService}.
+ */
+@LargeTest
+public class NetworkManagementServiceTest extends AndroidTestCase {
+ private File mTestProc;
+ private NetworkManagementService mService;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mTestProc = getContext().getFilesDir();
+ mService = NetworkManagementService.createForTest(mContext, mTestProc);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ mService = null;
+
+ super.tearDown();
+ }
+
+ public void testNetworkStatsDetail() throws Exception {
+ stageFile(R.raw.xt_qtaguid_typical, new File(mTestProc, "net/xt_qtaguid/stats"));
+
+ final NetworkStats stats = mService.getNetworkStatsDetail();
+ assertEquals(31, stats.size);
+ assertStatsEntry(stats, "wlan0", 0, 0, 14615L, 4270L);
+ assertStatsEntry(stats, "wlan0", 10004, 0, 333821L, 53558L);
+ assertStatsEntry(stats, "wlan0", 10004, 1947740890, 18725L, 1066L);
+ assertStatsEntry(stats, "rmnet0", 10037, 0, 31184994L, 684122L);
+ assertStatsEntry(stats, "rmnet0", 10037, 1947740890, 28507378L, 437004L);
+ }
+
+ public void testNetworkStatsDetailExtended() throws Exception {
+ stageFile(R.raw.xt_qtaguid_extended, new File(mTestProc, "net/xt_qtaguid/stats"));
+
+ final NetworkStats stats = mService.getNetworkStatsDetail();
+ assertEquals(2, stats.size);
+ assertStatsEntry(stats, "test0", 1000, 0, 1024L, 2048L);
+ assertStatsEntry(stats, "test0", 1000, 0xF00D, 512L, 512L);
+ }
+
+ public void testKernelTags() throws Exception {
+ assertEquals("0", tagToKernel(0x0));
+ assertEquals("214748364800", tagToKernel(0x32));
+ assertEquals("9223372032559808512", tagToKernel(Integer.MAX_VALUE));
+ assertEquals("0", tagToKernel(Integer.MIN_VALUE));
+ assertEquals("9223369837831520256", tagToKernel(Integer.MIN_VALUE - 512));
+
+ assertEquals(0, kernelToTag("0x0000000000000000"));
+ assertEquals(0x32, kernelToTag("0x0000003200000000"));
+ assertEquals(2147483647, kernelToTag("0x7fffffff00000000"));
+ assertEquals(0, kernelToTag("0x0000000000000000"));
+ assertEquals(2147483136, kernelToTag("0x7FFFFE0000000000"));
+
+ }
+
+ /**
+ * Copy a {@link Resources#openRawResource(int)} into {@link File} for
+ * testing purposes.
+ */
+ private void stageFile(int rawId, File file) throws Exception {
+ new File(file.getParent()).mkdirs();
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ in = getContext().getResources().openRawResource(rawId);
+ out = new FileOutputStream(file);
+ Streams.copy(in, out);
+ } finally {
+ IoUtils.closeQuietly(in);
+ IoUtils.closeQuietly(out);
+ }
+ }
+
+ private static void assertStatsEntry(
+ NetworkStats stats, String iface, int uid, int tag, long rx, long tx) {
+ final int i = stats.findIndex(iface, uid, tag);
+ assertEquals(rx, stats.rx[i]);
+ assertEquals(tx, stats.tx[i]);
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 07e5425..324e896 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -41,7 +41,9 @@ import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.IProcessObserver;
import android.content.Intent;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.Signature;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.net.INetworkPolicyListener;
@@ -63,12 +65,17 @@ import android.text.format.Time;
import android.util.TrustedTime;
import com.android.server.net.NetworkPolicyManagerService;
+import com.google.common.util.concurrent.AbstractFuture;
import org.easymock.Capture;
import org.easymock.EasyMock;
+import org.easymock.IAnswer;
import java.io.File;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* Tests for {@link NetworkPolicyManagerService}.
@@ -118,11 +125,27 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
public String[] getPackagesForUid(int uid) {
return new String[] { "com.example" };
}
+
+ @Override
+ public PackageInfo getPackageInfo(String packageName, int flags) {
+ final PackageInfo info = new PackageInfo();
+ final Signature signature;
+ if ("android".equals(packageName)) {
+ signature = new Signature("F00D");
+ } else {
+ signature = new Signature("DEAD");
+ }
+ info.signatures = new Signature[] { signature };
+ return info;
+ }
};
}
};
mPolicyDir = getContext().getFilesDir();
+ for (File file : mPolicyDir.listFiles()) {
+ file.delete();
+ }
mActivityManager = createMock(IActivityManager.class);
mPowerManager = createMock(IPowerManager.class);
@@ -228,81 +251,110 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
}
public void testScreenChangesRules() throws Exception {
- // push strict policy for foreground uid, verify ALLOW rule
- expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+ Future<Void> future;
+
+ future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
+ future.get();
+ verifyAndReset();
+
+ // push strict policy for foreground uid, verify ALLOW rule
+ future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+ replay();
mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+ future.get();
verifyAndReset();
// now turn screen off and verify REJECT rule
expect(mPowerManager.isScreenOn()).andReturn(false).atLeastOnce();
- expectRulesChanged(UID_A, RULE_REJECT_METERED);
+ future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SCREEN_OFF));
+ future.get();
verifyAndReset();
// and turn screen back on, verify ALLOW rule restored
expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
- expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+ future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SCREEN_ON));
+ future.get();
verifyAndReset();
}
public void testPolicyNone() throws Exception {
+ Future<Void> future;
+
+ future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+ replay();
+ mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
+ future.get();
+ verifyAndReset();
+
// POLICY_NONE should RULE_ALLOW in foreground
- expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+ future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mService.setUidPolicy(UID_A, POLICY_NONE);
- mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
+ future.get();
verifyAndReset();
// POLICY_NONE should RULE_ALLOW in background
- expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+ future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
+ future.get();
verifyAndReset();
}
public void testPolicyReject() throws Exception {
+ Future<Void> future;
+
// POLICY_REJECT should RULE_ALLOW in background
- expectRulesChanged(UID_A, RULE_REJECT_METERED);
+ future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+ future.get();
verifyAndReset();
// POLICY_REJECT should RULE_ALLOW in foreground
- expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+ future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
+ future.get();
verifyAndReset();
// POLICY_REJECT should RULE_REJECT in background
- expectRulesChanged(UID_A, RULE_REJECT_METERED);
+ future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
+ future.get();
verifyAndReset();
}
public void testPolicyRejectAddRemove() throws Exception {
+ Future<Void> future;
+
// POLICY_NONE should have RULE_ALLOW in background
- expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+ future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
- mService.setUidPolicy(UID_A, POLICY_NONE);
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
+ mService.setUidPolicy(UID_A, POLICY_NONE);
+ future.get();
verifyAndReset();
// adding POLICY_REJECT should cause RULE_REJECT
- expectRulesChanged(UID_A, RULE_REJECT_METERED);
+ future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+ future.get();
verifyAndReset();
// removing POLICY_REJECT should return us to RULE_ALLOW
- expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+ future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mService.setUidPolicy(UID_A, POLICY_NONE);
+ future.get();
verifyAndReset();
}
@@ -350,6 +402,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
long elapsedRealtime = 0;
NetworkState[] state = null;
NetworkStats stats = null;
+ Future<Void> future;
final long TIME_FEB_15 = 1171497600000L;
final long TIME_MAR_10 = 1173484800000L;
@@ -360,10 +413,11 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
state = new NetworkState[] { buildWifi() };
expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
expectTime(TIME_MAR_10 + elapsedRealtime);
- expectMeteredIfacesChanged();
+ future = expectMeteredIfacesChanged();
replay();
mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ future.get();
verifyAndReset();
// now change cycle to be on 15th, and test in early march, to verify we
@@ -381,26 +435,31 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
// TODO: write up NetworkManagementService mock
expectClearNotifications();
- expectMeteredIfacesChanged(TEST_IFACE);
+ future = expectMeteredIfacesChanged(TEST_IFACE);
replay();
setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1024L, 2048L));
+ future.get();
verifyAndReset();
}
public void testUidRemovedPolicyCleared() throws Exception {
+ Future<Void> future;
+
// POLICY_REJECT should RULE_REJECT in background
- expectRulesChanged(UID_A, RULE_REJECT_METERED);
+ future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+ future.get();
verifyAndReset();
// uninstall should clear RULE_REJECT
- expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+ future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
final Intent intent = new Intent(ACTION_UID_REMOVED);
intent.putExtra(EXTRA_UID, UID_A);
mServiceContext.sendBroadcast(intent);
+ future.get();
verifyAndReset();
}
@@ -435,14 +494,35 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
expectLastCall().anyTimes();
}
- private void expectRulesChanged(int uid, int policy) throws Exception {
+ private Future<Void> expectRulesChanged(int uid, int policy) throws Exception {
+ final FutureAnswer future = new FutureAnswer();
mPolicyListener.onUidRulesChanged(eq(uid), eq(policy));
- expectLastCall().atLeastOnce();
+ expectLastCall().andAnswer(future);
+ return future;
}
- private void expectMeteredIfacesChanged(String... ifaces) throws Exception {
+ private Future<Void> expectMeteredIfacesChanged(String... ifaces) throws Exception {
+ final FutureAnswer future = new FutureAnswer();
mPolicyListener.onMeteredIfacesChanged(aryEq(ifaces));
- expectLastCall().atLeastOnce();
+ expectLastCall().andAnswer(future);
+ return future;
+ }
+
+ private static class FutureAnswer extends AbstractFuture<Void> implements IAnswer<Void> {
+ @Override
+ public Void get() throws InterruptedException, ExecutionException {
+ try {
+ return get(5, TimeUnit.SECONDS);
+ } catch (TimeoutException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public Void answer() {
+ set(null);
+ return null;
+ }
}
private void replay() {
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 636d059..903f2b0 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -59,7 +59,6 @@ import android.os.INetworkManagementService;
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
import android.util.TrustedTime;
import com.android.server.net.NetworkStatsService;
@@ -611,6 +610,9 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
mAlarmManager.setInexactRepeating(
eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), isA(PendingIntent.class));
expectLastCall().atLeastOnce();
+
+ mNetManager.setBandwidthControlEnabled(true);
+ expectLastCall().atLeastOnce();
}
private void expectNetworkState(NetworkState... state) throws Exception {
@@ -631,6 +633,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
private void expectSettings(long persistThreshold, long bucketDuration, long maxHistory)
throws Exception {
+ expect(mSettings.getEnabled()).andReturn(true).anyTimes();
expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes();
expect(mSettings.getPersistThreshold()).andReturn(persistThreshold).anyTimes();
expect(mSettings.getNetworkBucketDuration()).andReturn(bucketDuration).anyTimes();