Extreme battery saver: Allow lowering framerate for experiments.

Bug: 68769804
Test: manual
Change-Id: Ic0c95f32c7ba6d86a997997e480e6d8a5f228f25
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 2ffa1c5..ba6b6cf 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -164,6 +164,7 @@
     private long mLastFrameTimeNanos;
     private long mFrameIntervalNanos;
     private boolean mDebugPrintNextFrameTimeDelta;
+    private int mFPSDivisor = 1;
 
     /**
      * Contains information about the current frame for jank-tracking,
@@ -601,6 +602,11 @@
         }
     }
 
+    void setFPSDivisor(int divisor) {
+        if (divisor <= 0) divisor = 1;
+        mFPSDivisor = divisor;
+    }
+
     void doFrame(long frameTimeNanos, int frame) {
         final long startNanos;
         synchronized (mLock) {
@@ -643,6 +649,14 @@
                 return;
             }
 
+            if (mFPSDivisor > 1) {
+                long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
+                if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
+                    scheduleVsyncLocked();
+                    return;
+                }
+            }
+
             mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
             mFrameScheduled = false;
             mLastFrameTimeNanos = frameTimeNanos;
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 7c76bab..0a69772 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -190,6 +190,17 @@
     public static final String DEBUG_SHOW_NON_RECTANGULAR_CLIP_PROPERTY =
             "debug.hwui.show_non_rect_clip";
 
+    /**
+     * Sets the FPS devisor to lower the FPS.
+     *
+     * Sets a positive integer as a divisor. 1 (the default value) menas the full FPS, and 2
+     * means half the full FPS.
+     *
+     *
+     * @hide
+     */
+    public static final String DEBUG_FPS_DIVISOR = "debug.hwui.fps_divisor";
+
     static {
         // Try to check OpenGL support early if possible.
         isAvailable();
@@ -955,6 +966,9 @@
             if (mInitialized) return;
             mInitialized = true;
             mAppContext = context.getApplicationContext();
+
+            // b/68769804: For low FPS experiments.
+            setFPSDivisor(SystemProperties.getInt(DEBUG_FPS_DIVISOR, 1));
             initSched(renderProxy);
             initGraphicsStats();
         }
@@ -1007,6 +1021,13 @@
         observer.mNative = null;
     }
 
+    /** b/68769804: For low FPS experiments. */
+    public static void setFPSDivisor(int divisor) {
+        if (divisor <= 0) divisor = 1;
+        Choreographer.getInstance().setFPSDivisor(divisor);
+        nHackySetRTAnimationsEnabled(divisor == 1);
+    }
+
     /** Not actually public - internal use only. This doc to make lint happy */
     public static native void disableVsync();
 
@@ -1075,4 +1096,6 @@
 
     private static native Bitmap nCreateHardwareBitmap(long renderNode, int width, int height);
     private static native void nSetHighContrastText(boolean enabled);
+    // For temporary experimentation b/66945974
+    private static native void nHackySetRTAnimationsEnabled(boolean enabled);
 }
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 519a885..9f3475a 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -937,6 +937,11 @@
     Properties::enableHighContrastText = enable;
 }
 
+static void android_view_ThreadedRenderer_hackySetRTAnimationsEnabled(JNIEnv*, jclass,
+        jboolean enable) {
+    Properties::enableRTAnimations = enable;
+}
+
 // ----------------------------------------------------------------------------
 // FrameMetricsObserver
 // ----------------------------------------------------------------------------
@@ -1041,6 +1046,8 @@
             (void*)android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode },
     { "disableVsync", "()V", (void*)android_view_ThreadedRenderer_disableVsync },
     { "nSetHighContrastText", "(Z)V", (void*)android_view_ThreadedRenderer_setHighContrastText },
+    { "nHackySetRTAnimationsEnabled", "(Z)V",
+            (void*)android_view_ThreadedRenderer_hackySetRTAnimationsEnabled },
 };
 
 static JavaVM* mJvm = nullptr;
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index d41db63..4243e7e 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -59,6 +59,7 @@
 bool Properties::filterOutTestOverhead = false;
 bool Properties::disableVsync = false;
 bool Properties::skpCaptureEnabled = false;
+bool Properties::enableRTAnimations = true;
 
 static int property_get_int(const char* key, int defaultValue) {
     char buf[PROPERTY_VALUE_MAX] = {
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 9c30e4a..af4b694 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -255,6 +255,9 @@
 
     static bool skpCaptureEnabled;
 
+    // For experimentation b/68769804
+    ANDROID_API static bool enableRTAnimations;
+
     // Used for testing only to change the render pipeline.
     static void overrideRenderPipelineType(RenderPipelineType);
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index b7bb2d15..820789d 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -34,6 +34,7 @@
 #include "renderstate/Stencil.h"
 #include "utils/GLUtils.h"
 #include "utils/TimeUtils.h"
+#include "../Properties.h"
 
 #include <cutils/properties.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -375,6 +376,9 @@
     }
 
     if (info.out.hasAnimations || !info.out.canDrawThisFrame) {
+        if (CC_UNLIKELY(!Properties::enableRTAnimations)) {
+            info.out.requiresUiRedraw = true;
+        }
         if (!info.out.requiresUiRedraw) {
             // If animationsNeedsRedraw is set don't bother posting for an RT anim
             // as we will just end up fighting the UI thread.