Merge "Declare new AAC struct for MPEG-4 / MPEG-D DRC parameters"
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index eeb8330..c30dcfe 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -425,12 +425,15 @@
  * valid refresh rate for this device's display - e.g., it's fine to pass 30fps to a device that can
  * only run the display at 60fps.
  *
+ * |compatibility| The frame rate compatibility of this surface. The compatibility value may
+ * influence the system's choice of display frame rate. To specify a compatibility use the
+ * ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* enum.
+ *
  * Available since API level 30.
  */
 void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction,
-                                      ASurfaceControl* surface_control,
-                                      float frameRate)
-                                      __INTRODUCED_IN(30);
+                                      ASurfaceControl* surface_control, float frameRate,
+                                      int8_t compatibility) __INTRODUCED_IN(30);
 
 #endif // __ANDROID_API__ >= 30
 
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 2f27fd2..ce41eab 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -1112,6 +1112,42 @@
         }
         return NO_ERROR;
     }
+
+    virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
+                                  int8_t compatibility) {
+        Parcel data, reply;
+        status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (err != NO_ERROR) {
+            ALOGE("setFrameRate: failed writing interface token: %s (%d)", strerror(-err), -err);
+            return err;
+        }
+
+        err = data.writeStrongBinder(IInterface::asBinder(surface));
+        if (err != NO_ERROR) {
+            ALOGE("setFrameRate: failed writing strong binder: %s (%d)", strerror(-err), -err);
+            return err;
+        }
+
+        err = data.writeFloat(frameRate);
+        if (err != NO_ERROR) {
+            ALOGE("setFrameRate: failed writing float: %s (%d)", strerror(-err), -err);
+            return err;
+        }
+
+        err = data.writeByte(compatibility);
+        if (err != NO_ERROR) {
+            ALOGE("setFrameRate: failed writing byte: %s (%d)", strerror(-err), -err);
+            return err;
+        }
+
+        err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply,
+                                 IBinder::FLAG_ONEWAY);
+        if (err != NO_ERROR) {
+            ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err);
+            return err;
+        }
+        return NO_ERROR;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -1877,6 +1913,36 @@
             return setGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ,
                                            lightRadius);
         }
+        case SET_FRAME_RATE: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> binder;
+            status_t err = data.readStrongBinder(&binder);
+            if (err != NO_ERROR) {
+                ALOGE("setFrameRate: failed to read strong binder: %s (%d)", strerror(-err), -err);
+                return err;
+            }
+            sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(binder);
+            if (!surface) {
+                ALOGE("setFrameRate: failed to cast to IGraphicBufferProducer: %s (%d)",
+                      strerror(-err), -err);
+                return err;
+            }
+            float frameRate;
+            err = data.readFloat(&frameRate);
+            if (err != NO_ERROR) {
+                ALOGE("setFrameRate: failed to read float: %s (%d)", strerror(-err), -err);
+                return err;
+            }
+            int8_t compatibility;
+            err = data.readByte(&compatibility);
+            if (err != NO_ERROR) {
+                ALOGE("setFrameRate: failed to read byte: %s (%d)", strerror(-err), -err);
+                return err;
+            }
+            status_t result = setFrameRate(surface, frameRate, compatibility);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 5547efc..a9c9b74 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -24,6 +24,8 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/LayerState.h>
 
+#include <cmath>
+
 namespace android {
 
 status_t layer_state_t::write(Parcel& output) const
@@ -113,6 +115,7 @@
     output.writeFloat(shadowRadius);
     output.writeInt32(frameRateSelectionPriority);
     output.writeFloat(frameRate);
+    output.writeByte(frameRateCompatibility);
     return NO_ERROR;
 }
 
@@ -194,6 +197,7 @@
     shadowRadius = input.readFloat();
     frameRateSelectionPriority = input.readInt32();
     frameRate = input.readFloat();
+    frameRateCompatibility = input.readByte();
     return NO_ERROR;
 }
 
