/* * Copyright (C) 2011 asksven * * 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 com.asksven.android.common.kernelutils; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.StringTokenizer; import android.util.Log; //import com.asksven.andoid.common.contrib.Shell; import com.asksven.andoid.common.contrib.Util; import com.asksven.android.common.RootShell; import com.asksven.android.common.privateapiproxies.NetworkUsage; import com.asksven.android.common.privateapiproxies.StatElement; import com.asksven.android.common.shellutils.Exec; import com.asksven.android.common.shellutils.ExecResult; import com.asksven.android.common.utils.StringUtils; /** * Parses the content of /proc/net/xt_qtaguid/stats * instead of using the API functions NetworkStats stats = new NetworkStatsFactory().readNetworkStatsDetail(uid-here) because http://stackoverflow.com/questions/9080229/why-i-cant-read-proc-net-xt-qtaguid-stats-correctly-by-filereader-in-android-i * format is: * idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets * example data: * 2 bnep1 0x0 0 0 21672 217 101512 526 0 0 16940 200 4732 17 0 0 50421 174 51091 352 * 3 bnep1 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 4 bnep0 0x0 0 0 151693 2305 408790 2375 334 7 151359 2298 0 0 1010 5 309743 1720 98037 650 * 5 bnep0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 6 wl0.1 0x0 0 0 10836 131 18274 139 0 0 8716 109 2120 22 0 0 15114 96 3160 43 * 7 wl0.1 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 8 wlan0 0x0 0 0 6449931 34871 624544 8518 335259 2562 5965630 30745 149042 1564 12579 203 467333 7261 144632 1054 * 9 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 10 wlan0 0x0 1000 0 12096 146 14679 194 11944 144 152 2 0 0 14332 189 347 5 0 0 * 11 wlan0 0x0 1000 1 1885 10 1867 26 1885 10 0 0 0 0 1466 20 401 6 0 0 * 12 wlan0 0x0 1014 0 317376 551 238620 615 0 0 317376 551 0 0 0 0 238620 615 0 0 * 13 wlan0 0x0 1014 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 14 wlan0 0x0 10003 0 697215 713 84843 848 697215 713 0 0 0 0 84371 840 472 8 0 0 * 15 wlan0 0x0 10003 1 1938719 2030 321314 2437 1938719 2030 0 0 0 0 321314 2437 0 0 0 0 * value holder is Netstat * @author sven */ public class Netstats { static final String TAG = "Netstats"; private static String FILE_PATH = "/proc/net/xt_qtaguid/stats"; static final String PERMISSION_DENIED = "su rights required to access alarms are not available / were not granted"; private static final String KEY_IDX = "idx"; private static final String KEY_IFACE = "iface"; private static final String KEY_UID = "uid_tag_int"; private static final String KEY_COUNTER_SET = "cnt_set"; private static final String KEY_TAG_HEX = "acct_tag_hex"; private static final String KEY_RX_BYTES = "rx_bytes"; private static final String KEY_RX_PACKETS = "rx_packets"; private static final String KEY_TX_BYTES = "tx_bytes"; private static final String KEY_TX_PACKETS = "tx_packets"; public static ArrayList<StatElement> parseNetstats() { List<String> stats = getStats(); return parseNetstats(stats); } public static ArrayList<StatElement> parseNetstats(List<String> stats) { ArrayList<StatElement> myStats = new ArrayList<StatElement>(); if ((stats != null) && (stats.size() != 0)) { // String strRes = res.getResultLine(); if (true) //(!strRes.contains("Permission Denial")) { ArrayList<String> keys = new ArrayList<String>(); keys.add(KEY_IDX); keys.add(KEY_IFACE); keys.add(KEY_TAG_HEX); keys.add(KEY_UID); keys.add(KEY_COUNTER_SET); keys.add(KEY_RX_BYTES); keys.add(KEY_RX_PACKETS); keys.add(KEY_TX_BYTES); keys.add(KEY_TX_PACKETS); final ArrayList<String> values = new ArrayList<String>(); final HashMap<String, String> parsed = new HashMap<String, String>(); // ArrayList<String> myRes = res.getResult(); // getTestData(); // process the file, starting on line 2 long totalBytes = 0; for (int i=1; i < stats.size(); i++) { String line = stats.get(i); StringUtils.splitLine(line, values); StringUtils.parseLine(keys, values, parsed); try { //Netstat entry = new Netstat(); NetworkUsage entry = new NetworkUsage( StringUtils.getParsedInt(parsed, KEY_UID), parsed.get(KEY_IFACE), StringUtils.getParsedLong(parsed, KEY_RX_BYTES), StringUtils.getParsedLong(parsed, KEY_TX_BYTES)); myStats = addToStats(myStats, entry); totalBytes += entry.getTotalBytes(); } catch (Exception e) { Log.e(TAG, "An error occured while parsing " + line + ": " + e.getMessage()); } } // set the total so that we can calculate the ratio for (int i = 0; i < myStats.size(); i++) { myStats.get(i).setTotal(totalBytes); } } } return myStats; } private static List<String> getStats() { // ExecResult res = Exec.execPrint(new String[]{"su", "-c", "cat /proc/net/xt_qtaguid/stats"}); List<String> res = RootShell.getInstance().run("cat /proc/net/xt_qtaguid/stats"); //Util.run("su", "cat /proc/net/xt_qtaguid/stats"); return res; } /** * Stats may be duplicate for one uid+iface so we sum them up * @param stats * @param entry * @return */ static ArrayList<StatElement> addToStats(ArrayList<StatElement> stats, NetworkUsage entry) { boolean merged = false; for (int i=0; i < stats.size(); i++) { NetworkUsage current = (NetworkUsage) stats.get(i); if ( (current.getuid() == entry.getuid()) && (current.getInterface().equals(entry.getInterface())) ) { current.addBytesReceived(entry.getBytesReceived()); current.addBytesSent(entry.getBytesSent()); merged = true; break; } } // if not summed up add normally if (!merged) { stats.add(entry); } return stats; } public static boolean fileExists() { boolean exists = false; FileReader fr = null; try { fr = new FileReader(FILE_PATH); exists = true; } catch (Exception e) { exists = false; } finally { if (exists) { try { fr.close(); } catch (IOException e) { // do nothing } } } return exists; } }