diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index e203fd5902582..a49a27a06368b 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -314,6 +314,15 @@ public abstract class BatteryStats implements Parcelable { * @return foreground cpu time in microseconds */ public abstract long getForegroundTime(int which); + + /** + * Returns the approximate cpu time spent in microseconds, at a certain CPU speed. + * @param speedStep the index of the CPU speed. This is not the actual speed of the + * CPU. + * @param which one of STATS_TOTAL, STATS_LAST, STATS_CURRENT or STATS_UNPLUGGED + * @see BatteryStats#getCpuSpeedSteps() + */ + public abstract long getTimeAtCpuSpeedStep(int speedStep, int which); } /** @@ -573,6 +582,9 @@ public abstract class BatteryStats implements Parcelable { public abstract Map getKernelWakelockStats(); + /** Returns the number of different speeds that the CPU can run at */ + public abstract int getCpuSpeedSteps(); + private final static void formatTimeRaw(StringBuilder out, long seconds) { long days = seconds / (60 * 60 * 24); if (days != 0) { diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java index b337d2803cfd1..a2645949b8a55 100644 --- a/core/java/android/preference/VolumePreference.java +++ b/core/java/android/preference/VolumePreference.java @@ -121,6 +121,9 @@ public class VolumePreference extends SeekBarPreference implements if (mSeekBarVolumizer != null) { Dialog dialog = getDialog(); if (dialog != null && dialog.isShowing()) { + View view = dialog.getWindow().getDecorView() + .findViewById(com.android.internal.R.id.seekbar); + if (view != null) view.setOnKeyListener(null); // Stopped while dialog was showing, revert changes mSeekBarVolumizer.revertVolume(); } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 2da72df59e7fd..35c66ba3bbb7e 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -56,7 +56,9 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 39; + private static final int VERSION = 40; + + private static int sNumSpeedSteps; private final File mFile; private final File mBackupFile; @@ -213,7 +215,7 @@ public final class BatteryStatsImpl extends BatteryStats { /** * State for keeping track of counting information. */ - public static final class Counter extends BatteryStats.Counter implements Unpluggable { + public static class Counter extends BatteryStats.Counter implements Unpluggable { int mCount; int mLoadedCount; int mLastCount; @@ -302,7 +304,22 @@ public final class BatteryStatsImpl extends BatteryStats { mUnpluggedCount = mPluggedCount = mCount; } } - + + public static class SamplingCounter extends Counter { + + SamplingCounter(ArrayList unpluggables, Parcel in) { + super(unpluggables, in); + } + + SamplingCounter(ArrayList unpluggables) { + super(unpluggables); + } + + public void addCountLocked(long count) { + mCount += count; + } + } + /** * State for keeping track of timing information. */ @@ -1940,10 +1957,16 @@ public final class BatteryStatsImpl extends BatteryStats { */ long mUnpluggedForegroundTime; + SamplingCounter[] mSpeedBins; + Proc() { mUnpluggables.add(this); + mSpeedBins = new SamplingCounter[getCpuSpeedSteps()]; + for (int i = 0; i < mSpeedBins.length; i++) { + mSpeedBins[i] = new SamplingCounter(mUnpluggables); + } } - + public void unplug(long batteryUptime, long batteryRealtime) { mUnpluggedUserTime = mUserTime; mUnpluggedSystemTime = mSystemTime; @@ -1974,6 +1997,11 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeLong(mUnpluggedSystemTime); out.writeLong(mUnpluggedForegroundTime); out.writeInt(mUnpluggedStarts); + + out.writeInt(mSpeedBins.length); + for (int i = 0; i < mSpeedBins.length; i++) { + mSpeedBins[i].writeToParcel(out); + } } void readFromParcelLocked(Parcel in) { @@ -1993,6 +2021,12 @@ public final class BatteryStatsImpl extends BatteryStats { mUnpluggedSystemTime = in.readLong(); mUnpluggedForegroundTime = in.readLong(); mUnpluggedStarts = in.readInt(); + + int bins = in.readInt(); + mSpeedBins = new SamplingCounter[bins]; + for (int i = 0; i < bins; i++) { + mSpeedBins[i] = new SamplingCounter(mUnpluggables, in); + } } public BatteryStatsImpl getBatteryStats() { @@ -2075,6 +2109,22 @@ public final class BatteryStatsImpl extends BatteryStats { } return val; } + + /* Called by ActivityManagerService when CPU times are updated. */ + public void addSpeedStepTimes(long[] values) { + for (int i = 0; i < mSpeedBins.length && i < values.length; i++) { + mSpeedBins[i].addCountLocked(values[i]); + } + } + + @Override + public long getTimeAtCpuSpeedStep(int speedStep, int which) { + if (speedStep < mSpeedBins.length) { + return mSpeedBins[speedStep].getCountLocked(which); + } else { + return 0; + } + } } /** @@ -2625,6 +2675,10 @@ public final class BatteryStatsImpl extends BatteryStats { readFromParcel(p); } + public void setNumSpeedSteps(int steps) { + if (sNumSpeedSteps == 0) sNumSpeedSteps = steps; + } + @Override public int getStartCount() { return mStartCount; @@ -2853,6 +2907,11 @@ public final class BatteryStatsImpl extends BatteryStats { return mDischargeCurrentLevel; } + @Override + public int getCpuSpeedSteps() { + return sNumSpeedSteps; + } + /** * Retrieve the statistics object for a particular uid, creating if needed. */ @@ -3063,7 +3122,9 @@ public final class BatteryStatsImpl extends BatteryStats { getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in); } } - + + sNumSpeedSteps = in.readInt(); + final int NU = in.readInt(); for (int iu = 0; iu < NU; iu++) { int uid = in.readInt(); @@ -3206,6 +3267,7 @@ public final class BatteryStatsImpl extends BatteryStats { } } + out.writeInt(sNumSpeedSteps); final int NU = mUidStats.size(); out.writeInt(NU); for (int iu = 0; iu < NU; iu++) { @@ -3404,6 +3466,8 @@ public final class BatteryStatsImpl extends BatteryStats { mFullTimers.clear(); mWindowTimers.clear(); + sNumSpeedSteps = in.readInt(); + int numUids = in.readInt(); mUidStats.clear(); for (int i = 0; i < numUids; i++) { @@ -3484,7 +3548,9 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(0); } } - + + out.writeInt(sNumSpeedSteps); + int size = mUidStats.size(); out.writeInt(size); for (int i = 0; i < size; i++) { diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java index 94f703add4692..4b4b71782552a 100644 --- a/core/java/com/android/internal/os/PowerProfile.java +++ b/core/java/com/android/internal/os/PowerProfile.java @@ -47,14 +47,9 @@ public class PowerProfile { public static final String POWER_CPU_IDLE = "cpu.idle"; /** - * Power consumption when CPU is running at normal speed. + * Power consumption when CPU is in power collapse mode. */ - public static final String POWER_CPU_NORMAL = "cpu.normal"; - - /** - * Power consumption when CPU is running at full speed. - */ - public static final String POWER_CPU_FULL = "cpu.full"; + public static final String POWER_CPU_ACTIVE = "cpu.active"; /** * Power consumption when WiFi driver is scanning for networks. @@ -124,6 +119,8 @@ public class PowerProfile { */ public static final String POWER_VIDEO = "dsp.video"; + public static final String POWER_CPU_SPEEDS = "cpu.speeds"; + static final HashMap sPowerMap = new HashMap(); private static final String TAG_DEVICE = "device"; @@ -214,10 +211,10 @@ public class PowerProfile { } /** - * Returns the average current in mA consumed by the subsystem for the given level. + * Returns the average current in mA consumed by the subsystem for the given level. * @param type the subsystem type * @param level the level of power at which the subsystem is running. For instance, the - * signal strength of the cell network between 0 and 4 (if there are 4 bars max.). + * signal strength of the cell network between 0 and 4 (if there are 4 bars max.) * If there is no data for multiple levels, the level is ignored. * @return the average current in milliAmps. */ @@ -240,4 +237,12 @@ public class PowerProfile { return 0; } } + + public int getNumSpeedSteps() { + Object value = sPowerMap.get(POWER_CPU_SPEEDS); + if (value != null && value instanceof Double[]) { + return ((Double[])value).length; + } + return 1; // Only one speed + } } diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml index 859902e73d9ed..710b71ea7e75c 100644 --- a/core/res/res/xml/power_profile.xml +++ b/core/res/res/xml/power_profile.xml @@ -26,15 +26,24 @@ 0.1 0.1 0.1 - 0.1 - 0.2 - 1 0.1 0.1 1 1 + 1 0.1 + + + 400000 + + + 0.1 + + + 0.2 + diff --git a/services/java/com/android/server/ProcessStats.java b/services/java/com/android/server/ProcessStats.java index af80e20cc0e66..eaab3ebfb86b3 100644 --- a/services/java/com/android/server/ProcessStats.java +++ b/services/java/com/android/server/ProcessStats.java @@ -30,6 +30,7 @@ import java.io.StringWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.StringTokenizer; public class ProcessStats { private static final String TAG = "ProcessStats"; @@ -138,7 +139,22 @@ public class ProcessStats { private boolean mFirst = true; private byte[] mBuffer = new byte[256]; - + + /** + * The time in microseconds that the CPU has been running at each speed. + */ + private long[] mCpuSpeedTimes; + + /** + * The relative time in microseconds that the CPU has been running at each speed. + */ + private long[] mRelCpuSpeedTimes; + + /** + * The different speeds that the CPU can be running at. + */ + private long[] mCpuSpeeds; + public static class Stats { public final int pid; final String statFile; @@ -460,6 +476,67 @@ public class ProcessStats { return 0; } + /** + * Returns the times spent at each CPU speed, since the last call to this method. If this + * is the first time, it will return 1 for each value. + * @return relative times spent at different speed steps. + */ + public long[] getLastCpuSpeedTimes() { + if (mCpuSpeedTimes == null) { + mCpuSpeedTimes = getCpuSpeedTimes(null); + mRelCpuSpeedTimes = new long[mCpuSpeedTimes.length]; + for (int i = 0; i < mCpuSpeedTimes.length; i++) { + mRelCpuSpeedTimes[i] = 1; // Initialize + } + } else { + getCpuSpeedTimes(mRelCpuSpeedTimes); + for (int i = 0; i < mCpuSpeedTimes.length; i++) { + long temp = mRelCpuSpeedTimes[i]; + mRelCpuSpeedTimes[i] -= mCpuSpeedTimes[i]; + mCpuSpeedTimes[i] = temp; + } + } + return mRelCpuSpeedTimes; + } + + private long[] getCpuSpeedTimes(long[] out) { + long[] tempTimes = out; + long[] tempSpeeds = mCpuSpeeds; + final int MAX_SPEEDS = 20; + if (out == null) { + tempTimes = new long[MAX_SPEEDS]; // Hopefully no more than that + tempSpeeds = new long[MAX_SPEEDS]; + } + int speed = 0; + String file = readFile("/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state", '\0'); + StringTokenizer st = new StringTokenizer(file, "\n "); + while (st.hasMoreElements()) { + String token = st.nextToken(); + try { + long val = Long.parseLong(token); + tempSpeeds[speed] = val; + token = st.nextToken(); + val = Long.parseLong(token); + tempTimes[speed] = val; + speed++; + if (speed == MAX_SPEEDS) break; // No more + if (localLOGV && out == null) { + Log.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1] + + "\t" + tempTimes[speed - 1]); + } + } catch (NumberFormatException nfe) { + Log.i(TAG, "Unable to parse time_in_state"); + } + } + if (out == null) { + out = new long[speed]; + mCpuSpeeds = new long[speed]; + System.arraycopy(tempSpeeds, 0, mCpuSpeeds, 0, speed); + System.arraycopy(tempTimes, 0, out, 0, speed); + } + return out; + } + final public int getLastUserTime() { return mRelUserTime; } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index e0cc07ff7a54e..0e877b69a244d 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -1572,6 +1572,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes(); final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics(); synchronized(bstats) { synchronized(mPidsSelfLocked) { @@ -1585,11 +1586,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (pr != null) { BatteryStatsImpl.Uid.Proc ps = pr.batteryStats; ps.addCpuTimeLocked(st.rel_utime, st.rel_stime); + ps.addSpeedStepTimes(cpuSpeedTimes); } else { BatteryStatsImpl.Uid.Proc ps = bstats.getProcessStatsLocked(st.name, st.pid); if (ps != null) { ps.addCpuTimeLocked(st.rel_utime, st.rel_stime); + ps.addSpeedStepTimes(cpuSpeedTimes); } } } diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java index ed0d534587f68..61537f56155f5 100644 --- a/services/java/com/android/server/am/BatteryStatsService.java +++ b/services/java/com/android/server/am/BatteryStatsService.java @@ -28,6 +28,7 @@ import android.util.Log; import com.android.internal.app.IBatteryStats; import com.android.internal.os.BatteryStatsImpl; +import com.android.internal.os.PowerProfile; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -49,6 +50,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub { public void publish(Context context) { mContext = context; ServiceManager.addService("batteryinfo", asBinder()); + mStats.setNumSpeedSteps(new PowerProfile(mContext).getNumSpeedSteps()); } public void shutdown() {