Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.net;
     18 
     19 import static android.net.NetworkStats.SET_ALL;
     20 import static android.net.NetworkStats.TAG_NONE;
     21 import static android.net.NetworkStats.UID_ALL;
     22 import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
     23 
     24 import android.net.NetworkStats;
     25 import android.os.StrictMode;
     26 import android.os.SystemClock;
     27 
     28 import com.android.internal.util.ProcFileReader;
     29 
     30 import java.io.File;
     31 import java.io.FileInputStream;
     32 import java.io.IOException;
     33 
     34 import libcore.io.IoUtils;
     35 
     36 /**
     37  * Creates {@link NetworkStats} instances by parsing various {@code /proc/}
     38  * files as needed.
     39  */
     40 public class NetworkStatsFactory {
     41     private static final String TAG = "NetworkStatsFactory";
     42 
     43     // TODO: consider moving parsing to native code
     44 
     45     /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */
     46     private final File mStatsXtIfaceAll;
     47     /** Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}. */
     48     private final File mStatsXtIfaceFmt;
     49     /** Path to {@code /proc/net/xt_qtaguid/stats}. */
     50     private final File mStatsXtUid;
     51 
     52     public NetworkStatsFactory() {
     53         this(new File("/proc/"));
     54     }
     55 
     56     // @VisibleForTesting
     57     public NetworkStatsFactory(File procRoot) {
     58         mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all");
     59         mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt");
     60         mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
     61     }
     62 
     63     /**
     64      * Parse and return interface-level summary {@link NetworkStats} measured
     65      * using {@code /proc/net/dev} style hooks, which may include non IP layer
     66      * traffic. Values monotonically increase since device boot, and may include
     67      * details about inactive interfaces.
     68      *
     69      * @throws IllegalStateException when problem parsing stats.
     70      */
     71     public NetworkStats readNetworkStatsSummaryDev() throws IllegalStateException {
     72         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
     73 
     74         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
     75         final NetworkStats.Entry entry = new NetworkStats.Entry();
     76 
     77         ProcFileReader reader = null;
     78         try {
     79             reader = new ProcFileReader(new FileInputStream(mStatsXtIfaceAll));
     80 
     81             while (reader.hasMoreData()) {
     82                 entry.iface = reader.nextString();
     83                 entry.uid = UID_ALL;
     84                 entry.set = SET_ALL;
     85                 entry.tag = TAG_NONE;
     86 
     87                 final boolean active = reader.nextInt() != 0;
     88 
     89                 // always include snapshot values
     90                 entry.rxBytes = reader.nextLong();
     91                 entry.rxPackets = reader.nextLong();
     92                 entry.txBytes = reader.nextLong();
     93                 entry.txPackets = reader.nextLong();
     94 
     95                 // fold in active numbers, but only when active
     96                 if (active) {
     97                     entry.rxBytes += reader.nextLong();
     98                     entry.rxPackets += reader.nextLong();
     99                     entry.txBytes += reader.nextLong();
    100                     entry.txPackets += reader.nextLong();
    101                 }
    102 
    103                 stats.addValues(entry);
    104                 reader.finishLine();
    105             }
    106         } catch (NullPointerException e) {
    107             throw new IllegalStateException("problem parsing stats: " + e);
    108         } catch (NumberFormatException e) {
    109             throw new IllegalStateException("problem parsing stats: " + e);
    110         } catch (IOException e) {
    111             throw new IllegalStateException("problem parsing stats: " + e);
    112         } finally {
    113             IoUtils.closeQuietly(reader);
    114             StrictMode.setThreadPolicy(savedPolicy);
    115         }
    116         return stats;
    117     }
    118 
    119     /**
    120      * Parse and return interface-level summary {@link NetworkStats}. Designed
    121      * to return only IP layer traffic. Values monotonically increase since
    122      * device boot, and may include details about inactive interfaces.
    123      *
    124      * @throws IllegalStateException when problem parsing stats.
    125      */
    126     public NetworkStats readNetworkStatsSummaryXt() throws IllegalStateException {
    127         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
    128 
    129         // return null when kernel doesn't support
    130         if (!mStatsXtIfaceFmt.exists()) return null;
    131 
    132         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
    133         final NetworkStats.Entry entry = new NetworkStats.Entry();
    134 
    135         ProcFileReader reader = null;
    136         try {
    137             // open and consume header line
    138             reader = new ProcFileReader(new FileInputStream(mStatsXtIfaceFmt));
    139             reader.finishLine();
    140 
    141             while (reader.hasMoreData()) {
    142                 entry.iface = reader.nextString();
    143                 entry.uid = UID_ALL;
    144                 entry.set = SET_ALL;
    145                 entry.tag = TAG_NONE;
    146 
    147                 entry.rxBytes = reader.nextLong();
    148                 entry.rxPackets = reader.nextLong();
    149                 entry.txBytes = reader.nextLong();
    150                 entry.txPackets = reader.nextLong();
    151 
    152                 stats.addValues(entry);
    153                 reader.finishLine();
    154             }
    155         } catch (NullPointerException e) {
    156             throw new IllegalStateException("problem parsing stats: " + e);
    157         } catch (NumberFormatException e) {
    158             throw new IllegalStateException("problem parsing stats: " + e);
    159         } catch (IOException e) {
    160             throw new IllegalStateException("problem parsing stats: " + e);
    161         } finally {
    162             IoUtils.closeQuietly(reader);
    163             StrictMode.setThreadPolicy(savedPolicy);
    164         }
    165         return stats;
    166     }
    167 
    168     public NetworkStats readNetworkStatsDetail() {
    169         return readNetworkStatsDetail(UID_ALL);
    170     }
    171 
    172     /**
    173      * Parse and return {@link NetworkStats} with UID-level details. Values
    174      * monotonically increase since device boot.
    175      *
    176      * @throws IllegalStateException when problem parsing stats.
    177      */
    178     public NetworkStats readNetworkStatsDetail(int limitUid) throws IllegalStateException {
    179         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
    180 
    181         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
    182         final NetworkStats.Entry entry = new NetworkStats.Entry();
    183 
    184         int idx = 1;
    185         int lastIdx = 1;
    186 
    187         ProcFileReader reader = null;
    188         try {
    189             // open and consume header line
    190             reader = new ProcFileReader(new FileInputStream(mStatsXtUid));
    191             reader.finishLine();
    192 
    193             while (reader.hasMoreData()) {
    194                 idx = reader.nextInt();
    195                 if (idx != lastIdx + 1) {
    196                     throw new IllegalStateException(
    197                             "inconsistent idx=" + idx + " after lastIdx=" + lastIdx);
    198                 }
    199                 lastIdx = idx;
    200 
    201                 entry.iface = reader.nextString();
    202                 entry.tag = kernelToTag(reader.nextString());
    203                 entry.uid = reader.nextInt();
    204                 entry.set = reader.nextInt();
    205                 entry.rxBytes = reader.nextLong();
    206                 entry.rxPackets = reader.nextLong();
    207                 entry.txBytes = reader.nextLong();
    208                 entry.txPackets = reader.nextLong();
    209 
    210                 if (limitUid == UID_ALL || limitUid == entry.uid) {
    211                     stats.addValues(entry);
    212                 }
    213 
    214                 reader.finishLine();
    215             }
    216         } catch (NullPointerException e) {
    217             throw new IllegalStateException("problem parsing idx " + idx, e);
    218         } catch (NumberFormatException e) {
    219             throw new IllegalStateException("problem parsing idx " + idx, e);
    220         } catch (IOException e) {
    221             throw new IllegalStateException("problem parsing idx " + idx, e);
    222         } finally {
    223             IoUtils.closeQuietly(reader);
    224             StrictMode.setThreadPolicy(savedPolicy);
    225         }
    226 
    227         return stats;
    228     }
    229 }
    230