Merge "Remove token invalid check for BufferSurfaceFrame" into sc-dev
diff --git a/Android.bp b/Android.bp
index 1393f61..dec6716 100644
--- a/Android.bp
+++ b/Android.bp
@@ -86,3 +86,9 @@
     name: "libandroid_headers_private",
     export_include_dirs: ["include/private"],
 }
+
+filegroup {
+    name: "deviceproductinfoconstants_aidl",
+    srcs: ["aidl/android/hardware/display/IDeviceProductInfoConstants.aidl"],
+    path: "aidl",
+}
diff --git a/aidl/android/hardware/display/IDeviceProductInfoConstants.aidl b/aidl/android/hardware/display/IDeviceProductInfoConstants.aidl
new file mode 100644
index 0000000..7cc272a
--- /dev/null
+++ b/aidl/android/hardware/display/IDeviceProductInfoConstants.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2021 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 android.hardware.display;
+
+/** @hide */
+interface IDeviceProductInfoConstants {
+    /** The device connection to the display sink is unknown. */
+    const int CONNECTION_TO_SINK_UNKNOWN = 0;
+
+    /** The device is built-in in the display sink. */
+    const int CONNECTION_TO_SINK_BUILT_IN = 1;
+
+    /** The device is directly connected to the display sink. */
+    const int CONNECTION_TO_SINK_DIRECT = 2;
+
+    /** The device is transitively connected to the display sink. */
+    const int CONNECTION_TO_SINK_TRANSITIVE = 3;
+}
\ No newline at end of file
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index a7a6563..c20d9f6 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -113,5 +113,14 @@
      * Returns the debug flag for the given package.
      * Unknown packages will cause the call to fail.
      */
-     boolean isPackageDebuggable(in String packageName);
+    boolean isPackageDebuggable(in String packageName);
+
+    /**
+     * Check whether the given feature name and version is one of the available
+     * features as returned by {@link PackageManager#getSystemAvailableFeatures()}. Since
+     * features are defined to always be backwards compatible, this returns true
+     * if the available feature version is greater than or equal to the
+     * requested version.
+     */
+    boolean hasSystemFeature(in String featureName, in int version);
 }
diff --git a/opengl/libs/EGL/egl_angle_platform.cpp b/opengl/libs/EGL/egl_angle_platform.cpp
index dc8e587..c29181d 100644
--- a/opengl/libs/EGL/egl_angle_platform.cpp
+++ b/opengl/libs/EGL/egl_angle_platform.cpp
@@ -129,8 +129,8 @@
         return false;
     }
 
-    angleResetDisplayPlatform = reinterpret_cast<ResetDisplayPlatformFunc>(
-            eglGetProcAddress("ANGLEResetDisplayPlatform"));
+    angleResetDisplayPlatform =
+            reinterpret_cast<ResetDisplayPlatformFunc>(dlsym(so, "ANGLEResetDisplayPlatform"));
 
     PlatformMethods* platformMethods = nullptr;
     if (!((angleGetDisplayPlatform)(dpy, g_PlatformMethodNames, g_NumPlatformMethods, nullptr,
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index d0a5c09..465e8be 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1439,7 +1439,7 @@
     ALOGD("notifySensorEvent eventTime=%" PRId64 ", hwTimestamp=%" PRId64 ", deviceId=%d, "
           "source=0x%x, sensorType=%s",
           entry->eventTime, entry->hwTimestamp, entry->deviceId, entry->source,
-          NamedEnum::string(sensorType).c_str());
+          NamedEnum::string(entry->sensorType).c_str());
 #endif
     std::unique_ptr<CommandEntry> commandEntry =
             std::make_unique<CommandEntry>(&InputDispatcher::doNotifySensorLockedInterruptible);
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index d0a9ca7..1a7fcd5 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1771,7 +1771,17 @@
     }
 }
 
