Merge "PowerManager: Adds the Sustained performance API."
diff --git a/api/current.txt b/api/current.txt
index a10c510..10562d5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28553,6 +28553,7 @@
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
     field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
     field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+    field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
   }
 
   public final class PowerManager.WakeLock {
diff --git a/api/system-current.txt b/api/system-current.txt
index de5d8c9..dc081bf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -30633,6 +30633,7 @@
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
     field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
     field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+    field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
     field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1
     field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0
     field public static final int USER_ACTIVITY_EVENT_TOUCH = 2; // 0x2
diff --git a/api/test-current.txt b/api/test-current.txt
index 25b72c0..1bf294b 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -28561,6 +28561,7 @@
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
     field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
     field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+    field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
   }
 
   public final class PowerManager.WakeLock {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 4159d89..314b7d5 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -219,6 +219,15 @@
     public static final int DRAW_WAKE_LOCK = 0x00000080;
 
     /**
+     * Wake lock level: Enables Sustained Performance Mode.
+     * <p>
+     * This is used by Gaming and VR applications to ensure the device provides
+     * will provide consistent performance over a large amount of time.
+     * </p>
+     */
+    public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 0x00000100;
+
+    /**
      * Mask for the wake lock level component of a combined wake lock level and flags integer.
      *
      * @hide
@@ -525,6 +534,7 @@
             case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
             case DOZE_WAKE_LOCK:
             case DRAW_WAKE_LOCK:
+            case SUSTAINED_PERFORMANCE_WAKE_LOCK:
                 break;
             default:
                 throw new IllegalArgumentException("Must specify a valid wake lock level.");
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 290019c..a1f24f7 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -131,6 +131,7 @@
     private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
     private static final int WAKE_LOCK_DOZE = 1 << 6;
     private static final int WAKE_LOCK_DRAW = 1 << 7;
+    private static final int WAKE_LOCK_SUSTAINED_PERFORMANCE = 1 << 8;
 
     // Summarizes the user activity state.
     private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -149,6 +150,7 @@
 
     // Power hints defined in hardware/libhardware/include/hardware/power.h.
     private static final int POWER_HINT_LOW_POWER = 5;
+    private static final int POWER_HINT_SUSTAINED_PERFORMANCE = 6;
 
     // Power features defined in hardware/libhardware/include/hardware/power.h.
     private static final int POWER_FEATURE_DOUBLE_TAP_TO_WAKE = 1;
@@ -444,6 +446,9 @@
     // True if we are currently in light device idle mode.
     private boolean mLightDeviceIdleMode;
 
+    // True if we are currently in sustained performance mode.
+    private boolean mSustainedPerformanceMode;
+
     // Set of app ids that we will always respect the wake locks for.
     int[] mDeviceIdleWhitelist = new int[0];
 
@@ -452,6 +457,8 @@
 
     private final SparseIntArray mUidState = new SparseIntArray();
 
+    private final SparseIntArray mSustainedPerformanceUid = new SparseIntArray();
+
     // True if theater mode is enabled
     private boolean mTheaterModeEnabled;
 
@@ -811,6 +818,12 @@
                     throw new IllegalArgumentException("Wake lock is already dead.");
                 }
                 mWakeLocks.add(wakeLock);
+
+                if ((flags & PowerManager.WAKE_LOCK_LEVEL_MASK)
+                        == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
+                    int numberWakelock = mSustainedPerformanceUid.get(uid);
+                    mSustainedPerformanceUid.put(uid, numberWakelock + 1);
+                }
                 setWakeLockDisabledStateLocked(wakeLock);
                 notifyAcquire = true;
             }
@@ -879,6 +892,17 @@
                 mRequestWaitForNegativeProximity = true;
             }
 
+
+            if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
+                    == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
+                int numberWakelock = mSustainedPerformanceUid.get(wakeLock.mOwnerUid);
+                if (numberWakelock == 1) {
+                    mSustainedPerformanceUid.delete(wakeLock.mOwnerUid);
+                } else {
+                    mSustainedPerformanceUid.put(wakeLock.mOwnerUid, numberWakelock - 1);
+                }
+            }
+
             wakeLock.mLock.unlinkToDeath(wakeLock, 0);
             removeWakeLockLocked(wakeLock, index);
         }
@@ -1501,6 +1525,10 @@
                         break;
                     case PowerManager.DRAW_WAKE_LOCK:
                         mWakeLockSummary |= WAKE_LOCK_DRAW;
+                    case PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK:
+                        if (!wakeLock.mDisabled) {
+                            mWakeLockSummary |= WAKE_LOCK_SUSTAINED_PERFORMANCE;
+                        }
                         break;
                 }
             }
@@ -2198,6 +2226,14 @@
         if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
             setHalAutoSuspendModeLocked(true);
         }
+
+        if (mSustainedPerformanceMode
+                && (mWakeLockSummary & WAKE_LOCK_SUSTAINED_PERFORMANCE) == 0) {
+            setSustainedPerformanceModeLocked(false);
+        } else if (!mSustainedPerformanceMode
+                && (mWakeLockSummary & WAKE_LOCK_SUSTAINED_PERFORMANCE) != 0) {
+            setSustainedPerformanceModeLocked(true);
+        }
     }
 
     /**
@@ -2296,6 +2332,12 @@
         }
     }
 
+    private void setSustainedPerformanceModeLocked(boolean mode) {
+            mSustainedPerformanceMode = mode;
+            powerHintInternal(POWER_HINT_SUSTAINED_PERFORMANCE,
+                              mSustainedPerformanceMode ? 1 : 0);
+    }
+
     boolean isDeviceIdleModeInternal() {
         synchronized (mLock) {
             return mDeviceIdleMode;
@@ -2425,7 +2467,7 @@
     void updateUidProcStateInternal(int uid, int procState) {
         synchronized (mLock) {
             mUidState.put(uid, procState);
-            if (mDeviceIdleMode) {
+            if (mDeviceIdleMode || mSustainedPerformanceUid.get(uid) != 0) {
                 updateWakeLockDisabledStatesLocked();
             }
         }
@@ -2446,7 +2488,9 @@
         for (int i = 0; i < numWakeLocks; i++) {
             final WakeLock wakeLock = mWakeLocks.get(i);
             if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
-                    == PowerManager.PARTIAL_WAKE_LOCK) {
+                    == PowerManager.PARTIAL_WAKE_LOCK
+                    || (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
+                    == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
                 if (setWakeLockDisabledStateLocked(wakeLock)) {
                     changed = true;
                     if (wakeLock.mDisabled) {
@@ -2465,9 +2509,9 @@
     }
 
     private boolean setWakeLockDisabledStateLocked(WakeLock wakeLock) {
+        boolean disabled = false;
         if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
                 == PowerManager.PARTIAL_WAKE_LOCK) {
-            boolean disabled = false;
             if (mDeviceIdleMode) {
                 final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);
                 // If we are in idle mode, we will ignore all partial wake locks that are
@@ -2481,10 +2525,16 @@
                     disabled = true;
                 }
             }
-            if (wakeLock.mDisabled != disabled) {
-                wakeLock.mDisabled = disabled;
-                return true;
-            }
+        } else if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
+                == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK
+                && mUidState.get(wakeLock.mOwnerUid,
+                                 ActivityManager.PROCESS_STATE_CACHED_EMPTY)
+                > ActivityManager.PROCESS_STATE_TOP) {
+            disabled = true;
+        }
+        if (wakeLock.mDisabled != disabled) {
+            wakeLock.mDisabled = disabled;
+            return true;
         }
         return false;
     }
@@ -2695,6 +2745,7 @@
             pw.println("  mBatteryLevelLow=" + mBatteryLevelLow);
             pw.println("  mLightDeviceIdleMode=" + mLightDeviceIdleMode);
             pw.println("  mDeviceIdleMode=" + mDeviceIdleMode);
+            pw.println("  mSustainedPerformanceMode=" + mSustainedPerformanceMode);
             pw.println("  mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
             pw.println("  mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist));
             pw.println("  mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
@@ -2809,6 +2860,14 @@
             pw.println();
             pw.println("Display Power: " + mDisplayPowerCallbacks);
 
+            pw.println();
+            pw.println("Sustained Performance UIDs:");
+            for (int i=0; i<mSustainedPerformanceUid.size(); i++) {
+                pw.print("  UID "); UserHandle.formatUid(pw, mSustainedPerformanceUid.keyAt(i));
+                pw.print(": "); pw.println(mSustainedPerformanceUid.valueAt(i));
+            }
+
+
             wcd = mWirelessChargerDetector;
         }