Initial checkin for App Fuel Gauge infrastructure.

This adds the PowerProfile class and data file that provides power consumption numbers
for different subsystems. Also added Audio/Video subsystems to track on a per UID basis.
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 8a0fd58..358a546 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -69,6 +69,20 @@
      public static final int WIFI_MULTICAST_ENABLED = 7;
 
     /**
+     * A constant indicating an audio turn on timer
+     *
+     * {@hide}
+     */
+    public static final int AUDIO_TURNED_ON = 7;
+
+    /**
+     * A constant indicating a video turn on timer
+     *
+     * {@hide}
+     */
+    public static final int VIDEO_TURNED_ON = 8;
+
+    /**
      * Include all of the data in the stats, including previously saved data.
      */
     public static final int STATS_TOTAL = 0;
@@ -164,7 +178,7 @@
          * @return a time in microseconds
          */
         public abstract long getTotalTimeLocked(long batteryRealtime, int which);
-        
+
         /**
          * Temporary for debugging.
          */
@@ -234,11 +248,17 @@
         public abstract void noteScanWifiLockReleasedLocked();
         public abstract void noteWifiMulticastEnabledLocked();
         public abstract void noteWifiMulticastDisabledLocked();
+        public abstract void noteAudioTurnedOnLocked();
+        public abstract void noteAudioTurnedOffLocked();
+        public abstract void noteVideoTurnedOnLocked();
+        public abstract void noteVideoTurnedOffLocked();
         public abstract long getWifiTurnedOnTime(long batteryRealtime, int which);
         public abstract long getFullWifiLockTime(long batteryRealtime, int which);
         public abstract long getScanWifiLockTime(long batteryRealtime, int which);
         public abstract long getWifiMulticastTime(long batteryRealtime,
                                                   int which);
+        public abstract long getAudioTurnedOnTime(long batteryRealtime, int which);
+        public abstract long getVideoTurnedOnTime(long batteryRealtime, int which);
 
         /**
          * Note that these must match the constants in android.os.LocalPowerManager.
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index bf9bc4e..a448ac6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -37,10 +37,8 @@
 import java.io.PrintWriter;
 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
@@ -55,7 +53,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS' 
 
     // Current on-disk Parcel version
-    private static final int VERSION = 35;
+    private static final int VERSION = 36;
 
     private final File mFile;
     private final File mBackupFile;
@@ -105,6 +103,12 @@
     boolean mPhoneOn;
     StopwatchTimer mPhoneOnTimer;
     
+    boolean mAudioOn;
+    StopwatchTimer mAudioOnTimer;
+    
+    boolean mVideoOn;
+    StopwatchTimer mVideoOnTimer;
+    
     int mPhoneSignalStrengthBin = -1;
     final StopwatchTimer[] mPhoneSignalStrengthsTimer = 
             new StopwatchTimer[NUM_SIGNAL_STRENGTH_BINS];
@@ -142,9 +146,9 @@
      */
     int mDischargeStartLevel;
     int mDischargeCurrentLevel;
-    
+
     long mLastWriteTime = 0; // Milliseconds
-    
+
     /*
      * Holds a SamplingTimer associated with each kernel wakelock name being tracked.
      */
@@ -320,6 +324,13 @@
          */
         long mUnpluggedTime;
         
+        /**
+         * Constructs from a parcel.
+         * @param type
+         * @param unpluggables
+         * @param powerType
+         * @param in
+         */
         Timer(int type, ArrayList<Unpluggable> unpluggables, Parcel in) {
             mType = type;
             
@@ -632,7 +643,6 @@
          * was actually held for an interesting duration.
          */
         long mAcquireTime;
-        
 
         StopwatchTimer(int type, ArrayList<StopwatchTimer> timerPool,
                 ArrayList<Unpluggable> unpluggables, Parcel in) {
@@ -1071,7 +1081,51 @@
             mWifiOnUid = -1;
         }
     }
+
+    public void noteAudioOnLocked(int uid) {
+        if (!mAudioOn) {
+            mAudioOn = true;
+            mAudioOnTimer.startRunningLocked(this);
+        }
+        Uid u = mUidStats.get(uid);
+        if (u != null) {
+            u.noteAudioTurnedOnLocked();
+        }
+    }
     