-status_t EventHub::openDeviceLocked(const std::string& devicePath) {
+void EventHub::openDeviceLocked(const std::string& devicePath) {
+    // If an input device happens to register around the time when EventHub's constructor runs, it
+    // is possible that the same input event node (for example, /dev/input/event3) will be noticed
+    // in both 'inotify' callback and also in the 'scanDirLocked' pass. To prevent duplicate devices
+    // from getting registered, ensure that this path is not already covered by an existing device.
+    for (const auto& [deviceId, device] : mDevices) {
+        if (device->path == devicePath) {
+            return; // device was already registered
+        }
+    }
+
     char buffer[80];
 
     ALOGV("Opening device: %s", devicePath.c_str());
@@ -1779,7 +1789,7 @@
     int fd = open(devicePath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
     if (fd < 0) {
         ALOGE("could not open %s, %s\n", devicePath.c_str(), strerror(errno));
-        return -1;
+        return;
     }
 
     InputDeviceIdentifier identifier;
@@ -1798,7 +1808,7 @@
         if (identifier.name == item) {
             ALOGI("ignoring event id %s driver %s\n", devicePath.c_str(), item.c_str());
             close(fd);
-            return -1;
+            return;
         }
     }
 
@@ -1807,7 +1817,7 @@
     if (ioctl(fd, EVIOCGVERSION, &driverVersion)) {
         ALOGE("could not get driver version for %s, %s\n", devicePath.c_str(), strerror(errno));
         close(fd);
-        return -1;
+        return;
     }
 
     // Get device identifier.
@@ -1815,7 +1825,7 @@
     if (ioctl(fd, EVIOCGID, &inputId)) {
         ALOGE("could not get device input id for %s, %s\n", devicePath.c_str(), strerror(errno));
         close(fd);
-        return -1;
+        return;
     }
     identifier.bus = inputId.bustype;
     identifier.product = inputId.product;
@@ -2013,7 +2023,7 @@
     if (device->classes == Flags<InputDeviceClass>(0)) {
         ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath.c_str(),
               device->identifier.name.c_str());
-        return -1;
+        return;
     }
 
     // Classify InputDeviceClass::BATTERY.
@@ -2043,7 +2053,7 @@
     }
 
     if (registerDeviceForEpollLocked(*device) != OK) {
-        return -1;
+        return;
     }
 
     device->configureFd();
@@ -2056,7 +2066,6 @@
           toString(mBuiltInKeyboardId == deviceId));
 
     addDeviceLocked(std::move(device));
-    return OK;
 }
 
 void EventHub::openVideoDeviceLocked(const std::string& devicePath) {
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 4059729..5e5f85e 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -567,7 +567,10 @@
         bool configureLightsLocked();
     };
 
