Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5a7bcf31 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Move non-monotonic reporting to interface.

Report non-monotonic NetworkStats through an observer interface
instead of throwing, since those events are still recoverable.

Change-Id: Ic0749f4634b0ac05dbe90e95ca490957ec8b2f23
parent b8f90a0e
Loading
Loading
Loading
Loading
+40 −56
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

package android.net;

import static com.android.internal.util.Preconditions.checkNotNull;

import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -40,8 +38,6 @@ import java.util.HashSet;
 * @hide
 */
public class NetworkStats implements Parcelable {
    private static final String TAG = "NetworkStats";

    /** {@link #iface} value when interface details unavailable. */
    public static final String IFACE_ALL = null;
    /** {@link #uid} value when UID details unavailable. */
@@ -463,62 +459,64 @@ public class NetworkStats implements Parcelable {
     * between two snapshots in time. Assumes that statistics rows collect over
     * time, and that none of them have disappeared.
     */
    public NetworkStats subtract(NetworkStats value) throws NonMonotonicException {
        return subtract(value, false);
    public NetworkStats subtract(NetworkStats right) {
        return subtract(this, right, null);
    }

    /**
     * Subtract the given {@link NetworkStats}, effectively leaving the delta
     * Subtract the two given {@link NetworkStats} objects, returning the delta
     * between two snapshots in time. Assumes that statistics rows collect over
     * time, and that none of them have disappeared.
     *
     * @param clampNonMonotonic When non-monotonic stats are found, just clamp
     *            to 0 instead of throwing {@link NonMonotonicException}.
     * <p>
     * If counters have rolled backwards, they are clamped to {@code 0} and
     * reported to the given {@link NonMonotonicObserver}.
     */
    public NetworkStats subtract(NetworkStats value, boolean clampNonMonotonic)
            throws NonMonotonicException {
        final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime;
    public static NetworkStats subtract(
            NetworkStats left, NetworkStats right, NonMonotonicObserver observer) {
        long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime;
        if (deltaRealtime < 0) {
            throw new NonMonotonicException(this, value);
            if (observer != null) {
                observer.foundNonMonotonic(left, -1, right, -1);
            }
            deltaRealtime = 0;
        }

        // result will have our rows, and elapsed time between snapshots
        final Entry entry = new Entry();
        final NetworkStats result = new NetworkStats(deltaRealtime, size);
        for (int i = 0; i < size; i++) {
            entry.iface = iface[i];
            entry.uid = uid[i];
            entry.set = set[i];
            entry.tag = tag[i];
        final NetworkStats result = new NetworkStats(deltaRealtime, left.size);
        for (int i = 0; i < left.size; i++) {
            entry.iface = left.iface[i];
            entry.uid = left.uid[i];
            entry.set = left.set[i];
            entry.tag = left.tag[i];

            // find remote row that matches, and subtract
            final int j = value.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, i);
            final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, i);
            if (j == -1) {
                // newly appearing row, return entire value
                entry.rxBytes = rxBytes[i];
                entry.rxPackets = rxPackets[i];
                entry.txBytes = txBytes[i];
                entry.txPackets = txPackets[i];
                entry.operations = operations[i];
                entry.rxBytes = left.rxBytes[i];
                entry.rxPackets = left.rxPackets[i];
                entry.txBytes = left.txBytes[i];
                entry.txPackets = left.txPackets[i];
                entry.operations = left.operations[i];
            } else {
                // existing row, subtract remote value
                entry.rxBytes = rxBytes[i] - value.rxBytes[j];
                entry.rxPackets = rxPackets[i] - value.rxPackets[j];
                entry.txBytes = txBytes[i] - value.txBytes[j];
                entry.txPackets = txPackets[i] - value.txPackets[j];
                entry.operations = operations[i] - value.operations[j];
                entry.rxBytes = left.rxBytes[i] - right.rxBytes[j];
                entry.rxPackets = left.rxPackets[i] - right.rxPackets[j];
                entry.txBytes = left.txBytes[i] - right.txBytes[j];
                entry.txPackets = left.txPackets[i] - right.txPackets[j];
                entry.operations = left.operations[i] - right.operations[j];

                if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
                        || entry.txPackets < 0 || entry.operations < 0) {
                    if (clampNonMonotonic) {
                    if (observer != null) {
                        observer.foundNonMonotonic(left, i, right, j);
                    }
                    entry.rxBytes = Math.max(entry.rxBytes, 0);
                    entry.rxPackets = Math.max(entry.rxPackets, 0);
                    entry.txBytes = Math.max(entry.txBytes, 0);
                    entry.txPackets = Math.max(entry.txPackets, 0);
                    entry.operations = Math.max(entry.operations, 0);
                    } else {
                        throw new NonMonotonicException(this, i, value, j);
                    }
                }
            }

@@ -665,22 +663,8 @@ public class NetworkStats implements Parcelable {
        }
    };

    public static class NonMonotonicException extends Exception {
        public final NetworkStats left;
        public final NetworkStats right;
        public final int leftIndex;
        public final int rightIndex;

        public NonMonotonicException(NetworkStats left, NetworkStats right) {
            this(left, -1, right, -1);
        }

        public NonMonotonicException(
                NetworkStats left, int leftIndex, NetworkStats right, int rightIndex) {
            this.left = checkNotNull(left, "missing left");
            this.right = checkNotNull(right, "missing right");
            this.leftIndex = leftIndex;
            this.rightIndex = rightIndex;
        }
    public interface NonMonotonicObserver {
        public void foundNonMonotonic(
                NetworkStats left, int leftIndex, NetworkStats right, int rightIndex);
    }
}
+6 −10
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import android.app.DownloadManager;
import android.app.backup.BackupManager;
import android.content.Context;
import android.media.MediaPlayer;
import android.net.NetworkStats.NonMonotonicException;
import android.os.RemoteException;
import android.os.ServiceManager;

@@ -193,15 +192,12 @@ public class TrafficStats {
                throw new IllegalStateException("not profiling data");
            }

            try {
            // subtract starting values and return delta
            final NetworkStats profilingStop = getDataLayerSnapshotForUid(context);
                final NetworkStats profilingDelta = profilingStop.subtract(sActiveProfilingStart);
            final NetworkStats profilingDelta = NetworkStats.subtract(
                    profilingStop, sActiveProfilingStart, null);
            sActiveProfilingStart = null;
            return profilingDelta;
            } catch (NonMonotonicException e) {
                throw new RuntimeException(e);
            }
        }
    }

+27 −22
Original line number Diff line number Diff line
@@ -71,7 +71,7 @@ import android.net.NetworkIdentity;
import android.net.NetworkInfo;
import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkStats.NonMonotonicException;
import android.net.NetworkStats.NonMonotonicObserver;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.os.Binder;
@@ -1551,34 +1551,39 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
        }
    }

    /**
     * Return the delta between two {@link NetworkStats} snapshots, where {@code
     * before} can be {@code null}.
     */
    private NetworkStats computeStatsDelta(
            NetworkStats before, NetworkStats current, boolean collectStale, String type) {
        if (before != null) {
            try {
                return current.subtract(before, false);
            } catch (NonMonotonicException e) {
    private StatsObserver mStatsObserver = new StatsObserver();

    private class StatsObserver implements NonMonotonicObserver {
        private String mCurrentType;

        public void setCurrentType(String type) {
            mCurrentType = type;
        }

        /** {@inheritDoc} */
        public void foundNonMonotonic(
                NetworkStats left, int leftIndex, NetworkStats right, int rightIndex) {
            Log.w(TAG, "found non-monotonic values; saving to dropbox");

            // record error for debugging
            final StringBuilder builder = new StringBuilder();
                builder.append("found non-monotonic " + type + " values at left[" + e.leftIndex
                        + "] - right[" + e.rightIndex + "]\n");
                builder.append("left=").append(e.left).append('\n');
                builder.append("right=").append(e.right).append('\n');
            builder.append("found non-monotonic " + mCurrentType + " values at left[" + leftIndex
                    + "] - right[" + rightIndex + "]\n");
            builder.append("left=").append(left).append('\n');
            builder.append("right=").append(right).append('\n');
            mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString());

                try {
                    // return clamped delta to help recover
                    return current.subtract(before, true);
                } catch (NonMonotonicException e1) {
                    Log.wtf(TAG, "found non-monotonic values; returning empty delta", e1);
                    return new NetworkStats(0L, 10);
        }
    }

    /**
     * Return the delta between two {@link NetworkStats} snapshots, where {@code
     * before} can be {@code null}.
     */
    private NetworkStats computeStatsDelta(
            NetworkStats before, NetworkStats current, boolean collectStale, String type) {
        if (before != null) {
            mStatsObserver.setCurrentType(type);
            return NetworkStats.subtract(current, before, mStatsObserver);
        } else if (collectStale) {
            // caller is okay collecting stale stats for first call.
            return current;