+    public void noteAudioOffLocked(int uid) {
+        if (mAudioOn) {
+            mAudioOn = false;
+            mAudioOnTimer.stopRunningLocked(this);
+        }
+        Uid u = mUidStats.get(uid);
+        if (u != null) {
+            u.noteAudioTurnedOffLocked();
+        }
+    }
+
+    public void noteVideoOnLocked(int uid) {
+        if (!mVideoOn) {
+            mVideoOn = true;
+            mVideoOnTimer.startRunningLocked(this);
+        }
+        Uid u = mUidStats.get(uid);
+        if (u != null) {
+            u.noteVideoTurnedOnLocked();
+        }
+    }
+    
+    public void noteVideoOffLocked(int uid) {
+        if (mVideoOn) {
+            mVideoOn = false;
+            mVideoOnTimer.stopRunningLocked(this);
+        }
+        Uid u = mUidStats.get(uid);
+        if (u != null) {
+            u.noteVideoTurnedOffLocked();
+        }
+    }
+
     public void noteWifiRunningLocked() {
         if (!mWifiRunning) {
             mWifiRunning = true;
@@ -1151,7 +1205,7 @@
         return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
                 batteryRealtime, which);
     }
-    
+
     @Override public int getInputEventCount(int which) {
         return mInputEventCounter.getCountLocked(which);
     }
@@ -1159,7 +1213,7 @@
     @Override public long getPhoneOnTime(long batteryRealtime, int which) {
         return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
     }
-    
+
     @Override public long getPhoneSignalStrengthTime(int strengthBin,
             long batteryRealtime, int which) {
         return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
@@ -1226,9 +1280,15 @@
         
         boolean mScanWifiLockOut;
         StopwatchTimer mScanWifiLockTimer;
-
+        
         boolean mWifiMulticastEnabled;
         StopwatchTimer mWifiMulticastTimer;
+        
+        boolean mAudioTurnedOn;
+        StopwatchTimer mAudioTurnedOnTimer;
+        
+        boolean mVideoTurnedOn;
+        StopwatchTimer mVideoTurnedOnTimer;
 
         Counter[] mUserActivityCounters;
         
@@ -1259,6 +1319,8 @@
             mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables);
             mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED,
                     null, mUnpluggables);
+            mAudioTurnedOnTimer = new StopwatchTimer(AUDIO_TURNED_ON, null, mUnpluggables);
+            mVideoTurnedOnTimer = new StopwatchTimer(VIDEO_TURNED_ON, null, mUnpluggables);
         }
 
         @Override
@@ -1343,6 +1405,38 @@
         }
         
         @Override