-    status_t openDeviceLocked(const std::string& devicePath);
+    /**
+     * Create a new device for the provided path.
+     */
+    void openDeviceLocked(const std::string& devicePath);
     void openVideoDeviceLocked(const std::string& devicePath);
     /**
      * Try to associate a video device with an input device. If the association succeeds,
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index e027c5e..51f6f5d 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -898,6 +898,8 @@
         mInfo.touchOcclusionMode = mode;
     }
 
+    void setApplicationToken(sp<IBinder> token) { mInfo.applicationInfo.token = token; }
+
     void setFrame(const Rect& frame) {
         mInfo.frameLeft = frame.left;
         mInfo.frameTop = frame.top;
@@ -4266,6 +4268,19 @@
 class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
 protected:
     constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
+
+    constexpr static const float OPACITY_ABOVE_THRESHOLD = 0.9;
+    static_assert(OPACITY_ABOVE_THRESHOLD > MAXIMUM_OBSCURING_OPACITY);
+
+    constexpr static const float OPACITY_BELOW_THRESHOLD = 0.7;
+    static_assert(OPACITY_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
+
+    // When combined twice, ie 1 - (1 - 0.5)*(1 - 0.5) = 0.75 < 8, is still below the threshold
+    constexpr static const float OPACITY_FAR_BELOW_THRESHOLD = 0.5;
+    static_assert(OPACITY_FAR_BELOW_THRESHOLD < MAXIMUM_OBSCURING_OPACITY);
+    static_assert(1 - (1 - OPACITY_FAR_BELOW_THRESHOLD) * (1 - OPACITY_FAR_BELOW_THRESHOLD) <
+                  MAXIMUM_OBSCURING_OPACITY);
+
     static const int32_t TOUCHED_APP_UID = 10001;
     static const int32_t APP_B_UID = 10002;
     static const int32_t APP_C_UID = 10003;
@@ -4321,6 +4336,17 @@
 }
 
 TEST_F(InputDispatcherUntrustedTouchesTest,
+       WindowWithBlockUntrustedOcclusionModeWithOpacityBelowThreshold_BlocksTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.7f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest,
        WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch) {
     const sp<FakeWindowHandle>& w =
             getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
@@ -4415,7 +4441,8 @@
 
 TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
     const sp<FakeWindowHandle>& w =
-            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_BELOW_THRESHOLD);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
 
     touch();
@@ -4436,7 +4463,8 @@
 
 TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) {
     const sp<FakeWindowHandle>& w =
-            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.9f);
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_ABOVE_THRESHOLD);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
 
     touch();
@@ -4447,9 +4475,11 @@
 TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThreshold_BlocksTouch) {
     // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91
     const sp<FakeWindowHandle>& w1 =
-            getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY, 0.7f);
+            getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_BELOW_THRESHOLD);
     const sp<FakeWindowHandle>& w2 =
-            getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY, 0.7f);
+            getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_BELOW_THRESHOLD);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w1, w2, mTouchWindow}}});
 
     touch();
@@ -4460,9 +4490,11 @@
 TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThreshold_AllowsTouch) {
     // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75
     const sp<FakeWindowHandle>& w1 =
-            getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY, 0.5f);
+            getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_FAR_BELOW_THRESHOLD);
     const sp<FakeWindowHandle>& w2 =
-            getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY, 0.5f);
+            getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_FAR_BELOW_THRESHOLD);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w1, w2, mTouchWindow}}});
 
     touch();
@@ -4473,9 +4505,11 @@
 TEST_F(InputDispatcherUntrustedTouchesTest,
        WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch) {
     const sp<FakeWindowHandle>& wB =
-            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_BELOW_THRESHOLD);
     const sp<FakeWindowHandle>& wC =
-            getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY, 0.7f);
+            getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_BELOW_THRESHOLD);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wB, wC, mTouchWindow}}});
 
     touch();
@@ -4485,9 +4519,11 @@
 
 TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch) {
     const sp<FakeWindowHandle>& wB =
-            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_BELOW_THRESHOLD);
     const sp<FakeWindowHandle>& wC =
-            getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY, 0.9f);
+            getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_ABOVE_THRESHOLD);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wB, wC, mTouchWindow}}});
 
     touch();
@@ -4498,9 +4534,11 @@
 TEST_F(InputDispatcherUntrustedTouchesTest,
        WindowWithOpacityAboveThresholdAndSelfWindow_BlocksTouch) {
     const sp<FakeWindowHandle>& wA =
-            getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY, 0.7f);
+            getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_BELOW_THRESHOLD);
     const sp<FakeWindowHandle>& wB =
-            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.9f);
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_ABOVE_THRESHOLD);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wA, wB, mTouchWindow}}});
 
     touch();
@@ -4511,9 +4549,11 @@
 TEST_F(InputDispatcherUntrustedTouchesTest,
        WindowWithOpacityBelowThresholdAndSelfWindow_AllowsTouch) {
     const sp<FakeWindowHandle>& wA =
-            getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY, 0.9f);
+            getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_ABOVE_THRESHOLD);
     const sp<FakeWindowHandle>& wB =
-            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_BELOW_THRESHOLD);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wA, wB, mTouchWindow}}});
 
     touch();
@@ -4523,7 +4563,8 @@
 
 TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_AllowsTouch) {
     const sp<FakeWindowHandle>& w =
-            getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY, 0.9f);
+            getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_ABOVE_THRESHOLD);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
 
     touch();
@@ -4568,7 +4609,59 @@
        OpacityThresholdIs1AndWindowBelowThreshold_AllowsTouch) {
     mDispatcher->setMaximumObscuringOpacityForTouch(1.0f);
     const sp<FakeWindowHandle>& w =
-            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.9f);
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_ABOVE_THRESHOLD);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest,
+       WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromSameApp_BlocksTouch) {
+    const sp<FakeWindowHandle>& w1 =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
+                               OPACITY_BELOW_THRESHOLD);
+    const sp<FakeWindowHandle>& w2 =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_BELOW_THRESHOLD);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w1, w2, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->assertNoEvents();
+}
+
+/**
+ * Window B of BLOCK_UNTRUSTED occlusion mode is enough to block the touch, we're testing that the
+ * addition of another window (C) of USE_OPACITY occlusion mode and opacity below the threshold
+ * (which alone would result in allowing touches) does not affect the blocking behavior.
+ */
+TEST_F(InputDispatcherUntrustedTouchesTest,
+       WindowWithBlockUntrustedModeAndWindowWithOpacityBelowFromDifferentApps_BlocksTouch) {
+    const sp<FakeWindowHandle>& wB =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED,
+                               OPACITY_BELOW_THRESHOLD);
+    const sp<FakeWindowHandle>& wC =
+            getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY,
+                               OPACITY_BELOW_THRESHOLD);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wB, wC, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->assertNoEvents();
+}
+
+/**
+ * This test is testing that a window from a different UID but with same application token doesn't
+ * block the touch. Apps can share the application token for close UI collaboration for example.
+ */
+TEST_F(InputDispatcherUntrustedTouchesTest,
+       WindowWithSameApplicationTokenFromDifferentApp_AllowsTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
+    w->setApplicationToken(mTouchWindow->getApplicationToken());
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
 
     touch();
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 097f7de..a96dffd 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -414,12 +414,6 @@
         return true;
     }
 