@@ -427,6 +431,7 @@
     if (other.what & eFrameRateChanged) {
         what |= eFrameRateChanged;
         frameRate = other.frameRate;
+        frameRateCompatibility = other.frameRateCompatibility;
     }
     if ((other.what & what) != other.what) {
         ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
@@ -474,4 +479,21 @@
     syncInputWindows = input.readBool();
 }
 
+bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunctionName) {
+    const char* functionName = inFunctionName != nullptr ? inFunctionName : "call";
+    int floatClassification = std::fpclassify(frameRate);
+    if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) {
+        ALOGE("%s failed - invalid frame rate %f", functionName, frameRate);
+        return false;
+    }
+
+    if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT &&
+        compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE) {
+        ALOGE("%s failed - invalid compatibility value %d", functionName, compatibility);
+        return false;
+    }
+
+    return true;
+}
+
 }; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 278cc59..f911e70 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -43,6 +43,7 @@
 #include <gui/IProducerListener.h>
 
 #include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
 #include <private/gui/ComposerService.h>
 
 namespace android {
@@ -1413,7 +1414,8 @@
 
 int Surface::dispatchSetFrameRate(va_list args) {
     float frameRate = static_cast<float>(va_arg(args, double));
-    return setFrameRate(frameRate);
+    int8_t compatibility = static_cast<int8_t>(va_arg(args, int));
+    return setFrameRate(frameRate, compatibility);
 }
 
 int Surface::dispatchAddCancelInterceptor(va_list args) {
@@ -2222,11 +2224,15 @@
     mSurfaceListener->onBuffersDiscarded(discardedBufs);
 }
 
-status_t Surface::setFrameRate(float frameRate) {
+status_t Surface::setFrameRate(float frameRate, int8_t compatibility) {
     ATRACE_CALL();
-    ALOGV("Surface::setTargetFrameRate");
-    Mutex::Autolock lock(mMutex);
-    return mGraphicBufferProducer->setFrameRate(frameRate);
+    ALOGV("Surface::setFrameRate");
+
+    if (!ValidateFrameRate(frameRate, compatibility, "Surface::setFrameRate")) {
+        return BAD_VALUE;
+    }
+
+    return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility);
 }
 
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index ff8b719..dc4860a 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1387,14 +1387,19 @@
 }
 
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate(
-        const sp<SurfaceControl>& sc, float frameRate) {
+        const sp<SurfaceControl>& sc, float frameRate, int8_t compatibility) {
     layer_state_t* s = getLayerState(sc);
     if (!s) {
         mStatus = BAD_INDEX;
         return *this;
     }
+    if (!ValidateFrameRate(frameRate, compatibility, "Transaction::setFrameRate")) {
+        mStatus = BAD_VALUE;
+        return *this;
+    }
     s->what |= layer_state_t::eFrameRateChanged;
     s->frameRate = frameRate;
+    s->frameRateCompatibility = compatibility;
     return *this;
 }
 
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index e860f61..0659f0d 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -500,6 +500,12 @@
     virtual status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
                                              float lightPosY, float lightPosZ,
                                              float lightRadius) = 0;
+
+    /*
+     * Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info.
+     */
+    virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
+                                  int8_t compatibility) = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -557,6 +563,7 @@
         SET_AUTO_LOW_LATENCY_MODE,
         GET_GAME_CONTENT_TYPE_SUPPORT,
         SET_GAME_CONTENT_TYPE,
+        SET_FRAME_RATE,
         // Always append new enum to the end.
     };
 
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 2d53b48..7e3d5d5 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -20,8 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/Errors.h>
-
+#include <android/native_window.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/ITransactionCompletedListener.h>
 #include <math/mat4.h>
@@ -36,6 +35,7 @@
 #include <ui/Rect.h>
 #include <ui/Region.h>
 #include <ui/Rotation.h>