+        public void noteVideoTurnedOnLocked() {
+            if (!mVideoTurnedOn) {
+                mVideoTurnedOn = true;
+                mVideoTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
+            }
+        }
+
+        @Override
+        public void noteVideoTurnedOffLocked() {
+            if (mVideoTurnedOn) {
+                mVideoTurnedOn = false;
+                mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
+            }
+        }
+
+        @Override
+        public void noteAudioTurnedOnLocked() {
+            if (!mAudioTurnedOn) {
+                mAudioTurnedOn = true;
+                mAudioTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
+            }
+        }
+
+        @Override
+        public void noteAudioTurnedOffLocked() {
+            if (mAudioTurnedOn) {
+                mAudioTurnedOn = false;
+                mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
+            }
+        }
+
+        @Override
         public void noteFullWifiLockReleasedLocked() {
             if (mFullWifiLockOut) {
                 mFullWifiLockOut = false;
@@ -1386,7 +1480,17 @@
         public long getWifiTurnedOnTime(long batteryRealtime, int which) {
             return mWifiTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
         }
-        
+
+        @Override 
+        public long getAudioTurnedOnTime(long batteryRealtime, int which) {
+            return mAudioTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
+        }
+
+        @Override 
+        public long getVideoTurnedOnTime(long batteryRealtime, int which) {
+            return mVideoTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
+        }
+
         @Override 
         public long getFullWifiLockTime(long batteryRealtime, int which) {
             return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
@@ -1437,7 +1541,7 @@
             return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
                     ? (NetStat.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0);
         }
-        
+
         void writeToParcelLocked(Parcel out, long batteryRealtime) {
             out.writeInt(mWakelockStats.size());
             for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
@@ -1475,6 +1579,8 @@
             out.writeLong(mTcpBytesSentAtLastUnplug);
             mWifiTurnedOnTimer.writeToParcel(out, batteryRealtime);
             mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
+            mAudioTurnedOnTimer.writeToParcel(out, batteryRealtime);
+            mVideoTurnedOnTimer.writeToParcel(out, batteryRealtime);
             mScanWifiLockTimer.writeToParcel(out, batteryRealtime);
             mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
             if (mUserActivityCounters == null) {
@@ -1534,6 +1640,10 @@
             mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables, in);
             mFullWifiLockOut = false;
             mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables, in);
+            mAudioTurnedOn = false;
+            mAudioTurnedOnTimer = new StopwatchTimer(AUDIO_TURNED_ON, null, mUnpluggables, in);
+            mVideoTurnedOn = false;
+            mVideoTurnedOnTimer = new StopwatchTimer(VIDEO_TURNED_ON, null, mUnpluggables, in);
             mScanWifiLockOut = false;
             mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables, in);
             mWifiMulticastEnabled = false;
@@ -2327,7 +2437,7 @@
             StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
             if (t != null) {
                 t.stopRunningLocked(BatteryStatsImpl.this);
-            }  
+            }
         }
 
         public BatteryStatsImpl getBatteryStats() {
@@ -2764,6 +2874,10 @@
             u.mWifiTurnedOnTimer.readSummaryFromParcelLocked(in);
             u.mFullWifiLockOut = false;
             u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
+            u.mAudioTurnedOn = false;
+            u.mAudioTurnedOnTimer.readSummaryFromParcelLocked(in);
+            u.mVideoTurnedOn = false;
+            u.mVideoTurnedOnTimer.readSummaryFromParcelLocked(in);
             u.mScanWifiLockOut = false;
             u.mScanWifiLockTimer.readSummaryFromParcelLocked(in);
             u.mWifiMulticastEnabled = false;
@@ -3063,6 +3177,7 @@
         for (int ikw = 0; ikw < NKW; ikw++) {
             if (in.readInt() != 0) {
                 String wakelockName = in.readString();
+                in.readInt(); // Extra 0/1 written by Timer.writeTimerToParcel
                 SamplingTimer kwlt = new SamplingTimer(mUnpluggables, mOnBattery, in);
                 mKernelWakelockStats.put(wakelockName, kwlt);
             }
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
new file mode 100644
index 0000000..f08dddd
--- /dev/null
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+
+import android.content.Context;
+import android.content.res.XmlResourceParser;
+
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * Reports power consumption values for various device activities. Reads values from an XML file.
+ * Customize the XML file for different devices.
+ * [hidden]
+ */
+public class PowerProfile {
+
+    /**
+     * No power consumption, or accounted for elsewhere.
+     */
+    public static final String POWER_NONE = "none";
+
+    /**
+     * Power consumption when CPU is in power collapse mode.
+     */
+    public static final String POWER_CPU_IDLE = "cpu.idle";
+
+    /**
+     * Power consumption when CPU is running at normal speed.
+     */
+    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";
+
+    /**
+     * Power consumption when WiFi driver is scanning for networks.
+     */
+    public static final String POWER_WIFI_SCAN = "wifi.scan";
+
+    /**
+     * Power consumption when WiFi driver is on.
+     */
+    public static final String POWER_WIFI_ON = "wifi.on";
+
+    /**
+     * Power consumption when WiFi driver is transmitting/receiving.
+     */
+    public static final String POWER_WIFI_ACTIVE = "wifi.active";
+
+    /**
+     * Power consumption when GPS is on.
+     */
+    public static final String POWER_GPS_ON = "gps.on";
+
+    /**
+     * Power consumption when Bluetooth driver is on.
+     */
+    public static final String POWER_BLUETOOTH_ON = "bluetooth.on";
+
+    /**
+     * Power consumption when Bluetooth driver is transmitting/receiving.
+     */
+    public static final String POWER_BLUETOOTH_ACTIVE = "bluetooth.active";
+
+    /**
+     * Power consumption when screen is on, not including the backlight power.
+     */
+    public static final String POWER_SCREEN_ON = "screen.on";
+
+    /**
+     * Power consumption when cell radio is on but not on a call.
+     */
+    public static final String POWER_RADIO_ON = "radio.on";
+
+    /**
+     * Power consumption when talking on the phone.
+     */
+    public static final String POWER_RADIO_ACTIVE = "radio.active";
+
+    /**
+     * Power consumption at full backlight brightness. If the backlight is at
+     * 50% brightness, then this should be multiplied by 0.5
+     */
+    public static final String POWER_SCREEN_FULL = "screen.full";
+
+    /**
+     * Power consumed by the audio hardware when playing back audio content. This is in addition
+     * to the CPU power, probably due to a DSP and / or amplifier.
+     */
+    public static final String POWER_AUDIO = "dsp.audio";
+
+    /**
+     * Power consumed by any media hardware when playing back video content. This is in addition
+     * to the CPU power, probably due to a DSP.
+     */
+    public static final String POWER_VIDEO = "dsp.video";
+
+    static final HashMap<String, Double> sPowerMap = new HashMap<String, Double>();
+
+    private static final String TAG_DEVICE = "device";
+    private static final String TAG_ITEM = "item";
+    private static final String ATTR_NAME = "name";
+
+    public PowerProfile(Context context, CharSequence profile) {
+        // Read the XML file for the given profile (normally only one per
+        // device)
+        if (sPowerMap.size() == 0) {
+            readPowerValuesFromXml(context, profile);
+        }
+    }
+
+    private void readPowerValuesFromXml(Context context, CharSequence profile) {
+        // FIXME
+        //int id = context.getResources().getIdentifier(profile.toString(), "xml", 
+        //        "com.android.internal");
+        int id = com.android.internal.R.xml.power_profile_default;
+        XmlResourceParser parser = context.getResources().getXml(id);
+
+        try {
+            XmlUtils.beginDocument(parser, TAG_DEVICE);
+
+            while (true) {
+                XmlUtils.nextElement(parser);
+
+                String element = parser.getName(); 
+                if (element == null || !(element.equals(TAG_ITEM))) {
+                    break;
+                }
+
+                String name = parser.getAttributeValue(null, ATTR_NAME);
+                if (parser.next() == XmlPullParser.TEXT) {
+                    String power = parser.getText();
+                    double value = 0;
+                    try {
+                        value = Double.valueOf(power);
+                    } catch (NumberFormatException nfe) {
+                    }
+                    sPowerMap.put(name, value);
+                }
+            }
+        } catch (XmlPullParserException e) {
+            throw new RuntimeException(e);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } finally {
+            parser.close();
+        }
+    }
+
+    /**
+     * Returns the average current in mA consumed by the subsystem 
+     * @param type the subsystem type
+     * @return the average current in milliAmps.
+     */
+    public double getAveragePower(String type) {
+        if (sPowerMap.containsKey(type)) {
+            return sPowerMap.get(type);
+        } else {
+            return 0;
+        }
+    }
+}
diff --git a/core/res/res/xml/power_profile_default.xml b/core/res/res/xml/power_profile_default.xml
new file mode 100644
index 0000000..d265b46
--- /dev/null
+++ b/core/res/res/xml/power_profile_default.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<device name="Android">
+  <item name="none">0</item>
+  <item name="screen.on">30</item>
+  <item name="bluetooth.active">103</item>
+  <item name="bluetooth.on">5</item>
+  <item name="screen.full">144</item>
+  <item name="wifi.on">23</item>
+  <item name="wifi.active">200</item>
+  <item name="wifi.scan">200</item>
+  <item name="cpu.idle">1.6</item>
+  <item name="cpu.normal">100</item>
+  <item name="cpu.full">140</item>
+  <item name="dsp.audio">70</item>
+  <item name="dsp.video">100</item>
+  <item name="radio.on">3</item>
+  <item name="radio.active">175</item>
+</device>
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index a695eba..9a4b642 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -206,6 +206,34 @@
         }
     }
 
+    public void noteStartAudio(int uid) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteAudioOnLocked(uid);
+        }
+    }
+
+    public void noteStopAudio(int uid) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteAudioOffLocked(uid);
+        }
+    }
+
+    public void noteStartVideo(int uid) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteVideoOnLocked(uid);
+        }
+    }
+
+    public void noteStopVideo(int uid) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteVideoOffLocked(uid);
+        }
+    }
+
     public void noteWifiRunning() {
         enforceCallingPermission();
         synchronized (mStats) {