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