+#include <utils/Errors.h>
 
 namespace android {
 
@@ -135,7 +135,8 @@
             colorSpaceAgnostic(false),
             shadowRadius(0.0f),
             frameRateSelectionPriority(-1),
-            frameRate(0.0f) {
+            frameRate(0.0f),
+            frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) {
         matrix.dsdx = matrix.dtdy = 1.0f;
         matrix.dsdy = matrix.dtdx = 0.0f;
         hdrMetadata.validTypes = 0;
@@ -221,7 +222,9 @@
     // Priority of the layer assigned by Window Manager.
     int32_t frameRateSelectionPriority;
 
+    // Layer frame rate and compatibility. See ANativeWindow_setFrameRate().
     float frameRate;
+    int8_t frameRateCompatibility;
 };
 
 struct ComposerState {
@@ -292,6 +295,12 @@
     return compare_type(lhs.token, rhs.token);
 }
 
+// Returns true if the frameRate and compatibility are valid values, false
+// othwerise. If either of the params are invalid, an error log is printed, and
+// functionName is added to the log to indicate which function call failed.
+// functionName can be null.
+bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* functionName);
+
 }; // namespace android
 
 #endif // ANDROID_SF_LAYER_STATE_H
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 4a353fc..ad7cbfe 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -179,7 +179,7 @@
     status_t getConsumerUsage(uint64_t* outUsage) const;
 
     // See IGraphicBufferProducer::setFrameRate
-    status_t setFrameRate(float frameRate);
+    status_t setFrameRate(float frameRate, int8_t compatibility);
 
 protected:
     virtual ~Surface();
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 27877bb..0cf141d 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -519,7 +519,8 @@
                 const Rect& source, const Rect& dst, int transform);
         Transaction& setShadowRadius(const sp<SurfaceControl>& sc, float cornerRadius);
 
-        Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate);
+        Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate,
+                                  int8_t compatibility);
 
         status_t setDisplaySurface(const sp<IBinder>& token,
                 const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 70fd888..8c0f8f8 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -854,6 +854,11 @@
         return NO_ERROR;
     }
 
+    status_t setFrameRate(const sp<IGraphicBufferProducer>& /*surface*/, float /*frameRate*/,
+                          int8_t /*compatibility*/) override {
+        return NO_ERROR;
+    }
+
 protected:
     IBinder* onAsBinder() override { return nullptr; }
 
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 98b76fd..fd1793b 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -158,11 +158,11 @@
     return query(window, NATIVE_WINDOW_DATASPACE);
 }
 
-int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) {
-    if (!window || !query(window, NATIVE_WINDOW_IS_VALID) || frameRate < 0) {
+int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) {
+    if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) {
         return -EINVAL;
     }
-    return native_window_set_frame_rate(window, frameRate);
+    return native_window_set_frame_rate(window, frameRate, compatibility);
 }
 
 void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) {
@@ -335,7 +335,3 @@
                                             void* data) {
     return window->perform(window, NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR, interceptor, data);
 }
-
-int64_t ANativeWindow_getNextFrameId(ANativeWindow* window) {
-    return query64(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID);
-}
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 4b426c5..59aa665 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -33,6 +33,7 @@
 #ifndef ANDROID_NATIVE_WINDOW_H
 #define ANDROID_NATIVE_WINDOW_H
 
+#include <stdint.h>
 #include <sys/cdefs.h>
 
 #include <android/data_space.h>
@@ -232,6 +233,24 @@
 
 #if __ANDROID_API__ >= 30
 
+/* Parameter for ANativeWindow_setFrameRate */
+enum {
+    /**
+     * There are no inherent restrictions on the frame rate of this window.
+     */
+    ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT = 0,
+    /**
+     * This window is being used to display content with an inherently fixed
+     * frame rate, e.g. a video that has a specific frame rate. When the system
+     * selects a frame rate other than what the app requested, the app will need
+     * to do pull down or use some other technique to adapt to the system's
+     * frame rate. The user experience is likely to be worse (e.g. more frame
+     * stuttering) than it would be if the system had chosen the app's requested
+     * frame rate.
+     */
+    ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1
+};
+
 /**
  * Sets the intended frame rate for this window.
  *
@@ -257,9 +276,15 @@
  * refresh rate for this device's display - e.g., it's fine to pass 30fps to a
  * device that can only run the display at 60fps.
  *
- * \return 0 for success, -EINVAL if the window or frame rate are invalid.
+ * \param compatibility The frame rate compatibility of this window. The
+ * compatibility value may influence the system's choice of display refresh
+ * rate. See the ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* values for more info.
+ *
+ * \return 0 for success, -EINVAL if the window, frame rate, or compatibility
+ * value are invalid.
  */
