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

Commit 2a2dc689 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "Return NetworkStats bundle from NM service."

parents 42a3a39e 9a13f36c
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
/**
 * 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 android.net;

parcelable NetworkStats;
+158 −0
Original line number Diff line number Diff line
/*
 * 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 android.net;

import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;

import java.io.CharArrayWriter;
import java.io.PrintWriter;

/**
 * Collection of network statistics. Can contain summary details across all
 * interfaces, or details with per-UID granularity. Designed to parcel quickly
 * across process boundaries.
 *
 * @hide
 */
public class NetworkStats implements Parcelable {
    /** {@link #iface} value when entry is summarized over all interfaces. */
    public static final String IFACE_ALL = null;
    /** {@link #uid} value when entry is summarized over all UIDs. */
    public static final int UID_ALL = 0;

    /**
     * {@link SystemClock#elapsedRealtime()} timestamp when this data was
     * generated.
     */
    public final long elapsedRealtime;
    public final String[] iface;
    public final int[] uid;
    public final long[] rx;
    public final long[] tx;

    // TODO: add fg/bg stats and tag granularity

    private NetworkStats(long elapsedRealtime, String[] iface, int[] uid, long[] rx, long[] tx) {
        this.elapsedRealtime = elapsedRealtime;
        this.iface = iface;
        this.uid = uid;
        this.rx = rx;
        this.tx = tx;
    }

    public NetworkStats(Parcel parcel) {
        elapsedRealtime = parcel.readLong();
        iface = parcel.createStringArray();
        uid = parcel.createIntArray();
        rx = parcel.createLongArray();
        tx = parcel.createLongArray();
    }

    public static class Builder {
        private long mElapsedRealtime;
        private final String[] mIface;
        private final int[] mUid;
        private final long[] mRx;
        private final long[] mTx;

        private int mIndex = 0;

        public Builder(long elapsedRealtime, int size) {
            mElapsedRealtime = elapsedRealtime;
            mIface = new String[size];
            mUid = new int[size];
            mRx = new long[size];
            mTx = new long[size];
        }

        public void addEntry(String iface, int uid, long rx, long tx) {
            mIface[mIndex] = iface;
            mUid[mIndex] = uid;
            mRx[mIndex] = rx;
            mTx[mIndex] = tx;
            mIndex++;
        }

        public NetworkStats build() {
            if (mIndex != mIface.length) {
                throw new IllegalArgumentException("unexpected number of entries");
            }
            return new NetworkStats(mElapsedRealtime, mIface, mUid, mRx, mTx);
        }
    }

    /**
     * Find first stats index that matches the requested parameters.
     */
    public int findIndex(String iface, int uid) {
        for (int i = 0; i < this.iface.length; i++) {
            if (equal(iface, this.iface[i]) && uid == this.uid[i]) {
                return i;
            }
        }
        return -1;
    }

    private static boolean equal(Object a, Object b) {
        return a == b || (a != null && a.equals(b));
    }

    /** {@inheritDoc} */
    public int describeContents() {
        return 0;
    }

    public void dump(String prefix, PrintWriter pw) {
        pw.print(prefix);
        pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
        for (int i = 0; i < iface.length; i++) {
            pw.print(prefix);
            pw.print("  iface="); pw.print(iface[i]);
            pw.print(" uid="); pw.print(uid[i]);
            pw.print(" rx="); pw.print(rx[i]);
            pw.print(" tx="); pw.println(tx[i]);
        }
    }

    @Override
    public String toString() {
        final CharArrayWriter writer = new CharArrayWriter();
        dump("", new PrintWriter(writer));
        return writer.toString();
    }

    /** {@inheritDoc} */
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeLong(elapsedRealtime);
        dest.writeStringArray(iface);
        dest.writeIntArray(uid);
        dest.writeLongArray(rx);
        dest.writeLongArray(tx);
    }

    public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
        public NetworkStats createFromParcel(Parcel in) {
            return new NetworkStats(in);
        }

        public NetworkStats[] newArray(int size) {
            return new NetworkStats[size];
        }
    };
}
+12 −6
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.os;

import android.net.InterfaceConfiguration;
import android.net.INetworkManagementEventObserver;
import android.net.NetworkStats;
import android.net.wifi.WifiConfiguration;

/**
@@ -65,7 +66,6 @@ interface INetworkManagementService
     ** TETHERING RELATED
     **/


    /**
     * Returns true if IP forwarding is enabled
     */
