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