-int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) __INTRODUCED_IN(30);
+int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility)
+        __INTRODUCED_IN(30);
 
 /**
  * Provides a hint to the window that buffers should be preallocated ahead of
diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h
index 02b886c..2d1354c 100644
--- a/libs/nativewindow/include/apex/window.h
+++ b/libs/nativewindow/include/apex/window.h
@@ -173,25 +173,22 @@
 /**
  * Retrieves how long it took for the last time a buffer was dequeued.
  *
- * \return a negative value on error, otherwise returns the duration in
- * nanoseconds
+ * \return the dequeue duration in nanoseconds
  */
 int64_t ANativeWindow_getLastDequeueDuration(ANativeWindow* window);
 
 /**
  * Retrieves how long it took for the last time a buffer was queued.
  *
- * \return a negative value on error, otherwise returns the duration in
- * nanoseconds.
+ * \return the queue duration in nanoseconds
  */
 int64_t ANativeWindow_getLastQueueDuration(ANativeWindow* window);
 
 /**
  * Retrieves the system time in nanoseconds when the last time a buffer
- * was dequeued.
+ * started to be dequeued.
  *
- * \return a negative value on error, otherwise returns the duration in
- * nanoseconds.
+ * \return the start time in nanoseconds
  */
 int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window);
 
@@ -200,23 +197,14 @@
  * made by the window will return -ETIMEDOUT after the timeout if the dequeue
  * takes too long.
  *
- * \return NO_ERROR on success, -errno on error.
+ * If the provided timeout is negative, hen this removes the previously configured
+ * timeout. The window then behaves as if ANativeWindow_setDequeueTimeout was
+ * never called.
+ *
+ * \return NO_ERROR on success
+ * \return BAD_VALUE if the dequeue timeout was unabled to be updated, as
+ * updating the dequeue timeout may change internals of the underlying window.
  */
 int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout);
 
-/**
- * Provides a hint to the window that buffers should be preallocated ahead of
- * time. Note that the window implementation is not guaranteed to preallocate
- * any buffers, for instance if a private API disallows allocation of new
- * buffers. As such no success/error status is returned.
- */
-void ANativeWindow_allocateBuffers(ANativeWindow* window);
-
-/**
- * Retrieves an identifier for the next frame to be queued by this window.
- *
- * \return -errno on error, otherwise returns the next frame id.
- */
-int64_t ANativeWindow_getNextFrameId(ANativeWindow* window);
-
 __END_DECLS
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index f686147..869ca9e 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1015,8 +1015,10 @@
     return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation);
 }
 
-static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate) {
-    return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate);
+static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate,
+                                               int8_t compatibility) {
+    return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate,
+                           (int)compatibility);
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -1049,4 +1051,15 @@
                            outTransformMatrix);
 }
 
+/**
+ * Retrieves an identifier for the next frame to be queued by this window.
+ *
+ * \return the next frame id.
+ */
+static inline int64_t ANativeWindow_getNextFrameId(ANativeWindow* window) {
+    int64_t value;
+    window->perform(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID, &value);
+    return value;
+}
+
 __END_DECLS
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 154eb8e..1b5d20d 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -25,7 +25,6 @@
     ANativeWindow_getLastDequeueDuration; # apex # introduced=30
     ANativeWindow_getLastDequeueStartTime; # apex # introduced=30
     ANativeWindow_getLastQueueDuration; # apex # introduced=30