-    // If the next planned present time is not current, return and try again later
-    if (frameIsEarly(expectedPresentTime)) {
-        ATRACE_NAME("frameIsEarly()");
-        return false;
-    }
-
     // If this layer doesn't have a frame is shouldn't be presented
     if (!hasFrameUpdate()) {
         return false;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 23758c9..a072554 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -924,6 +924,8 @@
 
     pid_t getOwnerPid() { return mOwnerPid; }
 
+    virtual bool frameIsEarly(nsecs_t /*expectedPresentTime*/) const { return false; }
+
     // This layer is not a clone, but it's the parent to the cloned hierarchy. The
     // variable mClonedChild represents the top layer that will be cloned so this
     // layer will be the parent of mClonedChild.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 31b253c..350a3c8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -496,6 +496,9 @@
     // the window manager died on us. prepare its eulogy.
     mBootFinished = false;
 
+    // Sever the link to inputflinger since its gone as well.
+    static_cast<void>(schedule([=] { mInputFlinger = nullptr; }));
+
     // restore initial conditions (default device unblank, etc)
     initializeDisplays();
 
@@ -3361,6 +3364,10 @@
         if (!layer) {
             continue;
         }
+        if (layer->frameIsEarly(expectedPresentTime)) {
+            ATRACE_NAME("frameIsEarly()");
+            return false;
+        }
 
         if (!mScheduler->isVsyncValid(expectedPresentTime, layer->getOwnerUid())) {
             ATRACE_NAME("!isVsyncValidForUid");
@@ -4945,8 +4952,6 @@
         case GET_DISPLAYED_CONTENT_SAMPLE:
         case NOTIFY_POWER_BOOST:
         case SET_GLOBAL_SHADOW_SETTINGS:
-        case ADD_FPS_LISTENER:
-        case REMOVE_FPS_LISTENER:
         case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
             // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN is used by CTS tests, which acquire the
             // necessary permission dynamically. Don't use the permission cache for this check.
@@ -5009,6 +5014,8 @@
             // This is not sensitive information, so should not require permission control.
             return OK;
         }
+        case ADD_FPS_LISTENER:
+        case REMOVE_FPS_LISTENER:
         case ADD_REGION_SAMPLING_LISTENER:
         case REMOVE_REGION_SAMPLING_LISTENER: {
             // codes that require permission check