From ba75b774fa45487f820e3a55765ecb9b820d18fc Mon Sep 17 00:00:00 2001 From: Santos Cordon Date: Tue, 15 Mar 2022 10:11:49 +0000 Subject: [PATCH] Add NPE check in ColorFade. There is a delay between when a display is removed in the DisplayManager thread and when the ColorFade is dismissed in the PowerManager thread which can leave ColorFade in a state where its associated display is no longer available. Check for valid display similar to how we are doing in other parts of the ColorFade code. Bug: 220650894 Test: atest ColorFadeTest Change-Id: I75528bf4cd398999e012c3c8d8c53b6ac0ce1552 --- .../com/android/server/display/ColorFade.java | 8 +- .../android/server/display/ColorFadeTest.java | 75 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java index 7cb29215b5bf..cb04ddfd636d 100644 --- a/services/core/java/com/android/server/display/ColorFade.java +++ b/services/core/java/com/android/server/display/ColorFade.java @@ -156,9 +156,15 @@ final class ColorFade { mMode = mode; + DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId); + if (displayInfo == null) { + // displayInfo can be null if the associated display has been removed. There + // is a delay between the display being removed and ColorFade being dismissed. + return false; + } + // Get the display size and layer stack. // This is not expected to change while the color fade surface is showing. - DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId); mDisplayLayerStack = displayInfo.layerStack; mDisplayWidth = displayInfo.getNaturalWidth(); mDisplayHeight = displayInfo.getNaturalHeight(); diff --git a/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java b/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java new file mode 100644 index 000000000000..26a83a23de33 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.hardware.display.DisplayManagerInternal; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.LocalServices; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@Presubmit +@RunWith(AndroidJUnit4.class) +public class ColorFadeTest { + private static final int DISPLAY_ID = 123; + + private Context mContext; + + @Mock private DisplayManagerInternal mDisplayManagerInternalMock; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + addLocalServiceMock(DisplayManagerInternal.class, mDisplayManagerInternalMock); + mContext = getInstrumentation().getTargetContext(); + } + + @After + public void tearDown() { + LocalServices.removeServiceForTest(DisplayManagerInternal.class); + } + + @Test + public void testPrepareColorFadeForInvalidDisplay() { + when(mDisplayManagerInternalMock.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(null); + ColorFade colorFade = new ColorFade(DISPLAY_ID); + assertFalse(colorFade.prepare(mContext, ColorFade.MODE_FADE)); + } + + private static void addLocalServiceMock(Class clazz, T mock) { + LocalServices.removeServiceForTest(clazz); + LocalServices.addService(clazz, mock); + } + +}