-    ANativeWindow_getNextFrameId; # apex # introduced=30
     ANativeWindow_getWidth;
     ANativeWindow_lock;
     ANativeWindow_query; # llndk
@@ -46,9 +45,9 @@
     ANativeWindow_setBuffersTimestamp; # llndk
     ANativeWindow_setBuffersTransform;
     ANativeWindow_setDequeueTimeout; # apex # introduced=30
+    ANativeWindow_setFrameRate; # introduced=30
     ANativeWindow_setSharedBufferMode; # llndk
     ANativeWindow_setSwapInterval; # llndk
-    ANativeWindow_setFrameRate; # introduced=30
     ANativeWindow_setUsage; # llndk
     ANativeWindow_tryAllocateBuffers; # introduced=30
     ANativeWindow_unlockAndPost;
diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp
index 385b981..066a816 100644
--- a/services/inputflinger/benchmarks/Android.bp
+++ b/services/inputflinger/benchmarks/Android.bp
@@ -7,6 +7,7 @@
     shared_libs: [
         "libbase",
         "libbinder",
+        "libcrypto",
         "libcutils",
         "libinput",
         "libinputflinger_base",
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index b723654..c4b3789 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -57,6 +57,32 @@
     }
     return StringPrintf("%" PRId32, action);
 }
+VerifiedKeyEvent verifiedKeyEventFromKeyEntry(const KeyEntry& entry) {
+    return {{VerifiedInputEvent::Type::KEY, entry.deviceId, entry.eventTime, entry.source,
+             entry.displayId},
+            entry.action,
+            entry.downTime,
+            entry.flags & VERIFIED_KEY_EVENT_FLAGS,
+            entry.keyCode,
+            entry.scanCode,
+            entry.metaState,
+            entry.repeatCount};
+}
+
+VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry) {
+    const float rawX = entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
+    const float rawY = entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
+    const int actionMasked = entry.action & AMOTION_EVENT_ACTION_MASK;
+    return {{VerifiedInputEvent::Type::MOTION, entry.deviceId, entry.eventTime, entry.source,
+             entry.displayId},
+            rawX,
+            rawY,
+            actionMasked,
+            entry.downTime,
+            entry.flags & VERIFIED_MOTION_EVENT_FLAGS,
+            entry.metaState,
+            entry.buttonState};
+}
 
 // --- EventEntry ---
 
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index e8c37f0..b5b61cc 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -220,6 +220,9 @@
     static uint32_t nextSeq();
 };
 
+VerifiedKeyEvent verifiedKeyEventFromKeyEntry(const KeyEntry& entry);
+VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry);
+
 class InputDispatcher;
 // A command entry captures state and behavior for an action to be performed in the
 // dispatch loop after the initial processing has taken place.  It is essentially
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 75bc0aa..f9a86dd 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2433,12 +2433,16 @@
         switch (eventEntry->type) {
             case EventEntry::Type::KEY: {
                 KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
+                VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEntry(*keyEntry);
+                verifiedEvent.flags = dispatchEntry->resolvedFlags & VERIFIED_KEY_EVENT_FLAGS;
+                verifiedEvent.action = dispatchEntry->resolvedAction;
+                std::array<uint8_t, 32> hmac = mHmacKeyManager.sign(verifiedEvent);
 
                 // Publish the key event.
                 status = connection->inputPublisher
                                  .publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId,
                                                   keyEntry->source, keyEntry->displayId,
-                                                  INVALID_HMAC, dispatchEntry->resolvedAction,
+                                                  std::move(hmac), dispatchEntry->resolvedAction,
                                                   dispatchEntry->resolvedFlags, keyEntry->keyCode,
                                                   keyEntry->scanCode, keyEntry->metaState,
                                                   keyEntry->repeatCount, keyEntry->downTime,
@@ -2482,12 +2486,18 @@
                         usingCoords = scaledCoords;
                     }
                 }
