Wait for keyguard draw before stopping boot animation
- Add check for keyguard drawn before stopping boot animation.
Otherwise blank screen can happen.
- Bind to keyguard service when sysui is launched to reduce waiting
time later.
- Increase keyguard timeout to 5 secs if it is not boot completed.
Otherwise (= normal screen on), keep the current 1 sec.
This timeout can still lead into blank screen so use bigger timeout
during boot-up to prevent such case.
bug: 37867510
Test: many reboots
Change-Id: Ibfdc42d295bb1d3f5b4ea316fe5aca9ab875e4be
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 030c78b..4cefa45 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -1661,4 +1661,16 @@
public void onConfigurationChanged();
public boolean shouldRotateSeamlessly(int oldRotation, int newRotation);
+
+ /**
+ * Called when System UI has been started.
+ */
+ void onSystemUiStarted();
+
+ /**
+ * Checks whether the policy is ready for dismissing the boot animation and completing the boot.
+ *
+ * @return true if ready; false otherwise.
+ */
+ boolean canDismissBootAnimation();
}
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index 10b2609..72ff606 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -164,6 +164,13 @@
}
}
+ /**
+ * @return true if system has completed the boot; false otherwise.
+ */
+ public boolean isBootCompleted() {
+ return mCurrentPhase >= SystemService.PHASE_BOOT_COMPLETED;
+ }
+
public void startUser(final int userHandle) {
Slog.i(TAG, "Calling onStartUser u" + userHandle);
final int serviceLen = mServices.size();
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8e058ad..8a2c0b1 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -234,6 +234,7 @@
import com.android.internal.widget.PointerLocationView;
import com.android.server.GestureLauncherService;
import com.android.server.LocalServices;
+import com.android.server.SystemServiceManager;
import com.android.server.policy.keyguard.KeyguardServiceDelegate;
import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener;
import com.android.server.policy.keyguard.KeyguardStateMonitor.StateCallback;
@@ -476,6 +477,7 @@
boolean mBootMessageNeedsHiding;
KeyguardServiceDelegate mKeyguardDelegate;
+ private boolean mKeyguardBound;
final Runnable mWindowManagerDrawCallback = new Runnable() {
@Override
public void run() {
@@ -530,7 +532,6 @@
boolean mSystemReady;
boolean mSystemBooted;
- private boolean mDeferBindKeyguard;
boolean mHdmiPlugged;
HdmiControl mHdmiControl;
IUiModeManager mUiModeManager;
@@ -2087,6 +2088,13 @@
handleStartTransitionForKeyguardLw(transit, null /* transit */);
}
});
+ mKeyguardDelegate = new KeyguardServiceDelegate(mContext,
+ new StateCallback() {
+ @Override
+ public void onTrustedChanged() {
+ mWindowManagerFuncs.notifyKeyguardTrustedChanged();
+ }
+ });
}
/**
@@ -6631,6 +6639,13 @@
reportScreenStateToVrManager(false);
}
+ private long getKeyguardDrawnTimeout() {
+ final boolean bootCompleted =
+ LocalServices.getService(SystemServiceManager.class).isBootCompleted();
+ // Set longer timeout if it has not booted yet to prevent showing empty window.
+ return bootCompleted ? 1000 : 5000;
+ }
+
// Called on the DisplayManager's DisplayPowerController thread.
@Override
public void screenTurningOn(final ScreenOnListener screenOnListener) {
@@ -6646,7 +6661,8 @@
if (mKeyguardDelegate != null) {
mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
- mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT, 1000);
+ mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,
+ getKeyguardDrawnTimeout());
mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
} else {
if (DEBUG_WAKEUP) Slog.d(TAG,
@@ -7154,16 +7170,26 @@
return out;
}
+ private void bindKeyguard() {
+ synchronized (mLock) {
+ if (mKeyguardBound) {
+ return;
+ }
+ mKeyguardBound = true;
+ }
+ mKeyguardDelegate.bindService(mContext);
+ }
+
+ @Override
+ public void onSystemUiStarted() {
+ bindKeyguard();
+ }
+
/** {@inheritDoc} */
@Override
public void systemReady() {
- mKeyguardDelegate = new KeyguardServiceDelegate(mContext,
- new StateCallback() {
- @Override
- public void onTrustedChanged() {
- mWindowManagerFuncs.notifyKeyguardTrustedChanged();
- }
- });
+ // In normal flow, systemReady is called before other system services are ready.
+ // So it is better not to bind keyguard here.
mKeyguardDelegate.onSystemReady();
mVrManagerInternal = LocalServices.getService(VrManagerInternal.class);
@@ -7173,7 +7199,6 @@
readCameraLensCoverState();
updateUiMode();
- boolean bindKeyguardNow;
synchronized (mLock) {
updateOrientationListenerLp();
mSystemReady = true;
@@ -7183,18 +7208,13 @@
updateSettings();
}
});
-
- bindKeyguardNow = mDeferBindKeyguard;
- if (bindKeyguardNow) {
- // systemBooted ran but wasn't able to bind to the Keyguard, we'll do it now.
- mDeferBindKeyguard = false;
+ // If this happens, for whatever reason, systemReady came later than systemBooted.
+ // And keyguard should be already bound from systemBooted
+ if (mSystemBooted) {
+ mKeyguardDelegate.onBootCompleted();
}
}
- if (bindKeyguardNow) {
- mKeyguardDelegate.bindService(mContext);
- mKeyguardDelegate.onBootCompleted();
- }
mSystemGestures.systemReady();
mImmersiveModeConfirmation.systemReady();
}
@@ -7202,30 +7222,25 @@
/** {@inheritDoc} */
@Override
public void systemBooted() {
- 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();
- }
+ bindKeyguard();
synchronized (mLock) {
mSystemBooted = true;
+ if (mSystemReady) {
+ mKeyguardDelegate.onBootCompleted();
+ }
}
startedWakingUp();
screenTurningOn(null);
screenTurnedOn();
}
+ @Override
+ public boolean canDismissBootAnimation() {
+ synchronized (mLock) {
+ return mKeyguardDrawComplete;
+ }
+ }
+
ProgressDialog mBootMsgDialog = null;
/** {@inheritDoc} */
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c8eb98c..109b340 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3335,6 +3335,13 @@
performEnableScreen();
}
+ /**
+ * Called when System UI has been started.
+ */
+ public void onSystemUiStarted() {
+ mPolicy.onSystemUiStarted();
+ }
+
private void performEnableScreen() {
synchronized(mWindowMap) {
if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
@@ -3350,6 +3357,10 @@
return;
}
+ if (!mShowingBootMessages && !mPolicy.canDismissBootAnimation()) {
+ return;
+ }
+
// Don't enable the screen until all existing windows have been drawn.
if (!mForceDisplayEnabled
// TODO(multidisplay): Expand to all displays?
@@ -3363,7 +3374,7 @@
try {
IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
if (surfaceFlinger != null) {
- //Slog.i(TAG_WM, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
+ Slog.i(TAG_WM, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0965f03..b620b3e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1644,6 +1644,7 @@
final MediaRouterService mediaRouterF = mediaRouter;
final MmsServiceBroker mmsServiceF = mmsService;
final IpSecService ipSecServiceF = ipSecService;
+ final WindowManagerService windowManagerF = wm;
// We now tell the activity manager it is okay to run third party
// code. It will call back into us once it has gotten to the state
@@ -1683,7 +1684,7 @@
traceBeginAndSlog("StartSystemUI");
try {
- startSystemUi(context);
+ startSystemUi(context, windowManagerF);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
@@ -1837,13 +1838,14 @@
}, BOOT_TIMINGS_TRACE_LOG);
}
- static final void startSystemUi(Context context) {
+ static final void startSystemUi(Context context, WindowManagerService windowManager) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
+ windowManager.onSystemUiStarted();
}
private static void traceBeginAndSlog(String name) {
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index be53667..9af4b4c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -632,5 +632,14 @@
@Override
public void setRecentsVisibilityLw(boolean visible) {
- }
+ }
+
+ @Override
+ public void onSystemUiStarted() {
+ }
+
+ @Override
+ public boolean canDismissBootAnimation() {
+ return true;
+ }
}