diff options
Diffstat (limited to 'core/java/android/os')
-rw-r--r-- | core/java/android/os/BatteryStats.java | 305 | ||||
-rw-r--r-- | core/java/android/os/Binder.java | 44 | ||||
-rw-r--r-- | core/java/android/os/Build.java | 3 | ||||
-rw-r--r-- | core/java/android/os/Debug.java | 26 | ||||
-rw-r--r-- | core/java/android/os/Environment.java | 12 | ||||
-rw-r--r-- | core/java/android/os/IBinder.java | 11 | ||||
-rw-r--r-- | core/java/android/os/ICheckinService.aidl | 3 | ||||
-rw-r--r-- | core/java/android/os/IMountService.aidl | 15 | ||||
-rw-r--r-- | core/java/android/os/INetStatService.aidl | 15 | ||||
-rw-r--r-- | core/java/android/os/NetStat.java | 187 |
10 files changed, 568 insertions, 53 deletions
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index ed7c366..017b14d 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -15,19 +15,26 @@ import android.util.SparseArray; public abstract class BatteryStats { /** - * A constant indicating a partial wake lock. + * A constant indicating a partial wake lock timer. */ public static final int WAKE_TYPE_PARTIAL = 0; /** - * A constant indicating a full wake lock. + * A constant indicating a full wake lock timer. */ public static final int WAKE_TYPE_FULL = 1; /** - * A constant indicating a window wake lock. + * A constant indicating a window wake lock timer. */ public static final int WAKE_TYPE_WINDOW = 2; + + /** + * A constant indicating a sensor timer. + * + * {@hide} + */ + public static final int SENSOR = 3; /** * Include all of the data in the stats, including previously saved data. @@ -48,6 +55,21 @@ public abstract class BatteryStats { * Include only the run since the last time the device was unplugged in the stats. */ public static final int STATS_UNPLUGGED = 3; + + /** + * Bump the version on this if the checkin format changes. + */ + private static final int BATTERY_STATS_CHECKIN_VERSION = 1; + + // TODO: Update this list if you add/change any stats above. + private static final String[] STAT_NAMES = { "total", "last", "current", "unplugged" }; + + private static final String APK_DATA = "apk"; + private static final String PROCESS_DATA = "process"; + private static final String SENSOR_DATA = "sensor"; + private static final String WAKELOCK_DATA = "wakelock"; + private static final String NETWORK_DATA = "network"; + private static final String BATTERY_DATA = "battery"; private final StringBuilder mFormatBuilder = new StringBuilder(8); private final Formatter mFormatter = new Formatter(mFormatBuilder); @@ -115,8 +137,28 @@ public abstract class BatteryStats { * @return a Map from Strings to Uid.Pkg objects. */ public abstract Map<String, ? extends Pkg> getPackageStats(); + + /** + * {@hide} + */ + public abstract int getUid(); + + /** + * {@hide} + */ + public abstract long getTcpBytesReceived(int which); + + /** + * {@hide} + */ + public abstract long getTcpBytesSent(int which); public static abstract class Sensor { + /** + * {@hide} + */ + public abstract String getName(); + public abstract Timer getSensorTime(); } @@ -200,6 +242,22 @@ public abstract class BatteryStats { * Returns the number of times the device has been started. */ public abstract int getStartCount(); + + /** + * Returns the time in milliseconds that the screen has been on while the device was + * running on battery. + * + * {@hide} + */ + public abstract long getBatteryScreenOnTime(); + + /** + * Returns the time in milliseconds that the screen has been on while the device was + * plugged in. + * + * {@hide} + */ + public abstract long getPluggedScreenOnTime(); /** * Returns a SparseArray containing the statistics for each uid. @@ -318,11 +376,14 @@ public abstract class BatteryStats { * @param linePrefix a String to be prepended to each line of output. * @return the line prefix */ - private final String printWakeLock(StringBuilder sb, Timer timer, long now, + private static final String printWakeLock(StringBuilder sb, Timer timer, long now, String name, int which, String linePrefix) { + if (timer != null) { // Convert from microseconds to milliseconds with rounding - long totalTimeMillis = (timer.getTotalTime(now, which) + 500) / 1000; + long totalTimeMicros = timer.getTotalTime(now, which); + long totalTimeMillis = (totalTimeMicros + 500) / 1000; + int count = timer.getCount(which); if (totalTimeMillis != 0) { sb.append(linePrefix); @@ -337,6 +398,184 @@ public abstract class BatteryStats { } return linePrefix; } + + /** + * Checkin version of wakelock printer. Prints simple comma-separated list. + * + * @param sb a StringBuilder object. + * @param timer a Timer object contining the wakelock times. + * @param now the current time in microseconds. + * @param name the name of the wakelock. + * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. + * @param linePrefix a String to be prepended to each line of output. + * @return the line prefix + */ + private static final String printWakeLockCheckin(StringBuilder sb, Timer timer, long now, + String name, int which, String linePrefix) { + long totalTimeMicros = 0; + int count = 0; + if (timer != null) { + totalTimeMicros = timer.getTotalTime(now, which); + count = timer.getCount(which); + } + sb.append(linePrefix); + sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding + sb.append(','); + sb.append(name); + sb.append(','); + sb.append(count); + return ","; + } + + /** + * Dump a comma-separated line of values for terse checkin mode. + * + * @param pw the PageWriter to dump log to + * @param category category of data (e.g. "total", "last", "unplugged", "current" ) + * @param type type of data (e.g. "wakelock", "sensor", "process", "apk" , "process", "network") + * @param args type-dependent data arguments + */ + private static final void dumpLine(PrintWriter pw, int uid, String category, String type, + Object... args ) { + pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); + pw.print(uid); pw.print(','); + pw.print(category); pw.print(','); + pw.print(type); + + for (Object arg : args) { + pw.print(','); + pw.print(arg); + } + pw.print('\n'); + } + + /** + * Checkin server version of dump to produce more compact, computer-readable log. + * + * NOTE: all times are expressed in 'ms'. + * @param fd + * @param pw + * @param which + */ + private final void dumpCheckinLocked(FileDescriptor fd, PrintWriter pw, int which) { + long uSecTime = SystemClock.elapsedRealtime() * 1000; + final long uSecNow = getBatteryUptime(uSecTime); + + StringBuilder sb = new StringBuilder(128); + long batteryUptime = computeBatteryUptime(uSecNow, which); + long batteryRealtime = computeBatteryRealtime(getBatteryRealtime(uSecTime), which); + long elapsedRealtime = computeRealtime(uSecTime, which); + long uptime = computeUptime(SystemClock.uptimeMillis() * 1000, which); + + String category = STAT_NAMES[which]; + + // Dump "battery" stat + dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, + which == STATS_TOTAL ? getStartCount() : "N/A", + batteryUptime / 1000, + formatRatioLocked(batteryUptime, elapsedRealtime), + batteryRealtime / 1000, + formatRatioLocked(batteryRealtime, elapsedRealtime), + uptime / 1000, + elapsedRealtime / 1000); + + SparseArray<? extends Uid> uidStats = getUidStats(); + final int NU = uidStats.size(); + for (int iu = 0; iu < NU; iu++) { + final int uid = uidStats.keyAt(iu); + Uid u = uidStats.valueAt(iu); + // Dump Network stats per uid, if any + long rx = u.getTcpBytesReceived(which); + long tx = u.getTcpBytesSent(which); + if (rx > 0 || tx > 0) dumpLine(pw, uid, category, NETWORK_DATA, rx, tx); + + Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats(); + if (wakelocks.size() > 0) { + for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent + : wakelocks.entrySet()) { + Uid.Wakelock wl = ent.getValue(); + String linePrefix = ""; + sb.setLength(0); + linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), uSecNow, + "full", which, linePrefix); + linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), uSecNow, + "partial", which, linePrefix); + linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), uSecNow, + "window", which, linePrefix); + + // Only log if we had at lease one wakelock... + if (sb.length() > 0) { + dumpLine(pw, uid, category, WAKELOCK_DATA, ent.getKey(), sb.toString()); + } + } + } + + Map<Integer, ? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats(); + if (sensors.size() > 0) { + for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent + : sensors.entrySet()) { + Uid.Sensor se = ent.getValue(); + int sensorNumber = ent.getKey(); + Timer timer = se.getSensorTime(); + if (timer != null) { + // Convert from microseconds to milliseconds with rounding + long totalTime = (timer.getTotalTime(uSecNow, which) + 500) / 1000; + int count = timer.getCount(which); + if (totalTime != 0) { + dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count); + } + } + } + } + + Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); + if (processStats.size() > 0) { + for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent + : processStats.entrySet()) { + Uid.Proc ps = ent.getValue(); + + long userTime = ps.getUserTime(which); + long systemTime = ps.getSystemTime(which); + int starts = ps.getStarts(which); + + if (userTime != 0 || systemTime != 0 || starts != 0) { + dumpLine(pw, uid, category, PROCESS_DATA, + ent.getKey(), // proc + userTime * 10, // cpu time in ms + systemTime * 10, // user time in ms + starts); // process starts + } + } + } + + Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats(); + if (packageStats.size() > 0) { + for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent + : packageStats.entrySet()) { + + Uid.Pkg ps = ent.getValue(); + int wakeups = ps.getWakeups(which); + Map<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats(); + for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent + : serviceStats.entrySet()) { + BatteryStats.Uid.Pkg.Serv ss = sent.getValue(); + long startTime = ss.getStartTime(uSecNow, which); + int starts = ss.getStarts(which); + int launches = ss.getLaunches(which); + if (startTime != 0 || starts != 0 || launches != 0) { + dumpLine(pw, uid, category, APK_DATA, + wakeups, // wakeup alarms + ent.getKey(), // Apk + sent.getKey(), // service + startTime / 1000, // time spent started, in ms + starts, + launches); + } + } + } + } + } + } @SuppressWarnings("unused") private final void dumpLocked(FileDescriptor fd, PrintWriter pw, String prefix, int which) { @@ -344,13 +583,22 @@ public abstract class BatteryStats { final long uSecNow = getBatteryUptime(uSecTime); StringBuilder sb = new StringBuilder(128); - if (which == STATS_TOTAL) { - pw.println(prefix + "Current and Historic Battery Usage Statistics:"); - pw.println(prefix + " System starts: " + getStartCount()); - } else if (which == STATS_LAST) { - pw.println(prefix + "Last Battery Usage Statistics:"); - } else { - pw.println(prefix + "Current Battery Usage Statistics:"); + switch (which) { + case STATS_TOTAL: + pw.println(prefix + "Current and Historic Battery Usage Statistics:"); + pw.println(prefix + " System starts: " + getStartCount()); + break; + case STATS_LAST: + pw.println(prefix + "Last Battery Usage Statistics:"); + break; + case STATS_UNPLUGGED: + pw.println(prefix + "Last Unplugged Battery Usage Statistics:"); + break; + case STATS_CURRENT: + pw.println(prefix + "Current Battery Usage Statistics:"); + break; + default: + throw new IllegalArgumentException("which = " + which); } long batteryUptime = computeBatteryUptime(uSecNow, which); long batteryRealtime = computeBatteryRealtime(getBatteryRealtime(uSecTime), which); @@ -359,7 +607,7 @@ public abstract class BatteryStats { pw.println(prefix + " On battery: " + formatTimeMs(batteryUptime / 1000) + "(" - + formatRatioLocked(batteryUptime, batteryRealtime) + + formatRatioLocked(batteryUptime, elapsedRealtime) + ") uptime, " + formatTimeMs(batteryRealtime / 1000) + "(" + formatRatioLocked(batteryRealtime, elapsedRealtime) @@ -380,6 +628,9 @@ public abstract class BatteryStats { Uid u = uidStats.valueAt(iu); pw.println(prefix + " #" + uid + ":"); boolean uidActivity = false; + + pw.println(prefix + " Network: " + u.getTcpBytesReceived(which) + " bytes received, " + + u.getTcpBytesSent(which) + " bytes sent"); Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats(); if (wakelocks.size() > 0) { @@ -512,12 +763,30 @@ public abstract class BatteryStats { */ @SuppressWarnings("unused") public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) { + boolean isCheckin = false; + if (args != null) { + for (String arg : args) { + if ("-c".equals(arg)) { + isCheckin = true; + break; + } + } + } synchronized (this) { - dumpLocked(fd, pw, "", STATS_TOTAL); - pw.println(""); - dumpLocked(fd, pw, "", STATS_LAST); - pw.println(""); - dumpLocked(fd, pw, "", STATS_CURRENT); + if (isCheckin) { + dumpCheckinLocked(fd, pw, STATS_TOTAL); + dumpCheckinLocked(fd, pw, STATS_LAST); + dumpCheckinLocked(fd, pw, STATS_UNPLUGGED); + dumpCheckinLocked(fd, pw, STATS_CURRENT); + } else { + dumpLocked(fd, pw, "", STATS_TOTAL); + pw.println(""); + dumpLocked(fd, pw, "", STATS_LAST); + pw.println(""); + dumpLocked(fd, pw, "", STATS_UNPLUGGED); + pw.println(""); + dumpLocked(fd, pw, "", STATS_CURRENT); + } } } } diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 528e6bd..df10c6a 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -33,7 +33,7 @@ import java.lang.reflect.Modifier; * the standard support creating a local implementation of such an object. * * <p>Most developers will not implement this class directly, instead using the - * <a href="{@docRoot}reference/aidl.html">aidl</a> tool to describe the desired + * <a href="{@docRoot}guide/developing/tools/aidl.html">aidl</a> tool to describe the desired * interface, having it generate the appropriate Binder subclass. You can, * however, derive directly from Binder to implement your own custom RPC * protocol or simply instantiate a raw Binder object directly to use as a @@ -194,18 +194,15 @@ public class Binder implements IBinder { return true; } else if (code == DUMP_TRANSACTION) { ParcelFileDescriptor fd = data.readFileDescriptor(); - FileOutputStream fout = fd != null - ? new FileOutputStream(fd.getFileDescriptor()) : null; - PrintWriter pw = fout != null ? new PrintWriter(fout) : null; - if (pw != null) { - String[] args = data.readStringArray(); - dump(fd.getFileDescriptor(), pw, args); - pw.flush(); - } + String[] args = data.readStringArray(); if (fd != null) { try { - fd.close(); - } catch (IOException e) { + dump(fd.getFileDescriptor(), args); + } finally { + try { + fd.close(); + } catch (IOException e) { + } } } return true; @@ -214,6 +211,20 @@ public class Binder implements IBinder { } /** + * Implemented to call the more convenient version + * {@link #dump(FileDescriptor, PrintWriter, String[])}. + */ + public void dump(FileDescriptor fd, String[] args) { + FileOutputStream fout = new FileOutputStream(fd); + PrintWriter pw = new PrintWriter(fout); + try { + dump(fd, pw, args); + } finally { + pw.flush(); + } + } + + /** * Print the object's state into the given stream. * * @param fd The raw file descriptor that the dump is being sent to. @@ -302,6 +313,17 @@ final class BinderProxy implements IBinder { throws RemoteException; public native boolean unlinkToDeath(DeathRecipient recipient, int flags); + public void dump(FileDescriptor fd, String[] args) throws RemoteException { + Parcel data = Parcel.obtain(); + data.writeFileDescriptor(fd); + data.writeStringArray(args); + try { + transact(DUMP_TRANSACTION, data, null, 0); + } finally { + data.recycle(); + } + } + BinderProxy() { mSelf = new WeakReference(this); } diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index cdf907b..467c17f 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -26,6 +26,9 @@ public class Build { /** Either a changelist number, or a label like "M4-rc20". */ public static final String ID = getString("ro.build.id"); + /** A build ID string meant for displaying to the user */ + public static final String DISPLAY = getString("ro.build.display.id"); + /** The name of the overall product. */ public static final String PRODUCT = getString("ro.product.name"); diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 5f7f91f..950bb09 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -17,6 +17,7 @@ package android.os; import java.io.FileOutputStream; +import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; @@ -28,12 +29,13 @@ import dalvik.bytecode.Opcodes; import dalvik.system.VMDebug; -/** Provides various debugging functions for Android applications, including +/** + * Provides various debugging functions for Android applications, including * tracing and allocation counts. * <p><strong>Logging Trace Files</strong></p> * <p>Debug can create log files that give details about an application, such as * a call stack and start/stop times for any running methods. See <a -href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for +href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for * information about reading trace files. To start logging trace files, call one * of the startMethodTracing() methods. To stop tracing, call * {@link #stopMethodTracing()}. @@ -285,7 +287,7 @@ public final class Debug /** * Start method tracing with default log name and buffer size. See <a -href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for +href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for * information about reading these files. Call stopMethodTracing() to stop * tracing. */ @@ -297,7 +299,7 @@ href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Progra * Start method tracing, specifying the trace log file name. The trace * file will be put under "/sdcard" unless an absolute path is given. * See <a - href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for + href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for * information about reading trace files. * * @param traceName Name for the trace log file to create. @@ -313,7 +315,7 @@ href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Progra * Start method tracing, specifying the trace log file name and the * buffer size. The trace files will be put under "/sdcard" unless an * absolute path is given. See <a - href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for + href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for * information about reading trace files. * @param traceName Name for the trace log file to create. * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace". @@ -330,7 +332,7 @@ href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Progra * Start method tracing, specifying the trace log file name and the * buffer size. The trace files will be put under "/sdcard" unless an * absolute path is given. See <a - href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for + href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for * information about reading trace files. * * <p> @@ -581,6 +583,18 @@ href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Progra } /** + * Dump "hprof" data to the specified file. This will cause a GC. + * + * @param fileName Full pathname of output file (e.g. "/sdcard/dump.hprof"). + * @throws UnsupportedOperationException if the VM was built without + * HPROF support. + * @throws IOException if an error occurs while opening or writing files. + */ + public static void dumpHprofData(String fileName) throws IOException { + VMDebug.dumpHprofData(fileName); + } + + /** * Returns the number of sent transactions from this process. * @return The number of sent transactions or -1 if it could not read t. */ diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index e37b551..f761e8e 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -75,6 +75,18 @@ public class Environment { public static final String MEDIA_UNMOUNTED = "unmounted"; /** + * getExternalStorageState() returns MEDIA_CHECKING if the media is present + * and being disk-checked + */ + public static final String MEDIA_CHECKING = "checking"; + + /** + * getExternalStorageState() returns MEDIA_NOFS if the media is present + * but is blank or is using an unsupported filesystem + */ + public static final String MEDIA_NOFS = "nofs"; + + /** * getExternalStorageState() returns MEDIA_MOUNTED if the media is present * and mounted at its mount point with read/write access. */ diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java index 3ec0e9b..5c40c9a0 100644 --- a/core/java/android/os/IBinder.java +++ b/core/java/android/os/IBinder.java @@ -16,6 +16,9 @@ package android.os; +import java.io.FileDescriptor; +import java.io.PrintWriter; + /** * Base interface for a remotable object, the core part of a lightweight * remote procedure call mechanism designed for high performance when @@ -145,6 +148,14 @@ public interface IBinder { public IInterface queryLocalInterface(String descriptor); /** + * Print the object's state into the given stream. + * + * @param fd The raw file descriptor that the dump is being sent to. + * @param args additional arguments to the dump request. + */ + public void dump(FileDescriptor fd, String[] args) throws RemoteException; + + /** * Perform a generic operation with the object. * * @param code The action to perform. This should diff --git a/core/java/android/os/ICheckinService.aidl b/core/java/android/os/ICheckinService.aidl index 70ad28e..11becc4 100644 --- a/core/java/android/os/ICheckinService.aidl +++ b/core/java/android/os/ICheckinService.aidl @@ -26,6 +26,9 @@ import android.os.IParentalControlCallback; * {@hide} */ interface ICheckinService { + /** Synchronously attempt a checkin with the server, return true on success. */ + boolean checkin(); + /** Direct submission of crash data; returns after writing the crash. */ void reportCrashSync(in byte[] crashData); diff --git a/core/java/android/os/IMountService.aidl b/core/java/android/os/IMountService.aidl index 0397446..88dae85 100644 --- a/core/java/android/os/IMountService.aidl +++ b/core/java/android/os/IMountService.aidl @@ -48,4 +48,19 @@ interface IMountService * Safely unmount external storage at given mount point. */ void unmountMedia(String mountPoint); + + /** + * Format external storage given a mount point + */ + void formatMedia(String mountPoint); + + /** + * Returns true if media notification sounds are enabled. + */ + boolean getPlayNotificationSounds(); + + /** + * Sets whether or not media notification sounds are played. + */ + void setPlayNotificationSounds(boolean value); } diff --git a/core/java/android/os/INetStatService.aidl b/core/java/android/os/INetStatService.aidl index fb840d8..a8f3de0 100644 --- a/core/java/android/os/INetStatService.aidl +++ b/core/java/android/os/INetStatService.aidl @@ -17,14 +17,19 @@ package android.os; /** - * Retrieves packet and byte counts for the phone data interface. + * Retrieves packet and byte counts for the phone data interface, + * and for all interfaces. * Used for the data activity icon and the phone status in Settings. * * {@hide} */ interface INetStatService { - int getTxPackets(); - int getRxPackets(); - int getTxBytes(); - int getRxBytes(); + long getMobileTxPackets(); + long getMobileRxPackets(); + long getMobileTxBytes(); + long getMobileRxBytes(); + long getTotalTxPackets(); + long getTotalRxPackets(); + long getTotalTxBytes(); + long getTotalRxBytes(); } diff --git a/core/java/android/os/NetStat.java b/core/java/android/os/NetStat.java index 7312236..733137a 100644 --- a/core/java/android/os/NetStat.java +++ b/core/java/android/os/NetStat.java @@ -16,36 +16,197 @@ package android.os; +import android.util.Log; + +import java.io.File; +import java.io.RandomAccessFile; +import java.io.IOException; + /** @hide */ public class NetStat{ /** - * Get total number of tx packets sent through ppp0 + * Get total number of tx packets sent through rmnet0 or ppp0 * - * @return number of Tx packets through ppp0 + * @return number of Tx packets through rmnet0 or ppp0 */ - - public native static int netStatGetTxPkts(); + public static long getMobileTxPkts() { + return getMobileStat("tx_packets"); + } /** - * Get total number of rx packets received through ppp0 + * Get total number of rx packets received through rmnet0 or ppp0 * - * @return number of Rx packets through ppp0 + * @return number of Rx packets through rmnet0 or ppp0 */ - public native static int netStatGetRxPkts(); + public static long getMobileRxPkts() { + return getMobileStat("rx_packets"); + } /** - * Get total number of tx bytes received through ppp0 + * Get total number of tx bytes received through rmnet0 or ppp0 + * + * @return number of Tx bytes through rmnet0 or ppp0 + */ + public static long getMobileTxBytes() { + return getMobileStat("tx_bytes"); + } + + /** + * Get total number of rx bytes received through rmnet0 or ppp0 + * + * @return number of Rx bytes through rmnet0 or ppp0 + */ + public static long getMobileRxBytes() { + return getMobileStat("rx_bytes"); + } + + /** + * Get the total number of packets sent through all network interfaces. + * + * @return the number of packets sent through all network interfaces + */ + public static long getTotalTxPkts() { + return getTotalStat("tx_packets"); + } + + /** + * Get the total number of packets received through all network interfaces. + * + * @return the number of packets received through all network interfaces + */ + public static long getTotalRxPkts() { + return getTotalStat("rx_packets"); + } + + /** + * Get the total number of bytes sent through all network interfaces. + * + * @return the number of bytes sent through all network interfaces + */ + public static long getTotalTxBytes() { + return getTotalStat("tx_bytes"); + } + + /** + * Get the total number of bytes received through all network interfaces. + * + * @return the number of bytes received through all network interfaces + */ + public static long getTotalRxBytes() { + return getTotalStat("rx_bytes"); + } + + /** + * Gets network bytes sent for this UID. + * The statistics are across all interfaces. + * The statistics come from /proc/uid_stat. * - * @return number of Tx bytes through ppp0 + * {@see android.os.Process#myUid()}. + * + * @param uid + * @return byte count */ - public native static int netStatGetTxBytes(); + public static long getUidTxBytes(int uid) { + return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_snd"); + } /** - * Get total number of rx bytes received through ppp0 + * Gets network bytes received for this UID. + * The statistics are across all interfaces. + * The statistics come from /proc/uid_stat. * - * @return number of Rx bytes through ppp0 + * {@see android.os.Process#myUid()}. + * + * @param uid + * @return byte count */ - public native static int netStatGetRxBytes(); + public static long getUidRxBytes(int uid) { + return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_rcv"); + } + + private static String TAG = "netstat"; + private static final byte[] buf = new byte[16]; + + private static long getTotalStat(String whatStat) { + File netdir = new File("/sys/class/net"); + + File[] nets = netdir.listFiles(); + if (nets == null) { + return 0; + } + long total = 0; + StringBuffer strbuf = new StringBuffer(); + for (File net : nets) { + strbuf.append(net.getPath()).append(File.separator).append("statistics") + .append(File.separator).append(whatStat); + total += getNumberFromFilePath(strbuf.toString()); + strbuf.setLength(0); + } + return total; + } + + private static long getMobileStat(String whatStat) { + String filename = "/sys/class/net/rmnet0/statistics/" + whatStat; + RandomAccessFile raf = getFile(filename); + if (raf == null) { + filename = "/sys/class/net/ppp0/statistics/" + whatStat; + raf = getFile(filename); + } + if (raf == null) { + return 0L; + } + return getNumberFromFile(raf, filename); + } + + // File will have format <number><newline> + private static long getNumberFromFilePath(String filename) { + RandomAccessFile raf = getFile(filename); + if (raf == null) { + return 0L; + } + return getNumberFromFile(raf, filename); + } + + private static synchronized long getNumberFromFile(RandomAccessFile raf, String filename) { + try { + raf.read(buf); + raf.close(); + } catch (IOException e) { + Log.w(TAG, "Exception getting TCP bytes from " + filename, e); + return 0L; + } finally { + if (raf != null) { + try { + raf.close(); + } catch (IOException e) { + Log.w(TAG, "Exception closing " + filename, e); + } + } + } + + long num = 0L; + for (int i = 0; i < buf.length; i++) { + if (buf[i] < '0' || buf[i] > '9') { + break; + } + num *= 10; + num += buf[i] - '0'; + } + return num; + } + + private static RandomAccessFile getFile(String filename) { + File f = new File(filename); + if (!f.canRead()) { + return null; + } + try { + return new RandomAccessFile(f, "r"); + } catch (IOException e) { + Log.w(TAG, "Exception opening TCP statistics file " + filename, e); + return null; + } + } } |