Fix stuck scrim on keyguard-less devices

Bug: 22413062
Change-Id: I6da6438ec54d33a1aa82d5575eb29e9bc4dbdd58
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 3393d7d..7f62b00 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -101,7 +101,6 @@
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewConfiguration;
-import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.WindowManagerInternal;
@@ -355,6 +354,7 @@
 
     boolean mSystemReady;
     boolean mSystemBooted;
+    private boolean mDeferBindKeyguard;
     boolean mHdmiPlugged;
     IUiModeManager mUiModeManager;
     int mUiMode;
@@ -5934,6 +5934,7 @@
 
         readCameraLensCoverState();
         updateUiMode();
+        boolean bindKeyguardNow;
         synchronized (mLock) {
             updateOrientationListenerLp();
             mSystemReady = true;
@@ -5943,13 +5944,36 @@
                     updateSettings();
                 }
             });
+
+            bindKeyguardNow = mDeferBindKeyguard;
+            if (bindKeyguardNow) {
+                // systemBooted ran but wasn't able to bind to the Keyguard, we'll do it now.
+                mDeferBindKeyguard = false;
+            }
+        }
+
+        if (bindKeyguardNow) {
+            mKeyguardDelegate.bindService(mContext);
+            mKeyguardDelegate.onBootCompleted();
         }
     }
 
     /** {@inheritDoc} */
     @Override
     public void systemBooted() {
-        if (mKeyguardDelegate != null) {
+        boolean bindKeyguardNow = false;
+        synchronized (mLock) {
+            // Time to bind Keyguard; take care to only bind it once, either here if ready or
+            // in systemReady if not.
+            if (mKeyguardDelegate != null) {
+                bindKeyguardNow = true;
+            } else {
+                // Because mKeyguardDelegate is null, we know that the synchronized block in
+                // systemReady didn't run yet and setting this will actually have an effect.
+                mDeferBindKeyguard = true;
+            }
+        }
+        if (bindKeyguardNow) {
             mKeyguardDelegate.bindService(mContext);
             mKeyguardDelegate.onBootCompleted();
         }
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index b9f132b..1406789 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -37,7 +37,7 @@
     private final KeyguardState mKeyguardState = new KeyguardState();
     private ShowListener mShowListenerWhenConnect;
 
-    /* package */ static final class KeyguardState {
+    private static final class KeyguardState {
         KeyguardState() {
             // Assume keyguard is showing and secure until we know for sure. This is here in
             // the event something checks before the service is actually started.
@@ -119,8 +119,13 @@
             mKeyguardState.showing = false;
             mKeyguardState.showingAndNotOccluded = false;
             mKeyguardState.secure = false;
-            mKeyguardState.deviceHasKeyguard = false;
-            hideScrim();
+            synchronized (mKeyguardState) {
+                // TODO: Fix synchronisation model in this class. The other state in this class
+                // is at least self-healing but a race condition here can lead to the scrim being
+                // stuck on keyguard-less devices.
+                mKeyguardState.deviceHasKeyguard = false;
+                hideScrim();
+            }
         } else {
             if (DEBUG) Log.v(TAG, "*** Keyguard started");
         }
@@ -307,13 +312,15 @@
     }
 
     public void showScrim() {
-        if (!mKeyguardState.deviceHasKeyguard) return;
-        mScrim.post(new Runnable() {
-            @Override
-            public void run() {
-                mScrim.setVisibility(View.VISIBLE);
-            }
-        });
+        synchronized (mKeyguardState) {
+            if (!mKeyguardState.deviceHasKeyguard) return;
+            mScrim.post(new Runnable() {
+                @Override
+                public void run() {
+                    mScrim.setVisibility(View.VISIBLE);
+                }
+            });
+        }
     }
 
     public void hideScrim() {