Adding "quiescent" reboot mechanism to support STB operators

Bug: 31681185
Change-Id: Iada4dd4624f0221e5b59440da2718da980742720
Test: with SampleLeanbackDeviceAdmin.  CTS test forthcoming
diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp
index 48a34e7..dca7ea6 100644
--- a/cmds/bootanimation/bootanimation_main.cpp
+++ b/cmds/bootanimation/bootanimation_main.cpp
@@ -37,6 +37,10 @@
     char value[PROPERTY_VALUE_MAX];
     property_get("debug.sf.nobootanimation", value, "0");
     int noBootAnimation = atoi(value);
+    if (!noBootAnimation) {
+        property_get("ro.boot.quiescent", value, "0");
+        noBootAnimation = atoi(value);
+    }
     ALOGI_IF(noBootAnimation,  "boot animation disabled");
     if (!noBootAnimation) {
 
@@ -47,7 +51,6 @@
         sp<BootAnimation> boot = new BootAnimation();
 
         IPCThreadState::self()->joinThreadPool();
-
     }
     return 0;
 }
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 8d4d0a5..9d04929 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -421,6 +421,12 @@
     public static final String REBOOT_SAFE_MODE = "safemode";
 
     /**
+     * The 'reason' value used when rebooting the device without turning on the screen.
+     * @hide
+     */
+    public static final String REBOOT_QUIESCENT = "quiescent";
+
+    /**
      * The value to pass as the 'reason' argument to android_reboot().
      * @hide
      */
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 1790554..f2ccac5 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -134,6 +134,8 @@
     private static final int DIRTY_DOCK_STATE = 1 << 10;
     // Dirty bit: brightness boost changed
     private static final int DIRTY_SCREEN_BRIGHTNESS_BOOST = 1 << 11;
+    // Dirty bit: sQuiescent changed
+    private static final int DIRTY_QUIESCENT = 1 << 12;
 
     // Summarizes the state of all active wakelocks.
     private static final int WAKE_LOCK_CPU = 1 << 0;
@@ -169,6 +171,9 @@
     // Default setting for double tap to wake.
     private static final int DEFAULT_DOUBLE_TAP_TO_WAKE = 0;
 
+    // System property indicating that the screen should remain off until an explicit user action
+    private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent";
+
     /** Constants for {@link #shutdownOrRebootInternal} */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({HALT_MODE_SHUTDOWN, HALT_MODE_REBOOT, HALT_MODE_REBOOT_SAFE_MODE})
@@ -398,6 +403,9 @@
     // True if the device should stay on.
     private boolean mStayOn;
 
+    // True if the lights should stay off until an explicit user action.
+    private static boolean sQuiescent;
+
     // True if the proximity sensor reads a positive result.
     private boolean mProximityPositive;
 
@@ -530,6 +538,8 @@
 
             mWakefulness = WAKEFULNESS_AWAKE;
 
+            sQuiescent = SystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1");
+
             nativeInit();
             nativeSetAutoSuspend(false);
             nativeSetInteractive(true);
@@ -1190,12 +1200,19 @@
                         && eventTime > mLastUserActivityTime) {
                     mLastUserActivityTimeNoChangeLights = eventTime;
                     mDirty |= DIRTY_USER_ACTIVITY;
+                    if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
+                        mDirty |= DIRTY_QUIESCENT;
+                    }
+
                     return true;
                 }
             } else {
                 if (eventTime > mLastUserActivityTime) {
                     mLastUserActivityTime = eventTime;
                     mDirty |= DIRTY_USER_ACTIVITY;
+                    if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
+                        mDirty |= DIRTY_QUIESCENT;
+                    }
                     return true;
                 }
             }
@@ -2096,7 +2113,7 @@
         final boolean oldDisplayReady = mDisplayReady;
         if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
                 | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
-                | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST)) != 0) {
+                | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_QUIESCENT)) != 0) {
             mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();
 
             // Determine appropriate screen brightness and auto-brightness adjustments.
@@ -2163,6 +2180,9 @@
                     mRequestWaitForNegativeProximity);
             mRequestWaitForNegativeProximity = false;
 
+            if ((dirty & DIRTY_QUIESCENT) != 0) {
+                sQuiescent = false;
+            }
             if (DEBUG_SPEW) {
                 Slog.d(TAG, "updateDisplayPowerStateLocked: mDisplayReady=" + mDisplayReady
                         + ", policy=" + mDisplayPowerRequest.policy
@@ -2170,8 +2190,8 @@
                         + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
                         + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
                         + ", mBootCompleted=" + mBootCompleted
-                        + ", mScreenBrightnessBoostInProgress="
-                                + mScreenBrightnessBoostInProgress);
+                        + ", mScreenBrightnessBoostInProgress=" + mScreenBrightnessBoostInProgress
+                        + ", sQuiescent=" + sQuiescent);
             }
         }
         return mDisplayReady && !oldDisplayReady;
@@ -2210,7 +2230,7 @@
     }
 
     private int getDesiredScreenPolicyLocked() {
-        if (mWakefulness == WAKEFULNESS_ASLEEP) {
+        if (mWakefulness == WAKEFULNESS_ASLEEP || sQuiescent) {
             return DisplayPowerRequest.POLICY_OFF;
         }
 
@@ -2899,10 +2919,25 @@
         }
         if (reason.equals(PowerManager.REBOOT_RECOVERY)
                 || reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) {
-            SystemProperties.set("sys.powerctl", "reboot,recovery");
-        } else {
-            SystemProperties.set("sys.powerctl", "reboot," + reason);
+            reason = "recovery";
         }
+
+        // If the reason is "quiescent", it means that the boot process should proceed
+        // without turning on the screen/lights.
+        // The "quiescent" property is sticky, meaning that any number
+        // of subsequent reboots should honor the property until it is reset.
+        if (reason.equals(PowerManager.REBOOT_QUIESCENT)) {
+            sQuiescent = true;
+            reason = "";
+        }
+
+        if (sQuiescent) {
+            // Pass the optional "quiescent" argument to the bootloader to let it know
+            // that it should not turn the screen/lights on.
+            reason = reason + ",quiescent";
+        }
+
+        SystemProperties.set("sys.powerctl", "reboot," + reason);
         try {
             Thread.sleep(20 * 1000L);
         } catch (InterruptedException e) {