diff options
Diffstat (limited to 'core/java/android/net/SamplingDataTracker.java')
| -rw-r--r-- | core/java/android/net/SamplingDataTracker.java | 295 |
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(); + } + } +} + |
