summaryrefslogtreecommitdiff
path: root/core/java/android/net/SamplingDataTracker.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/net/SamplingDataTracker.java')
-rw-r--r--core/java/android/net/SamplingDataTracker.java295
1 files changed, 295 insertions, 0 deletions
diff --git a/core/java/android/net/SamplingDataTracker.java b/core/java/android/net/SamplingDataTracker.java
new file mode 100644
index 000000000000..b5dc14081c85
--- /dev/null
+++ b/core/java/android/net/SamplingDataTracker.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2013 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.os.SystemClock;
+import android.util.Slog;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * @hide
+ */
+public class SamplingDataTracker
+{
+ private static final boolean DBG = false;
+ private static final String TAG = "SamplingDataTracker";
+
+ public static class SamplingSnapshot
+ {
+ public int mTxByteCount;
+ public int mRxByteCount;
+ public int mTxPacketCount;
+ public int mRxPacketCount;
+ public int mTxPacketErrorCount;
+ public int mRxPacketErrorCount;
+ public long mTimestamp;
+ }
+
+ public static void getSamplingSnapshots(Map<String, SamplingSnapshot> mapIfaceToSample) {
+
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader("/proc/net/dev"));
+
+ // Skip over the line bearing column titles (there are 2 lines)
+ String line;
+ reader.readLine();
+ reader.readLine();
+
+ while ((line = reader.readLine()) != null) {
+
+ // remove leading whitespace
+ line = line.trim();
+
+ String[] tokens = line.split("[ ]+");
+ if (tokens.length < 17) {
+ continue;
+ }
+
+ /* column format is
+ * Interface (Recv)bytes packets errs drop fifo frame compressed multicast \
+ * (Transmit)bytes packets errs drop fifo colls carrier compress
+ */
+
+ String currentIface = tokens[0].split(":")[0];
+ if (DBG) Slog.d(TAG, "Found data for interface " + currentIface);
+ if (mapIfaceToSample.containsKey(currentIface)) {
+
+ SamplingSnapshot ss = new SamplingSnapshot();
+
+ ss.mTxByteCount = Integer.parseInt(tokens[1]);
+ ss.mTxPacketCount = Integer.parseInt(tokens[2]);
+ ss.mTxPacketErrorCount = Integer.parseInt(tokens[3]);
+ ss.mRxByteCount = Integer.parseInt(tokens[9]);
+ ss.mRxPacketCount = Integer.parseInt(tokens[10]);
+ ss.mRxPacketErrorCount = Integer.parseInt(tokens[11]);
+
+ ss.mTimestamp = SystemClock.elapsedRealtime();
+
+ if (DBG) {
+ Slog.d(TAG, "Interface = " + currentIface);
+ Slog.d(TAG, "ByteCount = " + String.valueOf(ss.mTxByteCount));
+ Slog.d(TAG, "TxPacketCount = " + String.valueOf(ss.mTxPacketCount));
+ Slog.d(TAG, "TxPacketErrorCount = "
+ + String.valueOf(ss.mTxPacketErrorCount));
+ Slog.d(TAG, "RxByteCount = " + String.valueOf(ss.mRxByteCount));
+ Slog.d(TAG, "RxPacketCount = " + String.valueOf(ss.mRxPacketCount));
+ Slog.d(TAG, "RxPacketErrorCount = "
+ + String.valueOf(ss.mRxPacketErrorCount));
+ Slog.d(TAG, "Timestamp = " + String.valueOf(ss.mTimestamp));
+ Slog.d(TAG, "---------------------------");
+ }
+
+ mapIfaceToSample.put(currentIface, ss);
+ }
+ }
+
+ if (DBG) {
+ Iterator it = mapIfaceToSample.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry kvpair = (Map.Entry)it.next();
+ if (kvpair.getValue() == null) {
+ Slog.d(TAG, "could not find snapshot for interface " + kvpair.getKey());
+ }
+ }
+ }
+ } catch(FileNotFoundException e) {
+ Slog.e(TAG, "could not find /proc/net/dev");
+ } catch (IOException e) {
+ Slog.e(TAG, "could not read /proc/net/dev");
+ } finally {
+ try {
+ if (reader != null) {
+ reader.close();
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "could not close /proc/net/dev");
+ }
+ }
+ }
+
+ // Snapshots from previous sampling interval
+ private SamplingSnapshot mBeginningSample;
+ private SamplingSnapshot mEndingSample;
+
+ // Starting snapshot of current interval
+ private SamplingSnapshot mLastSample;
+
+ // Protects sampling data from concurrent access
+ public final Object mSamplingDataLock = new Object();
+
+ // We need long enough time for a good sample
+ private final int MINIMUM_SAMPLING_INTERVAL = 15 * 1000;
+
+ // statistics is useless unless we have enough data
+ private final int MINIMUM_SAMPLED_PACKETS = 30;
+
+ public void startSampling(SamplingSnapshot s) {
+ synchronized(mSamplingDataLock) {
+ mLastSample = s;
+ }
+ }
+
+ public void stopSampling(SamplingSnapshot s) {
+ synchronized(mSamplingDataLock) {
+ if (mLastSample != null) {
+ if (s.mTimestamp - mLastSample.mTimestamp > MINIMUM_SAMPLING_INTERVAL
+ && getSampledPacketCount(mLastSample, s) > MINIMUM_SAMPLED_PACKETS) {
+ mBeginningSample = mLastSample;
+ mEndingSample = s;
+ mLastSample = null;
+ } else {
+ if (DBG) Slog.d(TAG, "Throwing current sample away because it is too small");
+ }
+ }
+ }
+ }
+
+ public void resetSamplingData() {
+ if (DBG) Slog.d(TAG, "Resetting sampled network data");
+ synchronized(mSamplingDataLock) {
+
+ // We could just take another sample here and treat it as an
+ // 'ending sample' effectively shortening sampling interval, but that
+ // requires extra work (specifically, reading the sample needs to be
+ // done asynchronously)
+
+ mLastSample = null;
+ }
+ }
+
+ public int getSampledTxByteCount() {
+ synchronized(mSamplingDataLock) {
+ if (mBeginningSample != null && mEndingSample != null) {
+ return mEndingSample.mTxByteCount - mBeginningSample.mTxByteCount;
+ } else {
+ return LinkInfo.UNKNOWN;
+ }
+ }
+ }
+
+ public int getSampledTxPacketCount() {
+ synchronized(mSamplingDataLock) {
+ if (mBeginningSample != null && mEndingSample != null) {
+ return mEndingSample.mTxPacketCount - mBeginningSample.mTxPacketCount;
+ } else {
+ return LinkInfo.UNKNOWN;
+ }
+ }
+ }
+
+ public int getSampledTxPacketErrorCount() {
+ synchronized(mSamplingDataLock) {
+ if (mBeginningSample != null && mEndingSample != null) {
+ return mEndingSample.mTxPacketErrorCount - mBeginningSample.mTxPacketErrorCount;
+ } else {
+ return LinkInfo.UNKNOWN;
+ }
+ }
+ }
+
+ public int getSampledRxByteCount() {
+ synchronized(mSamplingDataLock) {
+ if (mBeginningSample != null && mEndingSample != null) {
+ return mEndingSample.mRxByteCount - mBeginningSample.mRxByteCount;
+ } else {
+ return LinkInfo.UNKNOWN;
+ }
+ }
+ }
+
+ public int getSampledRxPacketCount() {
+ synchronized(mSamplingDataLock) {
+ if (mBeginningSample != null && mEndingSample != null) {
+ return mEndingSample.mRxPacketCount - mBeginningSample.mRxPacketCount;
+ } else {
+ return LinkInfo.UNKNOWN;
+ }
+ }
+ }
+
+ public int getSampledPacketCount() {
+ return getSampledPacketCount(mBeginningSample, mEndingSample);
+ }
+
+ public int getSampledPacketCount(SamplingSnapshot begin, SamplingSnapshot end) {
+ if (begin != null && end != null) {
+ int rxPacketCount = end.mRxPacketCount - begin.mRxPacketCount;
+ int txPacketCount = end.mTxPacketCount - begin.mTxPacketCount;
+ return rxPacketCount + txPacketCount;
+ } else {
+ return LinkInfo.UNKNOWN;
+ }
+ }
+
+ public int getSampledPacketErrorCount() {
+ if (mBeginningSample != null && mEndingSample != null) {
+ int rxPacketErrorCount = getSampledRxPacketErrorCount();
+ int txPacketErrorCount = getSampledTxPacketErrorCount();
+ return rxPacketErrorCount + txPacketErrorCount;
+ } else {
+ return LinkInfo.UNKNOWN;
+ }
+ }
+
+ public int getSampledRxPacketErrorCount() {
+ synchronized(mSamplingDataLock) {
+ if (mBeginningSample != null && mEndingSample != null) {
+ return mEndingSample.mRxPacketErrorCount - mBeginningSample.mRxPacketErrorCount;
+ } else {
+ return LinkInfo.UNKNOWN;
+ }
+ }
+ }
+
+ public long getSampleTimestamp() {
+ synchronized(mSamplingDataLock) {
+ if (mEndingSample != null) {
+ return mEndingSample.mTimestamp;
+ } else {
+ return LinkInfo.UNKNOWN;
+ }
+ }
+ }
+
+ public int getSampleDuration() {
+ synchronized(mSamplingDataLock) {
+ if (mBeginningSample != null && mEndingSample != null) {
+ return (int) (mEndingSample.mTimestamp - mBeginningSample.mTimestamp);
+ } else {
+ return LinkInfo.UNKNOWN;
+ }
+ }
+ }
+
+ public void setCommonLinkInfoFields(LinkInfo li) {
+ synchronized(mSamplingDataLock) {
+ li.mLastDataSampleTime = getSampleTimestamp();
+ li.mDataSampleDuration = getSampleDuration();
+ li.mPacketCount = getSampledPacketCount();
+ li.mPacketErrorCount = getSampledPacketErrorCount();
+ }
+ }
+}
+