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

Commit 9a2c2a6d authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Parse network stats using native code.

Switch to parsing detailed network stats with native code, which
is 71% faster than ProcFileReader.

Change-Id: I2525aaee74d227ce187ba3a74dd08a2b06514deb
parent 336fcac3
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -135,6 +135,18 @@ public class NetworkStats implements Parcelable {
            builder.append(" operations=").append(operations);
            return builder.toString();
        }

        @Override
        public boolean equals(Object o) {
            if (o instanceof Entry) {
                final Entry e = (Entry) o;
                return uid == e.uid && set == e.set && tag == e.tag && rxBytes == e.rxBytes
                        && rxPackets == e.rxPackets && txBytes == e.txBytes
                        && txPackets == e.txPackets && operations == e.operations
                        && iface.equals(e.iface);
            }
            return false;
        }
    }

    public NetworkStats(long elapsedRealtime, int initialSize) {
+61 −23
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import com.android.internal.util.ProcFileReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.ProtocolException;

import libcore.io.IoUtils;

@@ -41,7 +42,8 @@ import libcore.io.IoUtils;
public class NetworkStatsFactory {
    private static final String TAG = "NetworkStatsFactory";

    // TODO: consider moving parsing to native code
    private static final boolean USE_NATIVE_PARSING = true;
    private static final boolean SANITY_CHECK_NATIVE = false;

    /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */
    private final File mStatsXtIfaceAll;
@@ -69,7 +71,7 @@ public class NetworkStatsFactory {
     *
     * @throws IllegalStateException when problem parsing stats.
     */
    public NetworkStats readNetworkStatsSummaryDev() throws IllegalStateException {
    public NetworkStats readNetworkStatsSummaryDev() throws IOException {
        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();

        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
@@ -105,11 +107,9 @@ public class NetworkStatsFactory {
                reader.finishLine();
            }
        } catch (NullPointerException e) {
            throw new IllegalStateException("problem parsing stats: " + e);
            throw new ProtocolException("problem parsing stats", e);
        } catch (NumberFormatException e) {
            throw new IllegalStateException("problem parsing stats: " + e);
        } catch (IOException e) {
            throw new IllegalStateException("problem parsing stats: " + e);
            throw new ProtocolException("problem parsing stats", e);
        } finally {
            IoUtils.closeQuietly(reader);
            StrictMode.setThreadPolicy(savedPolicy);
@@ -124,7 +124,7 @@ public class NetworkStatsFactory {
     *
     * @throws IllegalStateException when problem parsing stats.
     */
    public NetworkStats readNetworkStatsSummaryXt() throws IllegalStateException {
    public NetworkStats readNetworkStatsSummaryXt() throws IOException {
        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();

        // return null when kernel doesn't support
@@ -154,11 +154,9 @@ public class NetworkStatsFactory {
                reader.finishLine();
            }
        } catch (NullPointerException e) {
            throw new IllegalStateException("problem parsing stats: " + e);
            throw new ProtocolException("problem parsing stats", e);
        } catch (NumberFormatException e) {
            throw new IllegalStateException("problem parsing stats: " + e);
        } catch (IOException e) {
            throw new IllegalStateException("problem parsing stats: " + e);
            throw new ProtocolException("problem parsing stats", e);
        } finally {
            IoUtils.closeQuietly(reader);
            StrictMode.setThreadPolicy(savedPolicy);
@@ -166,17 +164,33 @@ public class NetworkStatsFactory {
        return stats;
    }

    public NetworkStats readNetworkStatsDetail() {
    public NetworkStats readNetworkStatsDetail() throws IOException {
        return readNetworkStatsDetail(UID_ALL);
    }

    public NetworkStats readNetworkStatsDetail(int limitUid) throws IOException {
        if (USE_NATIVE_PARSING) {
            final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
            if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid) != 0) {
                throw new IOException("Failed to parse network stats");
            }
            if (SANITY_CHECK_NATIVE) {
                final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid);
                assertEquals(javaStats, stats);
            }
            return stats;
        } else {
            return javaReadNetworkStatsDetail(mStatsXtUid, limitUid);
        }
    }

    /**
     * Parse and return {@link NetworkStats} with UID-level details. Values
     * monotonically increase since device boot.
     *
     * @throws IllegalStateException when problem parsing stats.
     * Parse and return {@link NetworkStats} with UID-level details. Values are
     * expected to monotonically increase since device boot.
     */
    public NetworkStats readNetworkStatsDetail(int limitUid) throws IllegalStateException {
    @VisibleForTesting
    public static NetworkStats javaReadNetworkStatsDetail(File detailPath, int limitUid)
            throws IOException {
        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();

        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
@@ -188,13 +202,13 @@ public class NetworkStatsFactory {
        ProcFileReader reader = null;
        try {
            // open and consume header line
            reader = new ProcFileReader(new FileInputStream(mStatsXtUid));
            reader = new ProcFileReader(new FileInputStream(detailPath));
            reader.finishLine();

            while (reader.hasMoreData()) {
                idx = reader.nextInt();
                if (idx != lastIdx + 1) {
                    throw new IllegalStateException(
                    throw new ProtocolException(
                            "inconsistent idx=" + idx + " after lastIdx=" + lastIdx);
                }
                lastIdx = idx;
@@ -215,11 +229,9 @@ public class NetworkStatsFactory {
                reader.finishLine();
            }
        } catch (NullPointerException e) {
            throw new IllegalStateException("problem parsing idx " + idx, e);
            throw new ProtocolException("problem parsing idx " + idx, e);
        } catch (NumberFormatException e) {
            throw new IllegalStateException("problem parsing idx " + idx, e);
        } catch (IOException e) {
            throw new IllegalStateException("problem parsing idx " + idx, e);
            throw new ProtocolException("problem parsing idx " + idx, e);
        } finally {
            IoUtils.closeQuietly(reader);
            StrictMode.setThreadPolicy(savedPolicy);
@@ -227,4 +239,30 @@ public class NetworkStatsFactory {

        return stats;
    }

    public void assertEquals(NetworkStats expected, NetworkStats actual) {
        if (expected.size() != actual.size()) {
            throw new AssertionError(
                    "Expected size " + expected.size() + ", actual size " + actual.size());
        }

        NetworkStats.Entry expectedRow = null;
        NetworkStats.Entry actualRow = null;
        for (int i = 0; i < expected.size(); i++) {
            expectedRow = expected.getValues(i, expectedRow);
            actualRow = actual.getValues(i, actualRow);
            if (!expectedRow.equals(actualRow)) {
                throw new AssertionError(
                        "Expected row " + i + ": " + expectedRow + ", actual row " + actualRow);
            }
        }
    }

    /**
     * Parse statistics from file into given {@link NetworkStats} object. Values
     * are expected to monotonically increase since device boot.
     */
    @VisibleForTesting
    public static native int nativeReadNetworkStatsDetail(
            NetworkStats stats, String path, int limitUid);
}
+2 −2
Original line number Diff line number Diff line
@@ -5956,7 +5956,7 @@ public final class BatteryStatsImpl extends BatteryStats {
                if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
                    try {
                        mNetworkSummaryCache = mNetworkStatsFactory.readNetworkStatsSummaryDev();
                    } catch (IllegalStateException e) {
                    } catch (IOException e) {
                        Log.wtf(TAG, "problem reading network stats", e);
                    }
                }
@@ -5980,7 +5980,7 @@ public final class BatteryStatsImpl extends BatteryStats {
                    try {
                        mNetworkDetailCache = mNetworkStatsFactory
                                .readNetworkStatsDetail().groupedByUid();
                    } catch (IllegalStateException e) {
                    } catch (IOException e) {
                        Log.wtf(TAG, "problem reading network stats", e);
                    }
                }
+3 −2
Original line number Diff line number Diff line
@@ -145,7 +145,8 @@ LOCAL_SRC_FILES:= \
	android_app_backup_FullBackup.cpp \
	android_content_res_ObbScanner.cpp \
	android_content_res_Configuration.cpp \
    android_animation_PropertyValuesHolder.cpp
	android_animation_PropertyValuesHolder.cpp \
	com_android_internal_net_NetworkStatsFactory.cpp

LOCAL_C_INCLUDES += \
	$(JNI_H_INCLUDE) \
+2 −0
Original line number Diff line number Diff line
@@ -173,6 +173,7 @@ extern int register_android_content_res_ObbScanner(JNIEnv* env);
extern int register_android_content_res_Configuration(JNIEnv* env);
extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);

static AndroidRuntime* gCurRuntime = NULL;

@@ -1204,6 +1205,7 @@ static const RegJNIRec gRegJNI[] = {

    REG_JNI(register_android_animation_PropertyValuesHolder),
    REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
    REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
};

/*
Loading