+                VerifiedMotionEvent verifiedEvent =
+                        verifiedMotionEventFromMotionEntry(*motionEntry);
+                verifiedEvent.actionMasked =
+                        dispatchEntry->resolvedAction & AMOTION_EVENT_ACTION_MASK;
+                verifiedEvent.flags = dispatchEntry->resolvedFlags & VERIFIED_MOTION_EVENT_FLAGS;
+                std::array<uint8_t, 32> hmac = mHmacKeyManager.sign(verifiedEvent);
 
                 // Publish the motion event.
                 status = connection->inputPublisher
                                  .publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId,
                                                      motionEntry->source, motionEntry->displayId,
-                                                     INVALID_HMAC, dispatchEntry->resolvedAction,
+                                                     std::move(hmac), dispatchEntry->resolvedAction,
                                                      motionEntry->actionButton,
                                                      dispatchEntry->resolvedFlags,
                                                      motionEntry->edgeFlags, motionEntry->metaState,
@@ -3392,7 +3402,36 @@
 }
 
 std::unique_ptr<VerifiedInputEvent> InputDispatcher::verifyInputEvent(const InputEvent& event) {
-    return nullptr;
+    std::array<uint8_t, 32> calculatedHmac;
+    std::unique_ptr<VerifiedInputEvent> result;
+    switch (event.getType()) {
+        case AINPUT_EVENT_TYPE_KEY: {
+            const KeyEvent& keyEvent = static_cast<const KeyEvent&>(event);
+            VerifiedKeyEvent verifiedKeyEvent = verifiedKeyEventFromKeyEvent(keyEvent);
+            result = std::make_unique<VerifiedKeyEvent>(verifiedKeyEvent);
+            calculatedHmac = mHmacKeyManager.sign(verifiedKeyEvent);
+            break;
+        }
+        case AINPUT_EVENT_TYPE_MOTION: {
+            const MotionEvent& motionEvent = static_cast<const MotionEvent&>(event);
+            VerifiedMotionEvent verifiedMotionEvent =
+                    verifiedMotionEventFromMotionEvent(motionEvent);
+            result = std::make_unique<VerifiedMotionEvent>(verifiedMotionEvent);
+            calculatedHmac = mHmacKeyManager.sign(verifiedMotionEvent);
+            break;
+        }
+        default: {
+            ALOGE("Cannot verify events of type %" PRId32, event.getType());
+            return nullptr;
+        }
+    }
+    if (calculatedHmac == INVALID_HMAC) {
+        return nullptr;
+    }
+    if (calculatedHmac != event.getHmac()) {
+        return nullptr;
+    }
+    return result;
 }
 
 bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index ded59a5..482133e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -217,6 +217,8 @@
     // the pointer stream in order to claim it for a system gesture.
     std::unordered_map<int32_t, std::vector<Monitor>> mGestureMonitorsByDisplay GUARDED_BY(mLock);
 
+    HmacKeyManager mHmacKeyManager;
+
     // Event injection and synchronization.
     std::condition_variable mInjectionResultAvailable;
     bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index c4092cd..2fb1b65 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -1398,6 +1398,44 @@
     window->assertNoEvents();
 }
 
+TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> window =
+            new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+
+    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+    window->setFocus(true);
+
+    mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+    window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
+
+    NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
+    mDispatcher->notifyKey(&keyArgs);
+
+    InputEvent* event = window->consume();
+    ASSERT_NE(event, nullptr);
+
+    std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
+    ASSERT_NE(verified, nullptr);
+    ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY);
+
+    ASSERT_EQ(keyArgs.eventTime, verified->eventTimeNanos);
+    ASSERT_EQ(keyArgs.deviceId, verified->deviceId);
+    ASSERT_EQ(keyArgs.source, verified->source);
+    ASSERT_EQ(keyArgs.displayId, verified->displayId);
+
+    const VerifiedKeyEvent& verifiedKey = static_cast<const VerifiedKeyEvent&>(*verified);
+
+    ASSERT_EQ(keyArgs.action, verifiedKey.action);
+    ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos);
+    ASSERT_EQ(keyArgs.eventTime, verifiedKey.eventTimeNanos);
+    ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags);
+    ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode);
+    ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode);
+    ASSERT_EQ(keyArgs.metaState, verifiedKey.metaState);
+    ASSERT_EQ(0, verifiedKey.repeatCount);
+}
+
 /* Test InputDispatcher for MultiDisplay */
 class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
 public:
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e65064b..f5a99ca 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -124,18 +124,6 @@
     return isDue || !isPlausible;
 }
 
