/* (C) 2012 Pragmatic Software This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/ */ package com.googlecode.networklog; import android.util.Log; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class ThroughputTracker { public static String throughputString = ""; static class ThroughputData { ApplicationsTracker.AppEntry app; String address; long upload; long download; long clearTime; boolean displayed; } public static HashMap<String, ThroughputData> throughputMap = new HashMap<String, ThroughputData>(); public static HashMap<String, ThroughputData> resetMap = new HashMap<String, ThroughputData>(); private static ApplicationsTracker.AppEntry appEntry; public static void updateEntry(LogEntry entry) { appEntry = ApplicationsTracker.uidMap.get(entry.uidString); if(appEntry == null) { Log.w("NetworkLog", "[ThroughputTracker] No app entry for uid " + entry.uidString); return; } synchronized(throughputMap) { ThroughputData throughput = throughputMap.get(appEntry.packageName); if(throughput == null) { throughput = new ThroughputData(); throughput.app = appEntry; throughputMap.put(appEntry.packageName, throughput); } if(throughput.displayed == true) { throughput.download = 0; throughput.upload = 0; } if(entry.in != null && entry.in.length() > 0) { if(NetworkLogService.throughputBps) { throughput.download += entry.len * Byte.SIZE; } else { throughput.download += entry.len; } throughput.address = entry.src + ":" + entry.spt; } else { if(NetworkLogService.throughputBps) { throughput.upload += entry.len * Byte.SIZE; } else { throughput.upload += entry.len; } throughput.address = entry.dst + ":" + entry.dpt; } throughput.clearTime = System.currentTimeMillis() + NetworkLogService.toastDuration; throughput.displayed = false; } } static class ThroughputUpdater implements Runnable { boolean running = false; long totalUpload; long totalDownload; StringBuilder toastString = new StringBuilder(512); public void stop() { running = false; } public void run() { String throughput; boolean isDirty = false; running = true; String newline; while(running) { synchronized(throughputMap) { if(isDirty) { isDirty = false; if(!resetMap.isEmpty()) { for(ThroughputData entry : resetMap.values()) { if(NetworkLog.appFragment != null) { NetworkLog.appFragment.updateAppThroughput(entry.app.uid, 0, 0); } } resetMap.clear(); } updateThroughput(0, 0); totalUpload = 0; totalDownload = 0; } if(!throughputMap.isEmpty()) { isDirty = true; toastString.setLength(0); newline = ""; long currentTime = System.currentTimeMillis(); boolean showToast = false; Iterator entries = throughputMap.entrySet().iterator(); while(entries.hasNext()) { Map.Entry entry = (Map.Entry) entries.next(); ThroughputData value = (ThroughputData) entry.getValue(); if(value.displayed == false) { totalUpload += value.upload; totalDownload += value.download; if(NetworkLog.appFragment != null) { NetworkLog.appFragment.updateAppThroughput(value.app.uid, value.upload, value.download); resetMap.put(value.app.packageName, value); } } if(NetworkLogService.toastBlockedApps.get(value.app.packageName) == null) { showToast = true; if(NetworkLogService.invertUploadDownload) { throughput = StringUtils.formatToBytes(value.download) + (NetworkLogService.throughputBps ? "bps/" : "B/") + StringUtils.formatToBytes(value.upload) + (NetworkLogService.throughputBps ? "bps" : "B"); } else { throughput = StringUtils.formatToBytes(value.upload) + (NetworkLogService.throughputBps ? "bps/" : "B/") + StringUtils.formatToBytes(value.download) + (NetworkLogService.throughputBps ? "bps" : "B"); } if(MyLog.enabled && MyLog.level >= 2 && value.displayed == false) { MyLog.d(2, value.app.name + " throughput: " + throughput); } if(NetworkLogService.toastShowAddress) { toastString.append(newline + "<b>" + value.app.name + "</b>: <u>" + value.address + "</u> <i>" + throughput + "</i>"); } else { toastString.append(newline + "<b>" + value.app.name + "</b>: " + throughput); } newline = "<br>"; } value.displayed = true; if(currentTime >= value.clearTime) { entries.remove(); } } if(showToast) { NetworkLogService.showToast(toastString); } updateThroughput(totalUpload, totalDownload); totalUpload = 0; totalDownload = 0; } } try { Thread.sleep(1000); } catch (Exception e) { Log.d("NetworkLog", "ThroughputUpdater", e); } } } } static ThroughputUpdater updater; public static void startUpdater() { if(updater != null) { stopUpdater(); } updateThroughput(0, 0); updater = new ThroughputUpdater(); new Thread(updater, "ThroughputUpdater").start(); } public static void stopUpdater() { if(updater == null) { return; } updateThroughput(-1, -1); updater.stop(); updater = null; } public static void updateThroughput(long upload, long download) { if(NetworkLogService.instance == null || upload == -1 || download == -1) { throughputString = ""; } else { if(NetworkLogService.invertUploadDownload) { throughputString = StringUtils.formatToBytes(download) + (NetworkLogService.throughputBps ? "bps/" : "B/") + StringUtils.formatToBytes(upload) + (NetworkLogService.throughputBps ? "bps" : "B"); } else { throughputString = StringUtils.formatToBytes(upload) + (NetworkLogService.throughputBps ? "bps/" : "B/") + StringUtils.formatToBytes(download) + (NetworkLogService.throughputBps ? "bps" : "B"); } if(MyLog.enabled && MyLog.level >= 2) { MyLog.d(2, "Throughput: " + throughputString); } } int icon; if(upload > 0 && download > 0) { icon = R.drawable.up1_down1; } else if(upload > 0 && download == 0) { icon = R.drawable.up1_down0; } else if(upload == 0 && download > 0) { icon = R.drawable.up0_down1; } else { icon = R.drawable.up0_down0; } NetworkLogService.updateNotification(icon); NetworkLog.updateStatus(icon); } public static void updateThroughputBps() { if(updater != null) { synchronized(throughputMap) { for(ThroughputData item : throughputMap.values()) { if(item.displayed == false) { if(NetworkLogService.throughputBps) { item.upload *= Byte.SIZE; item.download *= Byte.SIZE; } else { item.upload /= Byte.SIZE; item.download /= Byte.SIZE; } } } if(NetworkLogService.throughputBps) { updater.totalUpload *= Byte.SIZE; updater.totalDownload *= Byte.SIZE; } else { updater.totalUpload /= Byte.SIZE; updater.totalDownload /= Byte.SIZE; } updateThroughput(updater.totalUpload, updater.totalDownload); } } if(NetworkLog.appFragment != null) { NetworkLog.appFragment.updateAppThroughputBps(); } } }