From c64edde69d18498fb2954f71a546357b07ab996a Mon Sep 17 00:00:00 2001 From: Evan Millar <> Date: Sat, 18 Apr 2009 12:26:32 -0700 Subject: [PATCH] AI 146853: Add kernel wakelock data to batteryinfo dump. BUG=1755458 Automated import of CL 146853 --- core/java/android/os/BatteryStats.java | 86 ++- core/java/android/os/Process.java | 6 + .../com/android/internal/os/BatteryStatsImpl.java | 709 +++++++++++++++++---- core/jni/android_util_Process.cpp | 101 +-- 4 files changed, 696 insertions(+), 206 deletions(-) diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 0e9102f88da6..39d36de7e3fe 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -89,7 +89,7 @@ public abstract class BatteryStats implements Parcelable { /** * Bump the version on this if the checkin format changes. */ - private static final int BATTERY_STATS_CHECKIN_VERSION = 4; + private static final int BATTERY_STATS_CHECKIN_VERSION = 5; private static final long BYTES_PER_KB = 1024; private static final long BYTES_PER_MB = 1048576; // 1024^2 @@ -100,6 +100,7 @@ public abstract class BatteryStats implements Parcelable { private static final String PROCESS_DATA = "pr"; private static final String SENSOR_DATA = "sr"; private static final String WAKELOCK_DATA = "wl"; + private static final String KERNEL_WAKELOCK_DATA = "kwl"; private static final String NETWORK_DATA = "nt"; private static final String USER_ACTIVITY_DATA = "ua"; private static final String BATTERY_DATA = "bt"; @@ -126,7 +127,7 @@ public abstract class BatteryStats implements Parcelable { * * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT */ - public abstract int getCount(int which); + public abstract int getCountLocked(int which); /** * Temporary for debugging. @@ -145,7 +146,7 @@ public abstract class BatteryStats implements Parcelable { * * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT */ - public abstract int getCount(int which); + public abstract int getCountLocked(int which); /** * Returns the total time in microseconds associated with this Timer for the @@ -155,7 +156,7 @@ public abstract class BatteryStats implements Parcelable { * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT * @return a time in microseconds */ - public abstract long getTotalTime(long batteryRealtime, int which); + public abstract long getTotalTimeLocked(long batteryRealtime, int which); /** * Temporary for debugging. @@ -518,6 +519,8 @@ public abstract class BatteryStats implements Parcelable { * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. */ public abstract long computeRealtime(long curTime, int which); + + public abstract Map getKernelWakelockStats(); private final static void formatTime(StringBuilder out, long seconds) { long days = seconds / (60 * 60 * 24); @@ -607,14 +610,14 @@ public abstract class BatteryStats implements Parcelable { if (timer != null) { // Convert from microseconds to milliseconds with rounding - long totalTimeMicros = timer.getTotalTime(batteryRealtime, which); + long totalTimeMicros = timer.getTotalTimeLocked(batteryRealtime, which); long totalTimeMillis = (totalTimeMicros + 500) / 1000; - int count = timer.getCount(which); + int count = timer.getCountLocked(which); if (totalTimeMillis != 0) { sb.append(linePrefix); sb.append(formatTimeMs(totalTimeMillis)); - sb.append(name); + sb.append(name != null ? name : ""); sb.append(' '); sb.append('('); sb.append(count); @@ -637,18 +640,17 @@ public abstract class BatteryStats implements Parcelable { * @return the line prefix */ private static final String printWakeLockCheckin(StringBuilder sb, Timer timer, long now, - String name, int which, String linePrefix) { + String name, int which, String linePrefix) { long totalTimeMicros = 0; int count = 0; if (timer != null) { - totalTimeMicros = timer.getTotalTime(now, which); - count = timer.getCount(which); + totalTimeMicros = timer.getTotalTimeLocked(now, which); + count = timer.getCountLocked(which); } sb.append(linePrefix); sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding sb.append(','); - sb.append(name); - sb.append(','); + sb.append(name != null ? name + "," : ""); sb.append(count); return ","; } @@ -730,12 +732,12 @@ public abstract class BatteryStats implements Parcelable { Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL); if (fullWakeTimer != null) { - fullWakeLockTimeTotal += fullWakeTimer.getTotalTime(batteryRealtime, which); + fullWakeLockTimeTotal += fullWakeTimer.getTotalTimeLocked(batteryRealtime, which); } Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL); if (partialWakeTimer != null) { - partialWakeLockTimeTotal += partialWakeTimer.getTotalTime( + partialWakeLockTimeTotal += partialWakeTimer.getTotalTimeLocked( batteryRealtime, which); } } @@ -783,6 +785,17 @@ public abstract class BatteryStats implements Parcelable { getDischargeCurrentLevel()); } + Map kernelWakelocks = getKernelWakelockStats(); + if (kernelWakelocks.size() > 0) { + for (Map.Entry ent : kernelWakelocks.entrySet()) { + sb.setLength(0); + printWakeLockCheckin(sb, ent.getValue(), batteryRealtime, null, which, ""); + + dumpLine(pw, 0 /* uid */, category, KERNEL_WAKELOCK_DATA, ent.getKey(), + sb.toString()); + } + } + for (int iu = 0; iu < NU; iu++) { final int uid = uidStats.keyAt(iu); Uid u = uidStats.valueAt(iu); @@ -821,12 +834,12 @@ public abstract class BatteryStats implements Parcelable { Uid.Wakelock wl = ent.getValue(); String linePrefix = ""; sb.setLength(0); - linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), batteryRealtime, - "f", which, linePrefix); - linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), batteryRealtime, - "p", which, linePrefix); - linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), batteryRealtime, - "w", which, linePrefix); + linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), + batteryRealtime, "f", which, linePrefix); + linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), + batteryRealtime, "p", which, linePrefix); + linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), + batteryRealtime, "w", which, linePrefix); // Only log if we had at lease one wakelock... if (sb.length() > 0) { @@ -844,8 +857,8 @@ public abstract class BatteryStats implements Parcelable { Timer timer = se.getSensorTime(); if (timer != null) { // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000; - int count = timer.getCount(which); + long totalTime = (timer.getTotalTimeLocked(batteryRealtime, which) + 500) / 1000; + int count = timer.getCountLocked(which); if (totalTime != 0) { dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count); } @@ -971,6 +984,26 @@ public abstract class BatteryStats implements Parcelable { long fullWakeLockTimeTotalMicros = 0; long partialWakeLockTimeTotalMicros = 0; + Map kernelWakelocks = getKernelWakelockStats(); + if (kernelWakelocks.size() > 0) { + for (Map.Entry ent : kernelWakelocks.entrySet()) { + + String linePrefix = ": "; + sb.setLength(0); + sb.append(prefix); + sb.append(" Kernel Wake lock "); + sb.append(ent.getKey()); + linePrefix = printWakeLock(sb, ent.getValue(), batteryRealtime, null, which, + linePrefix); + if (!linePrefix.equals(": ")) { + sb.append(" realtime"); + } else { + sb.append(": (nothing executed)"); + } + pw.println(sb.toString()); + } + } + for (int iu = 0; iu < NU; iu++) { Uid u = uidStats.valueAt(iu); rxTotal += u.getTcpBytesReceived(which); @@ -984,13 +1017,13 @@ public abstract class BatteryStats implements Parcelable { Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL); if (fullWakeTimer != null) { - fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTime( + fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTimeLocked( batteryRealtime, which); } Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL); if (partialWakeTimer != null) { - partialWakeLockTimeTotalMicros += partialWakeTimer.getTotalTime( + partialWakeLockTimeTotalMicros += partialWakeTimer.getTotalTimeLocked( batteryRealtime, which); } } @@ -1179,8 +1212,9 @@ public abstract class BatteryStats implements Parcelable { Timer timer = se.getSensorTime(); if (timer != null) { // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000; - int count = timer.getCount(which); + long totalTime = (timer.getTotalTimeLocked( + batteryRealtime, which) + 500) / 1000; + int count = timer.getCountLocked(which); //timer.logState(); if (totalTime != 0) { sb.append(formatTimeMs(totalTime)); diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index cd86fbe70dac..e4412a34f764 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -680,6 +680,8 @@ public class Process { /** @hide */ public static final int PROC_SPACE_TERM = (int)' '; /** @hide */ + public static final int PROC_TAB_TERM = (int)'\t'; + /** @hide */ public static final int PROC_COMBINE = 0x100; /** @hide */ public static final int PROC_PARENS = 0x200; @@ -693,6 +695,10 @@ public class Process { /** @hide */ public static final native boolean readProcFile(String file, int[] format, String[] outStrings, long[] outLongs, float[] outFloats); + + /** @hide */ + public static final native boolean parseProcLine(byte[] buffer, int startIndex, + int endIndex, int[] format, String[] outStrings, long[] outLongs, float[] outFloats); /** * Gets the total Pss value for a given process, in bytes. diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index f492ad1cd5db..58a9be85cddb 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -21,6 +21,7 @@ import android.os.NetStat; import android.os.Parcel; import android.os.ParcelFormatException; import android.os.Parcelable; +import android.os.Process; import android.os.SystemClock; import android.telephony.TelephonyManager; import android.util.Log; @@ -33,7 +34,10 @@ import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; import java.util.Map; +import java.util.Set; /** * All information we are collecting about things that can happen that impact @@ -48,7 +52,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 32; + private static final int VERSION = 34; private final File mFile; private final File mBackupFile; @@ -63,11 +67,11 @@ public final class BatteryStatsImpl extends BatteryStats { // elapsed time by the number of active timers to arrive at that timer's share of the time. // In order to do this, we must refresh each timer whenever the number of active timers // changes. - final ArrayList mPartialTimers = new ArrayList(); - final ArrayList mFullTimers = new ArrayList(); - final ArrayList mWindowTimers = new ArrayList(); - final SparseArray> mSensorTimers - = new SparseArray>(); + final ArrayList mPartialTimers = new ArrayList(); + final ArrayList mFullTimers = new ArrayList(); + final ArrayList mWindowTimers = new ArrayList(); + final SparseArray> mSensorTimers + = new SparseArray>(); // These are the objects that will want to do something when the device // is unplugged from power. @@ -88,31 +92,33 @@ public final class BatteryStatsImpl extends BatteryStats { long mLastRealtime; boolean mScreenOn; - Timer mScreenOnTimer; + StopwatchTimer mScreenOnTimer; int mScreenBrightnessBin = -1; - final Timer[] mScreenBrightnessTimer = new Timer[NUM_SCREEN_BRIGHTNESS_BINS]; + final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS]; Counter mInputEventCounter; boolean mPhoneOn; - Timer mPhoneOnTimer; + StopwatchTimer mPhoneOnTimer; int mPhoneSignalStrengthBin = -1; - final Timer[] mPhoneSignalStrengthsTimer = new Timer[NUM_SIGNAL_STRENGTH_BINS]; + final StopwatchTimer[] mPhoneSignalStrengthsTimer = + new StopwatchTimer[NUM_SIGNAL_STRENGTH_BINS]; int mPhoneDataConnectionType = -1; - final Timer[] mPhoneDataConnectionsTimer = new Timer[NUM_DATA_CONNECTION_TYPES]; + final StopwatchTimer[] mPhoneDataConnectionsTimer = + new StopwatchTimer[NUM_DATA_CONNECTION_TYPES]; boolean mWifiOn; - Timer mWifiOnTimer; + StopwatchTimer mWifiOnTimer; int mWifiOnUid = -1; boolean mWifiRunning; - Timer mWifiRunningTimer; + StopwatchTimer mWifiRunningTimer; boolean mBluetoothOn; - Timer mBluetoothOnTimer; + StopwatchTimer mBluetoothOnTimer; /** * These provide time bases that discount the time the device is plugged @@ -135,6 +141,37 @@ public final class BatteryStatsImpl extends BatteryStats { int mDischargeCurrentLevel; long mLastWriteTime = 0; // Milliseconds + + /* + * Holds a SamplingTimer associated with each kernel wakelock name being tracked. + */ + private final HashMap mKernelWakelockStats = + new HashMap(); + + public Map getKernelWakelockStats() { + return mKernelWakelockStats; + } + + private static int sKernelWakelockUpdateVersion = 0; + + private static final int[] PROC_WAKELOCKS_FORMAT = new int[] { + Process.PROC_TAB_TERM|Process.PROC_OUT_STRING, // 0: name + Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 1: count + Process.PROC_TAB_TERM, + Process.PROC_TAB_TERM, + Process.PROC_TAB_TERM, + Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 5: totalTime + }; + + private final String[] mProcWakelocksName = new String[3]; + private final long[] mProcWakelocksData = new long[3]; + + /* + * Used as a buffer for reading in data from /proc/wakelocks before it is processed and added + * to mKernelWakelockStats. + */ + private final Map mProcWakelockFileStats = + new HashMap(); // For debugging public BatteryStatsImpl() { @@ -200,7 +237,7 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override - public int getCount(int which) { + public int getCountLocked(int which) { int val; if (which == STATS_LAST) { val = mLastCount; @@ -242,11 +279,9 @@ public final class BatteryStatsImpl extends BatteryStats { /** * State for keeping track of timing information. */ - public static final class Timer extends BatteryStats.Timer implements Unpluggable { + public static abstract class Timer extends BatteryStats.Timer implements Unpluggable { final int mType; - final ArrayList mTimerPool; - - int mNesting; + int mCount; int mLoadedCount; @@ -281,24 +316,10 @@ public final class BatteryStatsImpl extends BatteryStats { * power. */ long mUnpluggedTime; - - /** - * The last time at which we updated the timer. If mNesting is > 0, - * subtract this from the current battery time to find the amount of - * time we have been running since we last computed an update. - */ - long mUpdateTime; - - /** - * The total time at which the timer was acquired, to determine if - * was actually held for an interesting duration. - */ - long mAcquireTime; - Timer(int type, ArrayList timerPool, - ArrayList unpluggables, Parcel in) { + Timer(int type, ArrayList unpluggables, Parcel in) { mType = type; - mTimerPool = timerPool; + mCount = in.readInt(); mLoadedCount = in.readInt(); mLastCount = in.readInt(); @@ -306,17 +327,19 @@ public final class BatteryStatsImpl extends BatteryStats { mTotalTime = in.readLong(); mLoadedTime = in.readLong(); mLastTime = in.readLong(); - mUpdateTime = in.readLong(); mUnpluggedTime = in.readLong(); unpluggables.add(this); } - Timer(int type, ArrayList timerPool, - ArrayList unpluggables) { + Timer(int type, ArrayList unpluggables) { mType = type; - mTimerPool = timerPool; unpluggables.add(this); } + + protected abstract long computeRunTimeLocked(long curBatteryRealtime); + + protected abstract int computeCurrentCountLocked(); + public void writeToParcel(Parcel out, long batteryRealtime) { out.writeInt(mCount); @@ -326,7 +349,6 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeLong(computeRunTimeLocked(batteryRealtime)); out.writeLong(mLoadedTime); out.writeLong(mLastTime); - out.writeLong(mUpdateTime); out.writeLong(mUnpluggedTime); } @@ -346,19 +368,15 @@ public final class BatteryStatsImpl extends BatteryStats { } public void plug(long batteryUptime, long batteryRealtime) { - if (mNesting > 0) { - if (DEBUG && mType < 0) { - Log.v(TAG, "plug #" + mType + ": realtime=" + batteryRealtime - + " old mTotalTime=" + mTotalTime - + " old mUpdateTime=" + mUpdateTime); - } - mTotalTime = computeRunTimeLocked(batteryRealtime); - mUpdateTime = batteryRealtime; - if (DEBUG && mType < 0) { - Log.v(TAG, "plug #" + mType - + ": new mTotalTime=" + mTotalTime - + " old mUpdateTime=" + mUpdateTime); - } + if (DEBUG && mType < 0) { + Log.v(TAG, "plug #" + mType + ": realtime=" + batteryRealtime + + " old mTotalTime=" + mTotalTime); + } + mTotalTime = computeRunTimeLocked(batteryRealtime); + mCount = computeCurrentCountLocked(); + if (DEBUG && mType < 0) { + Log.v(TAG, "plug #" + mType + + ": new mTotalTime=" + mTotalTime); } } @@ -380,7 +398,7 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override - public long getTotalTime(long batteryRealtime, int which) { + public long getTotalTimeLocked(long batteryRealtime, int which) { long val; if (which == STATS_LAST) { val = mLastTime; @@ -397,12 +415,12 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override - public int getCount(int which) { + public int getCountLocked(int which) { int val; if (which == STATS_LAST) { val = mLastCount; } else { - val = mCount; + val = computeCurrentCountLocked(); if (which == STATS_UNPLUGGED) { val -= mUnpluggedCount; } else if (which != STATS_TOTAL) { @@ -414,14 +432,239 @@ public final class BatteryStatsImpl extends BatteryStats { } public void logState(Printer pw, String prefix) { - pw.println(prefix + "mNesting=" + mNesting + " mCount=" + mCount + pw.println(prefix + " mCount=" + mCount + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount + " mUnpluggedCount=" + mUnpluggedCount); pw.println(prefix + "mTotalTime=" + mTotalTime + " mLoadedTime=" + mLoadedTime); pw.println(prefix + "mLastTime=" + mLastTime + " mUnpluggedTime=" + mUnpluggedTime); - pw.println(prefix + "mUpdateTime=" + mUpdateTime + } + + + void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) { + long runTime = computeRunTimeLocked(batteryRealtime); + // Divide by 1000 for backwards compatibility + out.writeLong((runTime + 500) / 1000); + out.writeLong(((runTime - mLoadedTime) + 500) / 1000); + out.writeInt(mCount); + out.writeInt(mCount - mLoadedCount); + } + + void readSummaryFromParcelLocked(Parcel in) { + // Multiply by 1000 for backwards compatibility + mTotalTime = mLoadedTime = in.readLong() * 1000; + mLastTime = in.readLong() * 1000; + mUnpluggedTime = mTotalTime; + mCount = mLoadedCount = in.readInt(); + mLastCount = in.readInt(); + mUnpluggedCount = mCount; + } + } + + public static final class SamplingTimer extends Timer { + + /** + * The most recent reported count from /proc/wakelocks. + */ + int mCurrentReportedCount; + + /** + * The reported count from /proc/wakelocks when unplug() was last + * called. + */ + int mUnpluggedReportedCount; + + /** + * The most recent reported total_time from /proc/wakelocks. + */ + long mCurrentReportedTotalTime; + + + /** + * The reported total_time from /proc/wakelocks when unplug() was last + * called. + */ + long mUnpluggedReportedTotalTime; + + /** + * Whether we are currently in a discharge cycle. + */ + boolean mInDischarge; + + /** + * Whether we are currently recording reported values. + */ + boolean mTrackingReportedValues; + + /* + * A sequnce counter, incremented once for each update of the stats. + */ + int mUpdateVersion; + + SamplingTimer(ArrayList unpluggables, boolean inDischarge, Parcel in) { + super(0, unpluggables, in); + mCurrentReportedCount = in.readInt(); + mUnpluggedReportedCount = in.readInt(); + mCurrentReportedTotalTime = in.readLong(); + mUnpluggedReportedTotalTime = in.readLong(); + mTrackingReportedValues = in.readInt() == 1; + mInDischarge = inDischarge; + } + + SamplingTimer(ArrayList unpluggables, boolean inDischarge, + boolean trackReportedValues) { + super(0, unpluggables); + mTrackingReportedValues = trackReportedValues; + mInDischarge = inDischarge; + } + + public void setStale() { + mTrackingReportedValues = false; + mUnpluggedReportedTotalTime = 0; + mUnpluggedReportedCount = 0; + } + + public void setUpdateVersion(int version) { + mUpdateVersion = version; + } + + public int getUpdateVersion() { + return mUpdateVersion; + } + + public void updateCurrentReportedCount(int count) { + if (mInDischarge && mUnpluggedReportedCount == 0) { + // Updating the reported value for the first time. + mUnpluggedReportedCount = count; + // If we are receiving an update update mTrackingReportedValues; + mTrackingReportedValues = true; + } + mCurrentReportedCount = count; + } + + public void updateCurrentReportedTotalTime(long totalTime) { + if (mInDischarge && mUnpluggedReportedTotalTime == 0) { + // Updating the reported value for the first time. + mUnpluggedReportedTotalTime = totalTime; + // If we are receiving an update update mTrackingReportedValues; + mTrackingReportedValues = true; + } + mCurrentReportedTotalTime = totalTime; + } + + public void unplug(long batteryUptime, long batteryRealtime) { + super.unplug(batteryUptime, batteryRealtime); + if (mTrackingReportedValues) { + mUnpluggedReportedTotalTime = mCurrentReportedTotalTime; + mUnpluggedReportedCount = mCurrentReportedCount; + } + mInDischarge = true; + } + + public void plug(long batteryUptime, long batteryRealtime) { + super.plug(batteryUptime, batteryRealtime); + mInDischarge = false; + } + + public void logState(Printer pw, String prefix) { + super.logState(pw, prefix); + pw.println(prefix + "mCurrentReportedCount=" + mCurrentReportedCount + + " mUnpluggedReportedCount=" + mUnpluggedReportedCount + + " mCurrentReportedTotalTime=" + mCurrentReportedTotalTime + + " mUnpluggedReportedTotalTime=" + mUnpluggedReportedTotalTime); + } + + protected long computeRunTimeLocked(long curBatteryRealtime) { + return mTotalTime + (mInDischarge && mTrackingReportedValues + ? mCurrentReportedTotalTime - mUnpluggedReportedTotalTime : 0); + } + + protected int computeCurrentCountLocked() { + return mCount + (mInDischarge && mTrackingReportedValues + ? mCurrentReportedCount - mUnpluggedReportedCount : 0); + } + + public void writeToParcel(Parcel out, long batteryRealtime) { + super.writeToParcel(out, batteryRealtime); + out.writeInt(mCurrentReportedCount); + out.writeInt(mUnpluggedReportedCount); + out.writeLong(mCurrentReportedTotalTime); + out.writeLong(mUnpluggedReportedTotalTime); + out.writeInt(mTrackingReportedValues ? 1 : 0); + } + + void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) { + super.writeSummaryFromParcelLocked(out, batteryRealtime); + out.writeLong(mCurrentReportedTotalTime); + out.writeInt(mCurrentReportedCount); + out.writeInt(mTrackingReportedValues ? 1 : 0); + } + + void readSummaryFromParcelLocked(Parcel in) { + super.readSummaryFromParcelLocked(in); + mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = in.readLong(); + mUnpluggedReportedCount = mCurrentReportedCount = in.readInt(); + mTrackingReportedValues = in.readInt() == 1; + } + } + + /** + * State for keeping track of timing information. + */ + public static final class StopwatchTimer extends Timer { + final ArrayList mTimerPool; + int mNesting; + + + /** + * The last time at which we updated the timer. If mNesting is > 0, + * subtract this from the current battery time to find the amount of + * time we have been running since we last computed an update. + */ + long mUpdateTime; + + /** + * The total time at which the timer was acquired, to determine if + * was actually held for an interesting duration. + */ + long mAcquireTime; + + + StopwatchTimer(int type, ArrayList timerPool, + ArrayList unpluggables, Parcel in) { + super(type, unpluggables, in); + mTimerPool = timerPool; + mUpdateTime = in.readLong(); + } + + StopwatchTimer(int type, ArrayList timerPool, + ArrayList unpluggables) { + super(type, unpluggables); + mTimerPool = timerPool; + } + + public void writeToParcel(Parcel out, long batteryRealtime) { + super.writeToParcel(out, batteryRealtime); + out.writeLong(mUpdateTime); + } + + public void plug(long batteryUptime, long batteryRealtime) { + if (mNesting > 0) { + if (DEBUG && mType < 0) { + Log.v(TAG, "old mUpdateTime=" + mUpdateTime); + } + super.plug(batteryUptime, batteryRealtime); + mUpdateTime = batteryRealtime; + if (DEBUG && mType < 0) { + Log.v(TAG, "new mUpdateTime=" + mUpdateTime); + } + } + } + + public void logState(Printer pw, String prefix) { + super.logState(pw, prefix); + pw.println(prefix + "mNesting=" + mNesting + "mUpdateTime=" + mUpdateTime + " mAcquireTime=" + mAcquireTime); } @@ -484,12 +727,12 @@ public final class BatteryStatsImpl extends BatteryStats { // Update the total time for all other running Timers with the same type as this Timer // due to a change in timer count private static void refreshTimersLocked(final BatteryStatsImpl stats, - final ArrayList pool) { + final ArrayList pool) { final long realtime = SystemClock.elapsedRealtime() * 1000; final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime); final int N = pool.size(); for (int i=N-1; i>= 0; i--) { - final Timer t = pool.get(i); + final StopwatchTimer t = pool.get(i); long heldTime = batteryRealtime - t.mUpdateTime; if (heldTime > 0) { t.mTotalTime += heldTime / N; @@ -498,34 +741,146 @@ public final class BatteryStatsImpl extends BatteryStats { } } - private long computeRunTimeLocked(long curBatteryRealtime) { + @Override + protected long computeRunTimeLocked(long curBatteryRealtime) { return mTotalTime + (mNesting > 0 ? (curBatteryRealtime - mUpdateTime) / (mTimerPool != null ? mTimerPool.size() : 1) : 0); } - void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) { - long runTime = computeRunTimeLocked(batteryRealtime); - // Divide by 1000 for backwards compatibility - out.writeLong((runTime + 500) / 1000); - out.writeLong(((runTime - mLoadedTime) + 500) / 1000); - out.writeInt(mCount); - out.writeInt(mCount - mLoadedCount); + @Override + protected int computeCurrentCountLocked() { + return mCount; } void readSummaryFromParcelLocked(Parcel in) { - // Multiply by 1000 for backwards compatibility - mTotalTime = mLoadedTime = in.readLong() * 1000; - mLastTime = in.readLong() * 1000; - mUnpluggedTime = mTotalTime; - mCount = mLoadedCount = in.readInt(); - mLastCount = in.readInt(); - mUnpluggedCount = mCount; + super.readSummaryFromParcelLocked(in); mNesting = 0; } } + private final Map readKernelWakelockStats() { + + byte[] buffer = new byte[4096]; + int len; + + try { + FileInputStream is = new FileInputStream("/proc/wakelocks"); + len = is.read(buffer); + is.close(); + + if (len > 0) { + int i; + for (i=0; i parseProcWakelocks( + byte[] wlBuffer, int len) { + String name; + int count; + long totalTime; + int startIndex, endIndex; + int numUpdatedWlNames = 0; + + // Advance past the first line. + int i; + for (i = 0; i < len && wlBuffer[i] != '\n' && wlBuffer[i] != '\0'; i++); + startIndex = endIndex = i + 1; + + synchronized(this) { + Map m = mProcWakelockFileStats; + + sKernelWakelockUpdateVersion++; + while (endIndex < len) { + for (endIndex=startIndex; + endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0'; + endIndex++); + endIndex++; // endIndex is an exclusive upper bound. + + String[] nameStringArray = mProcWakelocksName; + long[] wlData = mProcWakelocksData; + Process.parseProcLine(wlBuffer, startIndex, endIndex, PROC_WAKELOCKS_FORMAT, + nameStringArray, wlData, null); + + name = nameStringArray[0]; + count = (int) wlData[1]; + // convert nanoseconds to microseconds with rounding. + totalTime = (wlData[2] + 500) / 1000; + + if (name.length() > 0) { + if (!m.containsKey(name)) { + m.put(name, new KernelWakelockStats(count, totalTime, + sKernelWakelockUpdateVersion)); + numUpdatedWlNames++; + } else { + KernelWakelockStats kwlStats = m.get(name); + if (kwlStats.mVersion == sKernelWakelockUpdateVersion) { + kwlStats.mCount += count; + kwlStats.mTotalTime += totalTime; + } else { + kwlStats.mCount = count; + kwlStats.mTotalTime = totalTime; + kwlStats.mVersion = sKernelWakelockUpdateVersion; + numUpdatedWlNames++; + } + } + } + startIndex = endIndex; + } + + if (m.size() != numUpdatedWlNames) { + // Don't report old data. + Iterator itr = m.values().iterator(); + while (itr.hasNext()) { + if (itr.next().mVersion != sKernelWakelockUpdateVersion) { + itr.remove(); + } + } + } + return m; + } + } + + private class KernelWakelockStats { + public int mCount; + public long mTotalTime; + public int mVersion; + + KernelWakelockStats(int count, long totalTime, int version) { + mCount = count; + mTotalTime = totalTime; + mVersion = version; + } + } + + /* + * Get the KernelWakelockTimer associated with name, and create a new one if one + * doesn't already exist. + */ + public SamplingTimer getKernelWakelockTimerLocked(String name) { + SamplingTimer kwlt = mKernelWakelockStats.get(name); + if (kwlt == null) { + kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal, + true /* track reported values */); + mKernelWakelockStats.put(name, kwlt); + } + return kwlt; + } + public void doUnplug(long batteryUptime, long batteryRealtime) { for (int iu = mUidStats.size() - 1; iu >= 0; iu--) { Uid u = mUidStats.valueAt(iu); @@ -760,53 +1115,53 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override public long getScreenOnTime(long batteryRealtime, int which) { - return mScreenOnTimer.getTotalTime(batteryRealtime, which); + return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which); } @Override public long getScreenBrightnessTime(int brightnessBin, long batteryRealtime, int which) { - return mScreenBrightnessTimer[brightnessBin].getTotalTime( + return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked( batteryRealtime, which); } @Override public int getInputEventCount(int which) { - return mInputEventCounter.getCount(which); + return mInputEventCounter.getCountLocked(which); } @Override public long getPhoneOnTime(long batteryRealtime, int which) { - return mPhoneOnTimer.getTotalTime(batteryRealtime, which); + return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which); } @Override public long getPhoneSignalStrengthTime(int strengthBin, long batteryRealtime, int which) { - return mPhoneSignalStrengthsTimer[strengthBin].getTotalTime( + return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked( batteryRealtime, which); } @Override public int getPhoneSignalStrengthCount(int dataType, int which) { - return mPhoneDataConnectionsTimer[dataType].getCount(which); + return mPhoneDataConnectionsTimer[dataType].getCountLocked(which); } @Override public long getPhoneDataConnectionTime(int dataType, long batteryRealtime, int which) { - return mPhoneDataConnectionsTimer[dataType].getTotalTime( + return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked( batteryRealtime, which); } @Override public int getPhoneDataConnectionCount(int dataType, int which) { - return mPhoneDataConnectionsTimer[dataType].getCount(which); + return mPhoneDataConnectionsTimer[dataType].getCountLocked(which); } @Override public long getWifiOnTime(long batteryRealtime, int which) { - return mWifiOnTimer.getTotalTime(batteryRealtime, which); + return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which); } @Override public long getWifiRunningTime(long batteryRealtime, int which) { - return mWifiRunningTimer.getTotalTime(batteryRealtime, which); + return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which); } @Override public long getBluetoothOnTime(long batteryRealtime, int which) { - return mBluetoothOnTimer.getTotalTime(batteryRealtime, which); + return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which); } @Override public boolean getIsOnBattery() { @@ -836,13 +1191,13 @@ public final class BatteryStatsImpl extends BatteryStats { long mStartedTcpBytesSent = -1; boolean mWifiTurnedOn; - Timer mWifiTurnedOnTimer; + StopwatchTimer mWifiTurnedOnTimer; boolean mFullWifiLockOut; - Timer mFullWifiLockTimer; + StopwatchTimer mFullWifiLockTimer; boolean mScanWifiLockOut; - Timer mScanWifiLockTimer; + StopwatchTimer mScanWifiLockTimer; Counter[] mUserActivityCounters; @@ -868,9 +1223,9 @@ public final class BatteryStatsImpl extends BatteryStats { public Uid(int uid) { mUid = uid; - mWifiTurnedOnTimer = new Timer(WIFI_TURNED_ON, null, mUnpluggables); - mFullWifiLockTimer = new Timer(FULL_WIFI_LOCK, null, mUnpluggables); - mScanWifiLockTimer = new Timer(SCAN_WIFI_LOCK, null, mUnpluggables); + mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables); + mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables); + mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables); } @Override @@ -980,17 +1335,17 @@ public final class BatteryStatsImpl extends BatteryStats { @Override public long getWifiTurnedOnTime(long batteryRealtime, int which) { - return mWifiTurnedOnTimer.getTotalTime(batteryRealtime, which); + return mWifiTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which); } @Override public long getFullWifiLockTime(long batteryRealtime, int which) { - return mFullWifiLockTimer.getTotalTime(batteryRealtime, which); + return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which); } @Override public long getScanWifiLockTime(long batteryRealtime, int which) { - return mScanWifiLockTimer.getTotalTime(batteryRealtime, which); + return mScanWifiLockTimer.getTotalTimeLocked(batteryRealtime, which); } @Override @@ -1013,7 +1368,7 @@ public final class BatteryStatsImpl extends BatteryStats { if (mUserActivityCounters == null) { return 0; } - return mUserActivityCounters[type].getCount(which); + return mUserActivityCounters[type].getCountLocked(which); } void initUserActivityLocked() { @@ -1120,11 +1475,11 @@ public final class BatteryStatsImpl extends BatteryStats { mTcpBytesReceivedAtLastUnplug = in.readLong(); mTcpBytesSentAtLastUnplug = in.readLong(); mWifiTurnedOn = false; - mWifiTurnedOnTimer = new Timer(WIFI_TURNED_ON, null, mUnpluggables, in); + mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables, in); mFullWifiLockOut = false; - mFullWifiLockTimer = new Timer(FULL_WIFI_LOCK, null, mUnpluggables, in); + mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables, in); mScanWifiLockOut = false; - mScanWifiLockTimer = new Timer(SCAN_WIFI_LOCK, null, mUnpluggables, in); + mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables, in); if (in.readInt() == 0) { mUserActivityCounters = null; } else { @@ -1142,17 +1497,17 @@ public final class BatteryStatsImpl extends BatteryStats { /** * How long (in ms) this uid has been keeping the device partially awake. */ - Timer mTimerPartial; + StopwatchTimer mTimerPartial; /** * How long (in ms) this uid has been keeping the device fully awake. */ - Timer mTimerFull; + StopwatchTimer mTimerFull; /** * How long (in ms) this uid has had a window keeping the device awake. */ - Timer mTimerWindow; + StopwatchTimer mTimerWindow; /** * Reads a possibly null Timer from a Parcel. The timer is associated with the @@ -1161,13 +1516,13 @@ public final class BatteryStatsImpl extends BatteryStats { * @param in the Parcel to be read from. * return a new Timer, or null. */ - private Timer readTimerFromParcel(int type, ArrayList pool, + private StopwatchTimer readTimerFromParcel(int type, ArrayList pool, ArrayList unpluggables, Parcel in) { if (in.readInt() == 0) { return null; } - return new Timer(type, pool, unpluggables, in); + return new StopwatchTimer(type, pool, unpluggables, in); } void readFromParcelLocked(ArrayList unpluggables, Parcel in) { @@ -1198,24 +1553,24 @@ public final class BatteryStatsImpl extends BatteryStats { public final class Sensor extends BatteryStats.Uid.Sensor { final int mHandle; - Timer mTimer; + StopwatchTimer mTimer; public Sensor(int handle) { mHandle = handle; } - private Timer readTimerFromParcel(ArrayList unpluggables, + private StopwatchTimer readTimerFromParcel(ArrayList unpluggables, Parcel in) { if (in.readInt() == 0) { return null; } - ArrayList pool = mSensorTimers.get(mHandle); + ArrayList pool = mSensorTimers.get(mHandle); if (pool == null) { - pool = new ArrayList(); + pool = new ArrayList(); mSensorTimers.put(mHandle, pool); } - return new Timer(0, pool, unpluggables, in); + return new StopwatchTimer(0, pool, unpluggables, in); } void readFromParcelLocked(ArrayList unpluggables, Parcel in) { @@ -1816,32 +2171,32 @@ public final class BatteryStatsImpl extends BatteryStats { return ss; } - public Timer getWakeTimerLocked(String name, int type) { + public StopwatchTimer getWakeTimerLocked(String name, int type) { Wakelock wl = mWakelockStats.get(name); if (wl == null) { wl = new Wakelock(); mWakelockStats.put(name, wl); } - Timer t = null; + StopwatchTimer t = null; switch (type) { case WAKE_TYPE_PARTIAL: t = wl.mTimerPartial; if (t == null) { - t = new Timer(WAKE_TYPE_PARTIAL, mPartialTimers, mUnpluggables); + t = new StopwatchTimer(WAKE_TYPE_PARTIAL, mPartialTimers, mUnpluggables); wl.mTimerPartial = t; } return t; case WAKE_TYPE_FULL: t = wl.mTimerFull; if (t == null) { - t = new Timer(WAKE_TYPE_FULL, mFullTimers, mUnpluggables); + t = new StopwatchTimer(WAKE_TYPE_FULL, mFullTimers, mUnpluggables); wl.mTimerFull = t; } return t; case WAKE_TYPE_WINDOW: t = wl.mTimerWindow; if (t == null) { - t = new Timer(WAKE_TYPE_WINDOW, mWindowTimers, mUnpluggables); + t = new StopwatchTimer(WAKE_TYPE_WINDOW, mWindowTimers, mUnpluggables); wl.mTimerWindow = t; } return t; @@ -1850,7 +2205,7 @@ public final class BatteryStatsImpl extends BatteryStats { } } - public Timer getSensorTimerLocked(int sensor, boolean create) { + public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) { Sensor se = mSensorStats.get(sensor); if (se == null) { if (!create) { @@ -1859,36 +2214,36 @@ public final class BatteryStatsImpl extends BatteryStats { se = new Sensor(sensor); mSensorStats.put(sensor, se); } - Timer t = se.mTimer; + StopwatchTimer t = se.mTimer; if (t != null) { return t; } - ArrayList timers = mSensorTimers.get(sensor); + ArrayList timers = mSensorTimers.get(sensor); if (timers == null) { - timers = new ArrayList(); + timers = new ArrayList(); mSensorTimers.put(sensor, timers); } - t = new Timer(BatteryStats.SENSOR, timers, mUnpluggables); + t = new StopwatchTimer(BatteryStats.SENSOR, timers, mUnpluggables); se.mTimer = t; return t; } public void noteStartWakeLocked(String name, int type) { - Timer t = getWakeTimerLocked(name, type); + StopwatchTimer t = getWakeTimerLocked(name, type); if (t != null) { t.startRunningLocked(BatteryStatsImpl.this); } } public void noteStopWakeLocked(String name, int type) { - Timer t = getWakeTimerLocked(name, type); + StopwatchTimer t = getWakeTimerLocked(name, type); if (t != null) { t.stopRunningLocked(BatteryStatsImpl.this); } } public void noteStartSensor(int sensor) { - Timer t = getSensorTimerLocked(sensor, true); + StopwatchTimer t = getSensorTimerLocked(sensor, true); if (t != null) { t.startRunningLocked(BatteryStatsImpl.this); } @@ -1896,21 +2251,21 @@ public final class BatteryStatsImpl extends BatteryStats { public void noteStopSensor(int sensor) { // Don't create a timer if one doesn't already exist - Timer t = getSensorTimerLocked(sensor, false); + StopwatchTimer t = getSensorTimerLocked(sensor, false); if (t != null) { t.stopRunningLocked(BatteryStatsImpl.this); } } public void noteStartGps() { - Timer t = getSensorTimerLocked(Sensor.GPS, true); + StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true); if (t != null) { t.startRunningLocked(BatteryStatsImpl.this); } } public void noteStopGps() { - Timer t = getSensorTimerLocked(Sensor.GPS, false); + StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false); if (t != null) { t.stopRunningLocked(BatteryStatsImpl.this); } @@ -1925,21 +2280,21 @@ public final class BatteryStatsImpl extends BatteryStats { mFile = new File(filename); mBackupFile = new File(filename + ".bak"); mStartCount++; - mScreenOnTimer = new Timer(-1, null, mUnpluggables); + mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables); for (int i=0; i m = readKernelWakelockStats(); + + for (Map.Entry ent : m.entrySet()) { + String name = ent.getKey(); + KernelWakelockStats kws = ent.getValue(); + + SamplingTimer kwlt = mKernelWakelockStats.get(name); + if (kwlt == null) { + kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal, + true /* track reported values */); + mKernelWakelockStats.put(name, kwlt); + } + kwlt.updateCurrentReportedCount(kws.mCount); + kwlt.updateCurrentReportedTotalTime(kws.mTotalTime); + kwlt.setUpdateVersion(sKernelWakelockUpdateVersion); + } + + if (m.size() != mKernelWakelockStats.size()) { + // Set timers to stale if they didn't appear in /proc/wakelocks this time. + for (Map.Entry ent : mKernelWakelockStats.entrySet()) { + SamplingTimer st = ent.getValue(); + if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) { + st.setStale(); + } + } + } + } public long getAwakeTimeBattery() { return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT); @@ -2296,6 +2681,14 @@ public final class BatteryStatsImpl extends BatteryStats { mBluetoothOn = false; mBluetoothOnTimer.readSummaryFromParcelLocked(in); + int NKW = in.readInt(); + for (int ikw = 0; ikw < NKW; ikw++) { + if (in.readInt() != 0) { + String kwltName = in.readString(); + getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in); + } + } + final int NU = in.readInt(); for (int iu = 0; iu < NU; iu++) { int uid = in.readInt(); @@ -2420,6 +2813,18 @@ public final class BatteryStatsImpl extends BatteryStats { mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL); mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL); + out.writeInt(mKernelWakelockStats.size()); + for (Map.Entry ent : mKernelWakelockStats.entrySet()) { + Timer kwlt = ent.getValue(); + if (kwlt != null) { + out.writeInt(1); + out.writeString(ent.getKey()); + ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL); + } else { + out.writeInt(0); + } + } + final int NU = mUidStats.size(); out.writeInt(NU); for (int iu = 0; iu < NU; iu++) { @@ -2548,25 +2953,25 @@ public final class BatteryStatsImpl extends BatteryStats { mBatteryRealtime = in.readLong(); mBatteryLastRealtime = in.readLong(); mScreenOn = false; - mScreenOnTimer = new Timer(-1, null, mUnpluggables, in); + mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables, in); for (int i=0; i ent : mKernelWakelockStats.entrySet()) { + SamplingTimer kwlt = ent.getValue(); + if (kwlt != null) { + out.writeInt(1); + out.writeString(ent.getKey()); + Timer.writeTimerToParcel(out, kwlt, batteryRealtime); + } else { + out.writeInt(0); + } + } + int size = mUidStats.size(); out.writeInt(size); for (int i = 0; i < size; i++) { diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 3feccde03c31..bd5660550d41 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -516,39 +516,10 @@ enum { PROC_OUT_FLOAT = 0x4000, }; -jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, - jstring file, jintArray format, jobjectArray outStrings, - jlongArray outLongs, jfloatArray outFloats) +jboolean android_os_Process_parseProcLineArray(JNIEnv* env, jobject clazz, + char* buffer, jint startIndex, jint endIndex, jintArray format, + jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats) { - if (file == NULL || format == NULL) { - jniThrowException(env, "java/lang/NullPointerException", NULL); - return JNI_FALSE; - } - - const char* file8 = env->GetStringUTFChars(file, NULL); - if (file8 == NULL) { - jniThrowException(env, "java/lang/OutOfMemoryError", NULL); - return JNI_FALSE; - } - int fd = open(file8, O_RDONLY); - env->ReleaseStringUTFChars(file, file8); - - if (fd < 0) { - //LOGW("Unable to open process file: %s\n", file8); - return JNI_FALSE; - } - - char buffer[256]; - const int len = read(fd, buffer, sizeof(buffer)-1); - close(fd); - - if (len < 0) { - //LOGW("Unable to open process file: %s fd=%d\n", file8, fd); - return JNI_FALSE; - } - buffer[len] = 0; - - //LOGI("Process file %s: %s\n", file8, buffer); const jsize NF = env->GetArrayLength(format); const jsize NS = outStrings ? env->GetArrayLength(outStrings) : 0; @@ -575,7 +546,7 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, return JNI_FALSE; } - jsize i = 0; + jsize i = startIndex; jsize di = 0; jboolean res = JNI_TRUE; @@ -587,30 +558,30 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, } const char term = (char)(mode&PROC_TERM_MASK); const jsize start = i; - if (i >= len) { + if (i >= endIndex) { res = JNI_FALSE; break; } jsize end = -1; if ((mode&PROC_PARENS) != 0) { - while (buffer[i] != ')' && i < len) { + while (buffer[i] != ')' && i < endIndex) { i++; } end = i; i++; } - while (buffer[i] != term && i < len) { + while (buffer[i] != term && i < endIndex) { i++; } if (end < 0) { end = i; } - if (i < len) { + if (i < endIndex) { i++; if ((mode&PROC_COMBINE) != 0) { - while (buffer[i] == term && i < len) { + while (buffer[i] == term && i < endIndex) { i++; } } @@ -649,6 +620,58 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, return res; } +jboolean android_os_Process_parseProcLine(JNIEnv* env, jobject clazz, + jbyteArray buffer, jint startIndex, jint endIndex, jintArray format, + jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats) +{ + jbyte* bufferArray = env->GetByteArrayElements(buffer, NULL); + + jboolean result = android_os_Process_parseProcLineArray(env, clazz, + (char*) bufferArray, startIndex, endIndex, format, outStrings, + outLongs, outFloats); + + env->ReleaseByteArrayElements(buffer, bufferArray, 0); + + return result; +} + +jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, + jstring file, jintArray format, jobjectArray outStrings, + jlongArray outLongs, jfloatArray outFloats) +{ + if (file == NULL || format == NULL) { + jniThrowException(env, "java/lang/NullPointerException", NULL); + return JNI_FALSE; + } + + const char* file8 = env->GetStringUTFChars(file, NULL); + if (file8 == NULL) { + jniThrowException(env, "java/lang/OutOfMemoryError", NULL); + return JNI_FALSE; + } + int fd = open(file8, O_RDONLY); + env->ReleaseStringUTFChars(file, file8); + + if (fd < 0) { + //LOGW("Unable to open process file: %s\n", file8); + return JNI_FALSE; + } + + char buffer[256]; + const int len = read(fd, buffer, sizeof(buffer)-1); + close(fd); + + if (len < 0) { + //LOGW("Unable to open process file: %s fd=%d\n", file8, fd); + return JNI_FALSE; + } + buffer[len] = 0; + + return android_os_Process_parseProcLineArray(env, clazz, buffer, 0, len, + format, outStrings, outLongs, outFloats); + +} + void android_os_Process_setApplicationObject(JNIEnv* env, jobject clazz, jobject binderObject) { @@ -728,6 +751,7 @@ static const JNINativeMethod methods[] = { {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines}, {"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids}, {"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile}, + {"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_parseProcLine}, {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime}, {"getPss", "(I)J", (void*)android_os_Process_getPss}, //{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject}, @@ -746,4 +770,3 @@ int register_android_os_Process(JNIEnv* env) env, kProcessPathName, methods, NELEM(methods)); } - -- 2.11.0