diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index b9a3cff1aabbe..2c63be255c0b0 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -1070,6 +1070,9 @@ public abstract class BatteryStats implements Parcelable { public int statSoftIrqTime; public int statIdlTime; + // Platform-level low power state stats + public String statPlatformIdleState; + public HistoryStepDetails() { clear(); } @@ -1099,6 +1102,7 @@ public abstract class BatteryStats implements Parcelable { out.writeInt(statIrqTime); out.writeInt(statSoftIrqTime); out.writeInt(statIdlTime); + out.writeString(statPlatformIdleState); } public void readFromParcel(Parcel in) { @@ -1119,6 +1123,7 @@ public abstract class BatteryStats implements Parcelable { statIrqTime = in.readInt(); statSoftIrqTime = in.readInt(); statIdlTime = in.readInt(); + statPlatformIdleState = in.readString(); } } @@ -4788,6 +4793,8 @@ public abstract class BatteryStats implements Parcelable { pw.print(sb); pw.print(")"); } + pw.print(", PlatformIdleStat "); + pw.print(rec.stepDetails.statPlatformIdleState); pw.println(); } else { pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); @@ -4821,6 +4828,8 @@ public abstract class BatteryStats implements Parcelable { pw.print(rec.stepDetails.statSoftIrqTime); pw.print(','); pw.print(rec.stepDetails.statIdlTime); + pw.print(','); + pw.print(rec.stepDetails.statPlatformIdleState); pw.println(); } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index e69ed35ff90d4..5358d78e1b02a 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -108,7 +108,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 142 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 143 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -150,6 +150,13 @@ public class BatteryStatsImpl extends BatteryStats { public void batterySendBroadcast(Intent intent); } + public interface PlatformIdleStateCallback { + public String getPlatformLowPowerStats(); + } + + private final PlatformIdleStateCallback mPlatformIdleStateCallback; + + final class MyHandler extends Handler { public MyHandler(Looper looper) { super(looper, null, true); @@ -569,6 +576,7 @@ public class BatteryStatsImpl extends BatteryStats { mDailyFile = null; mHandler = null; mExternalSync = null; + mPlatformIdleStateCallback = null; clearHistoryLocked(); } @@ -2220,6 +2228,12 @@ public class BatteryStatsImpl extends BatteryStats { + cur.eventTag.string); } if (computeStepDetails) { + if (mPlatformIdleStateCallback != null) { + mCurHistoryStepDetails.statPlatformIdleState = + mPlatformIdleStateCallback.getPlatformLowPowerStats(); + if (DEBUG) Slog.i(TAG, "WRITE PlatformIdleState:" + + mCurHistoryStepDetails.statPlatformIdleState); + } computeHistoryStepDetails(mCurHistoryStepDetails, mLastHistoryStepDetails); if (includeStepDetails != 0) { mCurHistoryStepDetails.writeToParcel(dest); @@ -7372,11 +7386,16 @@ public class BatteryStatsImpl extends BatteryStats { } public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) { - this(new SystemClocks(), systemDir, handler, externalSync); + this(new SystemClocks(), systemDir, handler, externalSync, null); + } + + public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync, + PlatformIdleStateCallback cb) { + this(new SystemClocks(), systemDir, handler, externalSync, cb); } public BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler, - ExternalStatsSync externalSync) { + ExternalStatsSync externalSync, PlatformIdleStateCallback cb) { init(clocks); if (systemDir != null) { @@ -7462,6 +7481,7 @@ public class BatteryStatsImpl extends BatteryStats { initDischarge(); clearHistoryLocked(); updateDailyDeadlineLocked(); + mPlatformIdleStateCallback = cb; } public BatteryStatsImpl(Parcel p) { @@ -7477,6 +7497,7 @@ public class BatteryStatsImpl extends BatteryStats { mExternalSync = null; clearHistoryLocked(); readFromParcel(p); + mPlatformIdleStateCallback = null; } public void setPowerProfile(PowerProfile profile) { diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 2516f5df4cbfd..c6786defd3f98 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -79,7 +79,8 @@ import java.util.concurrent.TimeoutException; * battery life. */ public final class BatteryStatsService extends IBatteryStats.Stub - implements PowerManagerInternal.LowPowerModeListener { + implements PowerManagerInternal.LowPowerModeListener, + BatteryStatsImpl.PlatformIdleStateCallback { static final String TAG = "BatteryStatsService"; /** @@ -173,6 +174,33 @@ public final class BatteryStatsService extends IBatteryStats.Stub } } + private native int getPlatformLowPowerStats(ByteBuffer outBuffer); + private CharsetDecoder mDecoderStat = StandardCharsets.UTF_8 + .newDecoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE) + .replaceWith("?"); + private ByteBuffer mUtf8BufferStat = ByteBuffer.allocateDirect(MAX_LOW_POWER_STATS_SIZE); + private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE); + private static final int MAX_LOW_POWER_STATS_SIZE = 512; + + @Override + public String getPlatformLowPowerStats() { + mUtf8BufferStat.clear(); + mUtf16BufferStat.clear(); + mDecoderStat.reset(); + int bytesWritten = getPlatformLowPowerStats(mUtf8BufferStat); + if (bytesWritten < 0) { + return null; + } else if (bytesWritten == 0) { + return "Empty"; + } + mUtf8BufferStat.limit(bytesWritten); + mDecoderStat.decode(mUtf8BufferStat, mUtf16BufferStat, true); + mUtf16BufferStat.flip(); + return mUtf16BufferStat.toString(); + } + BatteryStatsService(File systemDir, Handler handler) { // Our handler here will be accessing the disk, use a different thread than // what the ActivityManagerService gave us (no I/O on that one!). @@ -182,9 +210,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub mHandler = new BatteryStatsHandler(thread.getLooper()); // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through. - mStats = new BatteryStatsImpl(systemDir, handler, mHandler); + mStats = new BatteryStatsImpl(systemDir, handler, mHandler, this); } - + public void publish(Context context) { mContext = context; mStats.setRadioScanningTimeout(mContext.getResources().getInteger( diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp index 5c43659796440..183a370bac0d7 100644 --- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp +++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp @@ -27,8 +27,10 @@ #include #include #include +#include #include +#include #include #include #include @@ -47,6 +49,7 @@ namespace android static bool wakeup_init = false; static sem_t wakeup_sem; +extern struct power_module* gPowerModule; static void wakeup_callback(bool success) { @@ -170,8 +173,122 @@ static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf) return mergedreasonpos - mergedreason; } +static jint getPlatformLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) { + int num_modes = -1; + char *output = (char*)env->GetDirectBufferAddress(outBuf), *offset = output; + int remaining = (int)env->GetDirectBufferCapacity(outBuf); + power_state_platform_sleep_state_t *list; + size_t *voter_list; + int total_added = -1; + + if (outBuf == NULL) { + jniThrowException(env, "java/lang/NullPointerException", "null argument"); + goto error; + } + + if (!gPowerModule) { + ALOGE("%s: gPowerModule not loaded", POWER_HARDWARE_MODULE_ID); + goto error; + } + + if (! (gPowerModule->get_platform_low_power_stats && gPowerModule->get_number_of_platform_modes + && gPowerModule->get_voter_list)) { + ALOGE("%s: Missing API", POWER_HARDWARE_MODULE_ID); + goto error; + } + + if (gPowerModule->get_number_of_platform_modes) { + num_modes = gPowerModule->get_number_of_platform_modes(gPowerModule); + } + + if (num_modes < 1) { + ALOGE("%s: Platform does not even have one low power mode", POWER_HARDWARE_MODULE_ID); + goto error; + } + + list = (power_state_platform_sleep_state_t *)calloc(num_modes, + sizeof(power_state_platform_sleep_state_t)); + if (!list) { + ALOGE("%s: power_state_platform_sleep_state_t allocation failed", POWER_HARDWARE_MODULE_ID); + goto error; + } + + voter_list = (size_t *)calloc(num_modes, sizeof(*voter_list)); + if (!voter_list) { + ALOGE("%s: voter_list allocation failed", POWER_HARDWARE_MODULE_ID); + goto err_free; + } + + gPowerModule->get_voter_list(gPowerModule, voter_list); + + for (int i = 0; i < num_modes; i++) { + list[i].voters = (power_state_voter_t *)calloc(voter_list[i], + sizeof(power_state_voter_t)); + if (!list[i].voters) { + ALOGE("%s: voter_t allocation failed", POWER_HARDWARE_MODULE_ID); + goto err_free; + } + } + + if (!gPowerModule->get_platform_low_power_stats(gPowerModule, list)) { + for (int i = 0; i < num_modes; i++) { + int added; + + added = snprintf(offset, remaining, "%s_time=%" PRIu64 " %s_count=%" PRIu64 " ", + list[i].name, list[i].residency_in_msec_since_boot, list[i].name, + list[i].total_transitions); + if (added < 0) { + break; + } + if (added > remaining) { + added = remaining; + } + offset += added; + remaining -= added; + total_added += added; + + for (unsigned int j = 0; j < list[i].number_of_voters; j++) { + added = snprintf(offset, remaining, "%s_time=%" PRIu64 " %s_count=%" PRIu64 " ", + list[i].voters[j].name, + list[i].voters[j].total_time_in_msec_voted_for_since_boot, + list[i].voters[j].name, + list[i].voters[j].total_number_of_times_voted_since_boot); + if (added < 0) { + break; + } + if (added > remaining) { + added = remaining; + } + offset += added; + remaining -= added; + total_added += added; + } + + if (remaining <= 0) { + /* rewrite NULL character*/ + offset--; + total_added--; + ALOGE("%s module: buffer not enough", POWER_HARDWARE_MODULE_ID); + break; + } + } + } + *offset = 0; + total_added += 1; + +err_free: + for (int i = 0; i < num_modes; i++) { + free(list[i].voters); + } + free(list); + free(voter_list); +error: + return total_added; +} + static const JNINativeMethod method_table[] = { { "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup }, + { "getPlatformLowPowerStats", "(Ljava/nio/ByteBuffer;)I", (void*)getPlatformLowPowerStats }, }; int register_android_server_BatteryStatsService(JNIEnv *env) diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp index 2fdb8e2469cd6..cbbfda6aa1598 100644 --- a/services/core/jni/com_android_server_power_PowerManagerService.cpp +++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp @@ -48,7 +48,7 @@ static struct { // ---------------------------------------------------------------------------- static jobject gPowerManagerServiceObj; -static struct power_module* gPowerModule; +struct power_module* gPowerModule; static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];