Merge "Add low power stats to batteryhistory" into nyc-dev
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b9a3cff..2c63be2 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1070,6 +1070,9 @@
         public int statSoftIrqTime;
         public int statIdlTime;
 
+        // Platform-level low power state stats
+        public String statPlatformIdleState;
+
         public HistoryStepDetails() {
             clear();
         }
@@ -1099,6 +1102,7 @@
             out.writeInt(statIrqTime);
             out.writeInt(statSoftIrqTime);
             out.writeInt(statIdlTime);
+            out.writeString(statPlatformIdleState);
         }
 
         public void readFromParcel(Parcel in) {
@@ -1119,6 +1123,7 @@
             statIrqTime = in.readInt();
             statSoftIrqTime = in.readInt();
             statIdlTime = in.readInt();
+            statPlatformIdleState = in.readString();
         }
     }
 
@@ -4788,6 +4793,8 @@
                             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 @@
                         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 e69ed35..5358d78 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -108,7 +108,7 @@
     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 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 @@
         mDailyFile = null;
         mHandler = null;
         mExternalSync = null;
+        mPlatformIdleStateCallback = null;
         clearHistoryLocked();
     }
 
@@ -2220,6 +2228,12 @@
                     + 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 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 @@
         initDischarge();
         clearHistoryLocked();
         updateDailyDeadlineLocked();
+        mPlatformIdleStateCallback = cb;
     }
 
     public BatteryStatsImpl(Parcel p) {
@@ -7477,6 +7497,7 @@
         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 2516f5d..c6786de 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 @@
  * 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 @@
         }
     }
 
+    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 @@
         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 5c43659..183a370 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 <utils/misc.h>
 #include <utils/Log.h>
 #include <hardware/hardware.h>
+#include <hardware/power.h>
 #include <suspend/autosuspend.h>
 
+#include <inttypes.h>
 #include <stdio.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -47,6 +49,7 @@
 
 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 @@
     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 2fdb8e2..cbbfda6a 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 jobject gPowerManagerServiceObj;
-static struct power_module* gPowerModule;
+struct power_module* gPowerModule;
 
 static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];