@@ -181,17 +181,23 @@ interface INetworkManagementService
    void setAccessPoint(in WifiConfiguration wifiConfig, String wlanIface, String softapIface);

    /**
     * Read number of bytes sent over an interface
     ** DATA USAGE RELATED
     **/

    /**
     * Return global network statistics summarized at an interface level,
     * without any UID-level granularity.
     */
    long getInterfaceTxCounter(String iface);
    NetworkStats getNetworkStatsSummary();

    /**
     * Read number of bytes received over an interface
     * Return detailed network statistics with UID-level granularity,
     * including interface and tag details.
     */
    long getInterfaceRxCounter(String iface);
    NetworkStats getNetworkStatsDetail();

    /**
     * Configures bandwidth throttling on an interface
     * Configures bandwidth throttling on an interface.
     */
    void setInterfaceThrottle(String iface, int rxKbps, int txKbps);

+70 −4
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.content.pm.PackageManager;
import android.net.NetworkStats;
import android.net.Uri;
import android.net.InterfaceConfiguration;
import android.net.INetworkManagementEventObserver;
@@ -32,6 +33,8 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.os.INetworkManagementService;
import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
@@ -44,13 +47,21 @@ import android.content.ContentResolver;
import android.database.ContentObserver;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.io.Reader;
import java.lang.IllegalStateException;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.CountDownLatch;

import libcore.io.IoUtils;

/**
 * @hide
 */
@@ -716,12 +727,47 @@ class NetworkManagementService extends INetworkManagementService.Stub {
        return -1;
    }

    public long getInterfaceRxCounter(String iface) {
        return getInterfaceCounter(iface, true);
    /** {@inheritDoc} */
    public NetworkStats getNetworkStatsSummary() {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");

        final String[] ifaces = listInterfaces();
        final NetworkStats.Builder stats = new NetworkStats.Builder(
                SystemClock.elapsedRealtime(), ifaces.length);

        for (String iface : ifaces) {
            final long rx = getInterfaceCounter(iface, true);
            final long tx = getInterfaceCounter(iface, false);
            stats.addEntry(iface, NetworkStats.UID_ALL, rx, tx);
        }

    public long getInterfaceTxCounter(String iface) {
        return getInterfaceCounter(iface, false);
        return stats.build();
    }

    /** {@inheritDoc} */
    public NetworkStats getNetworkStatsDetail() {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");

        final File procPath = new File("/proc/uid_stat");
        final String[] knownUids = procPath.list();
        final NetworkStats.Builder stats = new NetworkStats.Builder(
                SystemClock.elapsedRealtime(), knownUids.length);

        // TODO: kernel module will provide interface-level stats in future
        // TODO: migrate these stats to come across netd in bulk, instead of all
        // these individual file reads.
        for (String uid : knownUids) {
            final File uidPath = new File(procPath, uid);
            final int rx = readSingleIntFromFile(new File(uidPath, "tcp_rcv"));
            final int tx = readSingleIntFromFile(new File(uidPath, "tcp_snd"));

            final int uidInt = Integer.parseInt(uid);
            stats.addEntry(NetworkStats.IFACE_ALL, uidInt, rx, tx);
        }

        return stats.build();
    }

    public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
@@ -782,4 +828,24 @@ class NetworkManagementService extends INetworkManagementService.Stub {
    public int getInterfaceTxThrottle(String iface) {
        return getInterfaceThrottle(iface, false);
    }

    /**
     * Utility method to read a single plain-text {@link Integer} from the given
     * {@link File}, usually from a {@code /proc/} filesystem.
     */
    private static int readSingleIntFromFile(File file) {
        RandomAccessFile f = null;
        try {
            f = new RandomAccessFile(file, "r");
            byte[] buffer = new byte[(int) f.length()];
            f.readFully(buffer);
            return Integer.parseInt(new String(buffer).trim());
        } catch (NumberFormatException e) {
            return -1;
        } catch (IOException e) {
            return -1;
        } finally {
            IoUtils.closeQuietly(f);
        }
    }
}
+12 −2
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.INetworkManagementEventObserver;
import android.net.IThrottleManager;
import android.net.NetworkStats;
import android.net.ThrottleManager;
import android.os.Binder;
import android.os.Environment;
@@ -531,8 +532,17 @@ public class ThrottleService extends IThrottleManager.Stub {
            long incRead = 0;
            long incWrite = 0;
            try {
                incRead = mNMService.getInterfaceRxCounter(mIface) - mLastRead;
                incWrite = mNMService.getInterfaceTxCounter(mIface) - mLastWrite;
                final NetworkStats stats = mNMService.getNetworkStatsSummary();
                final int index = stats.findIndex(mIface, NetworkStats.UID_ALL);

                if (index != -1) {
                    incRead = stats.rx[index] - mLastRead;
                    incWrite = stats.tx[index] - mLastWrite;
                } else {
                    // missing iface, assume stats are 0
                    Slog.w(TAG, "unable to find stats for iface " + mIface);
                }

                // handle iface resets - on some device the 3g iface comes and goes and gets
                // totals reset to 0.  Deal with it
                if ((incRead < 0) || (incWrite < 0)) {
Loading