diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index cd45cfb326ac3..4dadda2d7a6e0 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -592,6 +592,86 @@ public abstract class BatteryStats implements Parcelable { } } + /** + * Optional detailed information that can go into a history step. This is typically + * generated each time the battery level changes. + */ + public final static class HistoryStepDetails { + // Time (in 1/100 second) spent in user space and the kernel since the last step. + public int userTime; + public int systemTime; + + // Top three apps using CPU in the last step, with times in 1/100 second. + public int appCpuUid1; + public int appCpuUTime1; + public int appCpuSTime1; + public int appCpuUid2; + public int appCpuUTime2; + public int appCpuSTime2; + public int appCpuUid3; + public int appCpuUTime3; + public int appCpuSTime3; + + // Information from /proc/stat + public int statUserTime; + public int statSystemTime; + public int statIOWaitTime; + public int statIrqTime; + public int statSoftIrqTime; + public int statIdlTime; + + public HistoryStepDetails() { + clear(); + } + + public void clear() { + userTime = systemTime = 0; + appCpuUid1 = appCpuUid2 = appCpuUid3 = -1; + appCpuUTime1 = appCpuSTime1 = appCpuUTime2 = appCpuSTime2 + = appCpuUTime3 = appCpuSTime3 = 0; + } + + public void writeToParcel(Parcel out) { + out.writeInt(userTime); + out.writeInt(systemTime); + out.writeInt(appCpuUid1); + out.writeInt(appCpuUTime1); + out.writeInt(appCpuSTime1); + out.writeInt(appCpuUid2); + out.writeInt(appCpuUTime2); + out.writeInt(appCpuSTime2); + out.writeInt(appCpuUid3); + out.writeInt(appCpuUTime3); + out.writeInt(appCpuSTime3); + out.writeInt(statUserTime); + out.writeInt(statSystemTime); + out.writeInt(statIOWaitTime); + out.writeInt(statIrqTime); + out.writeInt(statSoftIrqTime); + out.writeInt(statIdlTime); + } + + public void readFromParcel(Parcel in) { + userTime = in.readInt(); + systemTime = in.readInt(); + appCpuUid1 = in.readInt(); + appCpuUTime1 = in.readInt(); + appCpuSTime1 = in.readInt(); + appCpuUid2 = in.readInt(); + appCpuUTime2 = in.readInt(); + appCpuSTime2 = in.readInt(); + appCpuUid3 = in.readInt(); + appCpuUTime3 = in.readInt(); + appCpuSTime3 = in.readInt(); + statUserTime = in.readInt(); + statSystemTime = in.readInt(); + statIOWaitTime = in.readInt(); + statIrqTime = in.readInt(); + statSoftIrqTime = in.readInt(); + statIdlTime = in.readInt(); + } + } + public final static class HistoryItem implements Parcelable { public HistoryItem next; @@ -687,6 +767,9 @@ public abstract class BatteryStats implements Parcelable { // Kernel wakeup reason at this point. public HistoryTag wakeReasonTag; + // Non-null when there is more detailed information at this step. + public HistoryStepDetails stepDetails; + public static final int EVENT_FLAG_START = 0x8000; public static final int EVENT_FLAG_FINISH = 0x4000; @@ -3692,10 +3775,115 @@ public abstract class BatteryStats implements Parcelable { } } pw.println(); + if (rec.stepDetails != null) { + if (!checkin) { + pw.print(" Details: cpu="); + pw.print(rec.stepDetails.userTime); + pw.print("u+"); + pw.print(rec.stepDetails.systemTime); + pw.print("s"); + if (rec.stepDetails.appCpuUid1 >= 0) { + pw.print(" ("); + printStepCpuUidDetails(pw, rec.stepDetails.appCpuUid1, + rec.stepDetails.appCpuUTime1, rec.stepDetails.appCpuSTime1); + if (rec.stepDetails.appCpuUid2 >= 0) { + pw.print(", "); + printStepCpuUidDetails(pw, rec.stepDetails.appCpuUid2, + rec.stepDetails.appCpuUTime2, rec.stepDetails.appCpuSTime2); + } + if (rec.stepDetails.appCpuUid3 >= 0) { + pw.print(", "); + printStepCpuUidDetails(pw, rec.stepDetails.appCpuUid3, + rec.stepDetails.appCpuUTime3, rec.stepDetails.appCpuSTime3); + } + pw.print(')'); + } + pw.println(); + pw.print(" /proc/stat="); + pw.print(rec.stepDetails.statUserTime); + pw.print(" usr, "); + pw.print(rec.stepDetails.statSystemTime); + pw.print(" sys, "); + pw.print(rec.stepDetails.statIOWaitTime); + pw.print(" io, "); + pw.print(rec.stepDetails.statIrqTime); + pw.print(" irq, "); + pw.print(rec.stepDetails.statSoftIrqTime); + pw.print(" sirq, "); + pw.print(rec.stepDetails.statIdlTime); + pw.print(" idle"); + int totalRun = rec.stepDetails.statUserTime + rec.stepDetails.statSystemTime + + rec.stepDetails.statIOWaitTime + rec.stepDetails.statIrqTime + + rec.stepDetails.statSoftIrqTime; + int total = totalRun + rec.stepDetails.statIdlTime; + if (total > 0) { + pw.print(" ("); + float perc = ((float)totalRun) / ((float)total) * 100; + pw.print(String.format("%.1f%%", perc)); + pw.print(" of "); + StringBuilder sb = new StringBuilder(64); + formatTimeMsNoSpace(sb, total*10); + pw.print(sb); + pw.print(")"); + } + pw.println(); + } else { + pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); + pw.print(HISTORY_DATA); pw.print(",0,Dcpu="); + pw.print(rec.stepDetails.userTime); + pw.print(":"); + pw.print(rec.stepDetails.systemTime); + if (rec.stepDetails.appCpuUid1 >= 0) { + printStepCpuUidCheckinDetails(pw, rec.stepDetails.appCpuUid1, + rec.stepDetails.appCpuUTime1, rec.stepDetails.appCpuSTime1); + if (rec.stepDetails.appCpuUid2 >= 0) { + printStepCpuUidCheckinDetails(pw, rec.stepDetails.appCpuUid2, + rec.stepDetails.appCpuUTime2, rec.stepDetails.appCpuSTime2); + } + if (rec.stepDetails.appCpuUid3 >= 0) { + printStepCpuUidCheckinDetails(pw, rec.stepDetails.appCpuUid3, + rec.stepDetails.appCpuUTime3, rec.stepDetails.appCpuSTime3); + } + } + pw.println(); + pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); + pw.print(HISTORY_DATA); pw.print(",0,Dpst="); + pw.print(rec.stepDetails.statUserTime); + pw.print(','); + pw.print(rec.stepDetails.statSystemTime); + pw.print(','); + pw.print(rec.stepDetails.statIOWaitTime); + pw.print(','); + pw.print(rec.stepDetails.statIrqTime); + pw.print(','); + pw.print(rec.stepDetails.statSoftIrqTime); + pw.print(','); + pw.print(rec.stepDetails.statIdlTime); + pw.println(); + } + } oldState = rec.states; oldState2 = rec.states2; } } + + private void printStepCpuUidDetails(PrintWriter pw, int uid, int utime, int stime) { + UserHandle.formatUid(pw, uid); + pw.print("="); + pw.print(utime); + pw.print("u+"); + pw.print(stime); + pw.print("s"); + } + + private void printStepCpuUidCheckinDetails(PrintWriter pw, int uid, int utime, int stime) { + pw.print('/'); + pw.print(uid); + pw.print(":"); + pw.print(utime); + pw.print(":"); + pw.print(stime); + } } private void printSizeValue(PrintWriter pw, long size) { diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 20bb95eeff4c6..d0c7f8c6ebc8b 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -94,7 +94,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 116 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 118 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -208,7 +208,7 @@ public final class BatteryStatsImpl extends BatteryStats { final HistoryItem mHistoryLastLastWritten = new HistoryItem(); final HistoryItem mHistoryReadTmp = new HistoryItem(); final HistoryItem mHistoryAddTmp = new HistoryItem(); - final HashMap mHistoryTagPool = new HashMap(); + final HashMap mHistoryTagPool = new HashMap(); String[] mReadHistoryStrings; int[] mReadHistoryUids; int mReadHistoryChars; @@ -227,6 +227,38 @@ public final class BatteryStatsImpl extends BatteryStats { HistoryItem mHistoryLastEnd; HistoryItem mHistoryCache; + // Used by computeHistoryStepDetails + HistoryStepDetails mLastHistoryStepDetails = null; + byte mLastHistoryStepLevel = 0; + final HistoryStepDetails mCurHistoryStepDetails = new HistoryStepDetails(); + final HistoryStepDetails mReadHistoryStepDetails = new HistoryStepDetails(); + final HistoryStepDetails mTmpHistoryStepDetails = new HistoryStepDetails(); + /** + * Total time (in 1/100 sec) spent executing in user code. + */ + long mLastStepCpuUserTime; + long mCurStepCpuUserTime; + /** + * Total time (in 1/100 sec) spent executing in kernel code. + */ + long mLastStepCpuSystemTime; + long mCurStepCpuSystemTime; + /** + * Times from /proc/stat + */ + long mLastStepStatUserTime; + long mLastStepStatSystemTime; + long mLastStepStatIOWaitTime; + long mLastStepStatIrqTime; + long mLastStepStatSoftIrqTime; + long mLastStepStatIdleTime; + long mCurStepStatUserTime; + long mCurStepStatSystemTime; + long mCurStepStatIOWaitTime; + long mCurStepStatIrqTime; + long mCurStepStatSoftIrqTime; + long mCurStepStatIdleTime; + private HistoryItem mHistoryIterator; private boolean mReadOverflow; private boolean mIteratingHistory; @@ -1938,6 +1970,10 @@ public final class BatteryStatsImpl extends BatteryStats { static final int STATE_BATTERY_PLUG_MASK = 0x00000003; static final int STATE_BATTERY_PLUG_SHIFT = 24; + // We use the low bit of the battery state int to indicate that we have full details + // from a battery level change. + static final int BATTERY_DELTA_LEVEL_FLAG = 0x00000001; + public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) { if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) { dest.writeInt(DELTA_TIME_ABS); @@ -1958,7 +1994,11 @@ public final class BatteryStatsImpl extends BatteryStats { deltaTimeToken = (int)deltaTime; } int firstToken = deltaTimeToken | (cur.states&DELTA_STATE_MASK); - final int batteryLevelInt = buildBatteryLevelInt(cur); + final int includeStepDetails = mLastHistoryStepLevel > cur.batteryLevel + ? BATTERY_DELTA_LEVEL_FLAG : 0; + final boolean computeStepDetails = includeStepDetails != 0 + || mLastHistoryStepDetails == null; + final int batteryLevelInt = buildBatteryLevelInt(cur) | includeStepDetails; final boolean batteryLevelIntChanged = batteryLevelInt != lastBatteryLevelInt; if (batteryLevelIntChanged) { firstToken |= DELTA_BATTERY_LEVEL_FLAG; @@ -2040,12 +2080,26 @@ public final class BatteryStatsImpl extends BatteryStats { + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":" + cur.eventTag.string); } + if (computeStepDetails) { + computeHistoryStepDetails(mCurHistoryStepDetails, mLastHistoryStepDetails); + if (includeStepDetails != 0) { + mCurHistoryStepDetails.writeToParcel(dest); + } + cur.stepDetails = mCurHistoryStepDetails; + mLastHistoryStepDetails = mCurHistoryStepDetails; + } else { + cur.stepDetails = null; + } + if (mLastHistoryStepLevel < cur.batteryLevel) { + mLastHistoryStepDetails = null; + } + mLastHistoryStepLevel = cur.batteryLevel; } private int buildBatteryLevelInt(HistoryItem h) { return ((((int)h.batteryLevel)<<25)&0xfe000000) - | ((((int)h.batteryTemperature)<<14)&0x01ffc000) - | (((int)h.batteryVoltage)&0x00003fff); + | ((((int)h.batteryTemperature)<<14)&0x01ff8000) + | ((((int)h.batteryVoltage)<<1)&0x00007fff); } private int buildStateInt(HistoryItem h) { @@ -2063,6 +2117,98 @@ public final class BatteryStatsImpl extends BatteryStats { | (h.states&(~DELTA_STATE_MASK)); } + private void computeHistoryStepDetails(final HistoryStepDetails out, + final HistoryStepDetails last) { + final HistoryStepDetails tmp = last != null ? mTmpHistoryStepDetails : out; + + // Perform a CPU update right after we do this collection, so we have started + // collecting good data for the next step. + requestImmediateCpuUpdate(); + + if (last == null) { + // We are not generating a delta, so all we need to do is reset the stats + // we will later be doing a delta from. + final int NU = mUidStats.size(); + for (int i=0; i= mBaseUserTime && systemtime >= mBaseSystemTime + && iowaittime >= mBaseIoWaitTime && irqtime >= mBaseIrqTime + && softirqtime >= mBaseSoftIrqTime && idletime >= mBaseIdleTime)) { + mRelUserTime = (int)(usertime - mBaseUserTime); + mRelSystemTime = (int)(systemtime - mBaseSystemTime); + mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime); + mRelIrqTime = (int)(irqtime - mBaseIrqTime); + mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime); + mRelIdleTime = (int)(idletime - mBaseIdleTime); + mRelStatsAreGood = true; - if (DEBUG) { - Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1] - + " S:" + sysCpu[2] + " I:" + sysCpu[3] - + " W:" + sysCpu[4] + " Q:" + sysCpu[5] - + " O:" + sysCpu[6]); - Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime - + " I:" + mRelIdleTime + " Q:" + mRelIrqTime); + if (DEBUG) { + Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1] + + " S:" + sysCpu[2] + " I:" + sysCpu[3] + + " W:" + sysCpu[4] + " Q:" + sysCpu[5] + + " O:" + sysCpu[6]); + Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime + + " I:" + mRelIdleTime + " Q:" + mRelIrqTime); + } + + mBaseUserTime = usertime; + mBaseSystemTime = systemtime; + mBaseIoWaitTime = iowaittime; + mBaseIrqTime = irqtime; + mBaseSoftIrqTime = softirqtime; + mBaseIdleTime = idletime; + + } else { + mRelUserTime = 0; + mRelSystemTime = 0; + mRelIoWaitTime = 0; + mRelIrqTime = 0; + mRelSoftIrqTime = 0; + mRelIdleTime = 0; + mRelStatsAreGood = false; + Slog.w(TAG, "/proc/stats has gone backwards; skipping CPU update"); + return; } - - mBaseUserTime = usertime; - mBaseSystemTime = systemtime; - mBaseIoWaitTime = iowaittime; - mBaseIrqTime = irqtime; - mBaseSoftIrqTime = softirqtime; - mBaseIdleTime = idletime; } + mLastSampleTime = mCurrentSampleTime; + mCurrentSampleTime = nowUptime; + mLastSampleRealTime = mCurrentSampleRealTime; + mCurrentSampleRealTime = nowRealtime; + final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); try { mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats); @@ -647,6 +670,10 @@ public class ProcessCpuTracker { return mRelIdleTime; } + final public boolean hasGoodLastStats() { + return mRelStatsAreGood; + } + final public float getTotalCpuPercent() { int denom = mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime; if (denom <= 0) { diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index 912a181ef944c..b3b46513ec6a7 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -626,6 +626,22 @@ public final class BatteryService extends SystemService { pw.println(" voltage: " + mBatteryProps.batteryVoltage); pw.println(" temperature: " + mBatteryProps.batteryTemperature); pw.println(" technology: " + mBatteryProps.batteryTechnology); + + } else if ("unplug".equals(args[0])) { + if (!mUpdatesStopped) { + mLastBatteryProps.set(mBatteryProps); + } + mBatteryProps.chargerAcOnline = false; + mBatteryProps.chargerUsbOnline = false; + mBatteryProps.chargerWirelessOnline = false; + long ident = Binder.clearCallingIdentity(); + try { + mUpdatesStopped = true; + processValuesLocked(false); + } finally { + Binder.restoreCallingIdentity(ident); + } + } else if (args.length == 3 && "set".equals(args[0])) { String key = args[1]; String value = args[2]; @@ -662,6 +678,7 @@ public final class BatteryService extends SystemService { } catch (NumberFormatException ex) { pw.println("Bad value: " + value); } + } else if (args.length == 1 && "reset".equals(args[0])) { long ident = Binder.clearCallingIdentity(); try { @@ -676,6 +693,7 @@ public final class BatteryService extends SystemService { } else { pw.println("Dump current battery state, or:"); pw.println(" set [ac|usb|wireless|status|level|invalid] "); + pw.println(" unplug"); pw.println(" reset"); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 511347e1dd119..d53b61bba1aa0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2255,31 +2255,33 @@ public final class ActivityManagerService extends ActivityManagerNative if (MONITOR_CPU_USAGE && mLastCpuTime.get() < (now-MONITOR_CPU_MIN_TIME)) { mLastCpuTime.set(now); - haveNewCpuStats = true; mProcessCpuTracker.update(); - //Slog.i(TAG, mProcessCpu.printCurrentState()); - //Slog.i(TAG, "Total CPU usage: " - // + mProcessCpu.getTotalCpuPercent() + "%"); + if (mProcessCpuTracker.hasGoodLastStats()) { + haveNewCpuStats = true; + //Slog.i(TAG, mProcessCpu.printCurrentState()); + //Slog.i(TAG, "Total CPU usage: " + // + mProcessCpu.getTotalCpuPercent() + "%"); - // Slog the cpu usage if the property is set. - if ("true".equals(SystemProperties.get("events.cpu"))) { - int user = mProcessCpuTracker.getLastUserTime(); - int system = mProcessCpuTracker.getLastSystemTime(); - int iowait = mProcessCpuTracker.getLastIoWaitTime(); - int irq = mProcessCpuTracker.getLastIrqTime(); - int softIrq = mProcessCpuTracker.getLastSoftIrqTime(); - int idle = mProcessCpuTracker.getLastIdleTime(); + // Slog the cpu usage if the property is set. + if ("true".equals(SystemProperties.get("events.cpu"))) { + int user = mProcessCpuTracker.getLastUserTime(); + int system = mProcessCpuTracker.getLastSystemTime(); + int iowait = mProcessCpuTracker.getLastIoWaitTime(); + int irq = mProcessCpuTracker.getLastIrqTime(); + int softIrq = mProcessCpuTracker.getLastSoftIrqTime(); + int idle = mProcessCpuTracker.getLastIdleTime(); - int total = user + system + iowait + irq + softIrq + idle; - if (total == 0) total = 1; + int total = user + system + iowait + irq + softIrq + idle; + if (total == 0) total = 1; - EventLog.writeEvent(EventLogTags.CPU, - ((user+system+iowait+irq+softIrq) * 100) / total, - (user * 100) / total, - (system * 100) / total, - (iowait * 100) / total, - (irq * 100) / total, - (softIrq * 100) / total); + EventLog.writeEvent(EventLogTags.CPU, + ((user+system+iowait+irq+softIrq) * 100) / total, + (user * 100) / total, + (system * 100) / total, + (iowait * 100) / total, + (irq * 100) / total, + (softIrq * 100) / total); + } } } @@ -2288,8 +2290,10 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized(bstats) { synchronized(mPidsSelfLocked) { if (haveNewCpuStats) { - if (mOnBattery) { - int perc = bstats.startAddingCpuLocked(); + final int perc = bstats.startAddingCpuLocked(); + if (perc >= 0) { + int remainUTime = 0; + int remainSTime = 0; int totalUTime = 0; int totalSTime = 0; final int N = mProcessCpuTracker.countStats(); @@ -2301,17 +2305,18 @@ public final class ActivityManagerService extends ActivityManagerNative ProcessRecord pr = mPidsSelfLocked.get(st.pid); int otherUTime = (st.rel_utime*perc)/100; int otherSTime = (st.rel_stime*perc)/100; - totalUTime += otherUTime; - totalSTime += otherSTime; + remainUTime += otherUTime; + remainSTime += otherSTime; + totalUTime += st.rel_utime; + totalSTime += st.rel_stime; if (pr != null) { BatteryStatsImpl.Uid.Proc ps = pr.curProcBatteryStats; if (ps == null || !ps.isActive()) { pr.curProcBatteryStats = ps = bstats.getProcessStatsLocked( pr.info.uid, pr.processName); } - ps.addCpuTimeLocked(st.rel_utime-otherUTime, - st.rel_stime-otherSTime); - ps.addSpeedStepTimes(cpuSpeedTimes); + ps.addCpuTimeLocked(st.rel_utime - otherUTime, + st.rel_stime - otherSTime, cpuSpeedTimes); pr.curCpuTime += (st.rel_utime+st.rel_stime) * 10; } else { BatteryStatsImpl.Uid.Proc ps = st.batteryStats; @@ -2319,13 +2324,19 @@ public final class ActivityManagerService extends ActivityManagerNative st.batteryStats = ps = bstats.getProcessStatsLocked( bstats.mapUid(st.uid), st.name); } - ps.addCpuTimeLocked(st.rel_utime-otherUTime, - st.rel_stime-otherSTime); - ps.addSpeedStepTimes(cpuSpeedTimes); + ps.addCpuTimeLocked(st.rel_utime - otherUTime, + st.rel_stime - otherSTime, cpuSpeedTimes); } } - bstats.finishAddingCpuLocked(perc, totalUTime, - totalSTime, cpuSpeedTimes); + final int userTime = mProcessCpuTracker.getLastUserTime(); + final int systemTime = mProcessCpuTracker.getLastSystemTime(); + final int iowaitTime = mProcessCpuTracker.getLastIoWaitTime(); + final int irqTime = mProcessCpuTracker.getLastIrqTime(); + final int softIrqTime = mProcessCpuTracker.getLastSoftIrqTime(); + final int idleTime = mProcessCpuTracker.getLastIdleTime(); + bstats.finishAddingCpuLocked(perc, remainUTime, + remainSTime, totalUTime, totalSTime, userTime, systemTime, + iowaitTime, irqTime, softIrqTime, idleTime, cpuSpeedTimes); } } }