-bool BufferQueueLayer::setFrameRate(FrameRate frameRate) {
-    float oldFrameRate = 0.f;
-    status_t result = mConsumer->getFrameRate(&oldFrameRate);
-    bool frameRateChanged = result < 0 || frameRate.rate != oldFrameRate;
-    mConsumer->setFrameRate(frameRate.rate);
-    return frameRateChanged;
-}
-
-Layer::FrameRate BufferQueueLayer::getFrameRate() const {
-    return FrameRate(mLatchedFrameRate, Layer::FrameRateCompatibility::Default);
-}
-
 // -----------------------------------------------------------------------
 // Interface implementation for BufferLayer
 // -----------------------------------------------------------------------
@@ -578,7 +566,6 @@
     mBufferInfo.mTransformToDisplayInverse = mConsumer->getTransformToDisplayInverse();
     float latchedFrameRate;
     mConsumer->getFrameRate(&latchedFrameRate);
-    mLatchedFrameRate = latchedFrameRate;
 }
 
 sp<Layer> BufferQueueLayer::createClone() {
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 626af4b..5f7587c 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -56,9 +56,6 @@
 
     bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
 
-    bool setFrameRate(FrameRate frameRate) override;
-    FrameRate getFrameRate() const override;
-
     // -----------------------------------------------------------------------
 
     // -----------------------------------------------------------------------
@@ -155,8 +152,6 @@
     std::atomic<bool> mSidebandStreamChanged{false};
 
     sp<ContentsChangedListener> mContentsChangedListener;
-
-    std::atomic<float> mLatchedFrameRate = 0.f;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index da26a37..d7647d7 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -26,6 +26,7 @@
 #include "Layer.h"
 
 #include <android-base/stringprintf.h>
+#include <android/native_window.h>
 #include <binder/IPCThreadState.h>
 #include <compositionengine/Display.h>
 #include <compositionengine/LayerFECompositionState.h>
@@ -2446,6 +2447,18 @@
     layer->mDrawingParent = this;
 }
 
+Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t compatibility) {
+    switch (compatibility) {
+        case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT:
+            return FrameRateCompatibility::Default;
+        case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE:
+            return FrameRateCompatibility::ExactOrMultiple;
+        default:
+            LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility);
+            return FrameRateCompatibility::Default;
+    }
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 37ae340..5d2144a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -161,6 +161,10 @@
         }
 
         bool operator!=(const FrameRate& other) const { return !(*this == other); }
+
+        // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a
+        // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid.
+        static FrameRateCompatibility convertCompatibility(int8_t compatibility);
     };
 
     struct State {
@@ -795,7 +799,7 @@
      */
     Rect getCroppedBufferSize(const Layer::State& s) const;
 
-    virtual bool setFrameRate(FrameRate frameRate);
+    bool setFrameRate(FrameRate frameRate);
     virtual FrameRate getFrameRate() const;
 
 protected:
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index bc0111b..a8e6756 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -180,4 +180,3 @@
     mActiveLayersEnd = 0;
 }
 } // namespace android::scheduler::impl
-
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index dcbd934..fbebea0 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -34,6 +34,8 @@
 #include <optional>
 #include <unordered_map>
 
+#include <android/native_window.h>
+
 #include <cutils/properties.h>
 #include <log/log.h>
 
@@ -58,6 +60,7 @@
 #include <gui/IProducerListener.h>
 #include <gui/LayerDebugInfo.h>
 #include <gui/LayerMetadata.h>
+#include <gui/LayerState.h>
 #include <gui/Surface.h>
 #include <input/IInputFlinger.h>
 #include <renderengine/RenderEngine.h>
@@ -3599,9 +3602,13 @@
         }
     }
     if (what & layer_state_t::eFrameRateChanged) {
-        if (layer->setFrameRate(
-                    Layer::FrameRate(s.frameRate, Layer::FrameRateCompatibility::Default)))
+        if (ValidateFrameRate(s.frameRate, s.frameRateCompatibility,
+                              "SurfaceFlinger::setClientStateLocked") &&
+            layer->setFrameRate(Layer::FrameRate(s.frameRate,
+                                                 Layer::FrameRate::convertCompatibility(
+                                                         s.frameRateCompatibility)))) {
             flags |= eTraversalNeeded;
+        }
     }
     // This has to happen after we reparent children because when we reparent to null we remove
     // child layers from current state and remove its relative z. If the children are reparented in
@@ -4699,6 +4706,9 @@
         case GET_COMPOSITION_PREFERENCE:
         case GET_PROTECTED_CONTENT_SUPPORT:
         case IS_WIDE_COLOR_DISPLAY:
+        // setFrameRate() is deliberately available for apps to call without any
+        // special permissions.
+        case SET_FRAME_RATE:
         case GET_DISPLAY_BRIGHTNESS_SUPPORT:
         case SET_DISPLAY_BRIGHTNESS: {
             return OK;
@@ -5912,6 +5922,27 @@
     return genericLayerMetadataKeyMap;
 }
 
+status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
+                                      int8_t compatibility) {
+    if (!ValidateFrameRate(frameRate, compatibility, "SurfaceFlinger::setFrameRate")) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mStateLock);
+    if (authenticateSurfaceTextureLocked(surface)) {
+        sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
+        if (layer->setFrameRate(
+                    Layer::FrameRate(frameRate,
+                                     Layer::FrameRate::convertCompatibility(compatibility)))) {
+            setTransactionFlags(eTraversalNeeded);
+        }
+    } else {
+        ALOGE("Attempt to set frame rate on an unrecognized IGraphicBufferProducer");
+        return BAD_VALUE;
+    }
+    return NO_ERROR;
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6770c1c..dcbb150 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -493,6 +493,8 @@
     status_t notifyPowerHint(int32_t hintId) override;
     status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
                                      float lightPosY, float lightPosZ, float lightRadius) override;
+    status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
+                          int8_t compatibility) override;
     /* ------------------------------------------------------------------------
      * DeathRecipient interface
      */
diff --git a/services/surfaceflinger/tests/SetFrameRate_test.cpp b/services/surfaceflinger/tests/SetFrameRate_test.cpp
index fc65263..02ba9e2 100644
--- a/services/surfaceflinger/tests/SetFrameRate_test.cpp
+++ b/services/surfaceflinger/tests/SetFrameRate_test.cpp
@@ -58,17 +58,23 @@
 
 TEST_F(SetFrameRateTest, BufferQueueLayerSetFrameRate) {
     CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferQueue);
-    native_window_set_frame_rate(mLayer->getSurface().get(), 100.f);
+    native_window_set_frame_rate(mLayer->getSurface().get(), 100.f,
+                                 ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT);
     ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
-    Transaction().setFrameRate(mLayer, 200.f).apply();
+    Transaction()
+            .setFrameRate(mLayer, 200.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT)
+            .apply();
     ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
-    native_window_set_frame_rate(mLayer->getSurface().get(), 300.f);
+    native_window_set_frame_rate(mLayer->getSurface().get(), 300.f,
+                                 ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT);
     ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
 }
 
 TEST_F(SetFrameRateTest, BufferStateLayerSetFrameRate) {
     CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferState);
-    Transaction().setFrameRate(mLayer, 400.f).apply();
+    Transaction()
+            .setFrameRate(mLayer, 400.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT)
+            .apply();
     ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::GREEN));
 }