Merge "Mark InputDispatcher::dump as const" into udc-qpr-dev
diff --git a/data/etc/input/Android.bp b/data/etc/input/Android.bp
index 90f3c6b..b662491 100644
--- a/data/etc/input/Android.bp
+++ b/data/etc/input/Android.bp
@@ -3,12 +3,21 @@
 }
 
 filegroup {
-    name: "motion_predictor_model.fb",
-    srcs: ["motion_predictor_model.fb"],
+    name: "motion_predictor_model",
+    srcs: [
+        "motion_predictor_model.tflite",
+        "motion_predictor_config.xml",
+    ],
 }
 
 prebuilt_etc {
     name: "motion_predictor_model_prebuilt",
     filename_from_src: true,
-    src: "motion_predictor_model.fb",
+    src: "motion_predictor_model.tflite",
+}
+
+prebuilt_etc {
+    name: "motion_predictor_model_config",
+    filename_from_src: true,
+    src: "motion_predictor_config.xml",
 }
diff --git a/data/etc/input/motion_predictor_config.xml b/data/etc/input/motion_predictor_config.xml
new file mode 100644
index 0000000..03dfd63
--- /dev/null
+++ b/data/etc/input/motion_predictor_config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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.
+-->
+<motion-predictor>
+  <!-- The time interval (ns) between the model's predictions. -->
+  <prediction-interval>4166666</prediction-interval>  <!-- 4.167 ms = ~240 Hz -->
+</motion-predictor>
+
diff --git a/data/etc/input/motion_predictor_model.fb b/data/etc/input/motion_predictor_model.tflite
similarity index 100%
rename from data/etc/input/motion_predictor_model.fb
rename to data/etc/input/motion_predictor_model.tflite
Binary files differ
diff --git a/include/input/InputEventBuilders.h b/include/input/InputEventBuilders.h
new file mode 100644
index 0000000..9c0c10e
--- /dev/null
+++ b/include/input/InputEventBuilders.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#pragma once
+
+#include <android/input.h>
+#include <attestation/HmacKeyManager.h>
+#include <gui/constants.h>
+#include <input/Input.h>
+#include <utils/Timers.h> // for nsecs_t, systemTime
+
+#include <vector>
+
+namespace android {
+
+// An arbitrary device id.
+static constexpr uint32_t DEFAULT_DEVICE_ID = 1;
+
+// The default policy flags to use for event injection by tests.
+static constexpr uint32_t DEFAULT_POLICY_FLAGS = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
+
+class PointerBuilder {
+public:
+    PointerBuilder(int32_t id, ToolType toolType) {
+        mProperties.clear();
+        mProperties.id = id;
+        mProperties.toolType = toolType;
+        mCoords.clear();
+    }
+
+    PointerBuilder& x(float x) { return axis(AMOTION_EVENT_AXIS_X, x); }
+
+    PointerBuilder& y(float y) { return axis(AMOTION_EVENT_AXIS_Y, y); }
+
+    PointerBuilder& axis(int32_t axis, float value) {
+        mCoords.setAxisValue(axis, value);
+        return *this;
+    }
+
+    PointerProperties buildProperties() const { return mProperties; }
+
+    PointerCoords buildCoords() const { return mCoords; }
+
+private:
+    PointerProperties mProperties;
+    PointerCoords mCoords;
+};
+
+class MotionEventBuilder {
+public:
+    MotionEventBuilder(int32_t action, int32_t source) {
+        mAction = action;
+        mSource = source;
+        mEventTime = systemTime(SYSTEM_TIME_MONOTONIC);
+        mDownTime = mEventTime;
+    }
+
+    MotionEventBuilder& deviceId(int32_t deviceId) {
+        mDeviceId = deviceId;
+        return *this;
+    }
+
+    MotionEventBuilder& downTime(nsecs_t downTime) {
+        mDownTime = downTime;
+        return *this;
+    }
+
+    MotionEventBuilder& eventTime(nsecs_t eventTime) {
+        mEventTime = eventTime;
+        return *this;
+    }
+
+    MotionEventBuilder& displayId(int32_t displayId) {
+        mDisplayId = displayId;
+        return *this;
+    }
+
+    MotionEventBuilder& actionButton(int32_t actionButton) {
+        mActionButton = actionButton;
+        return *this;
+    }
+
+    MotionEventBuilder& buttonState(int32_t buttonState) {
+        mButtonState = buttonState;
+        return *this;
+    }
+
+    MotionEventBuilder& rawXCursorPosition(float rawXCursorPosition) {
+        mRawXCursorPosition = rawXCursorPosition;
+        return *this;
+    }
+
+    MotionEventBuilder& rawYCursorPosition(float rawYCursorPosition) {
+        mRawYCursorPosition = rawYCursorPosition;
+        return *this;
+    }
+
+    MotionEventBuilder& pointer(PointerBuilder pointer) {
+        mPointers.push_back(pointer);
+        return *this;
+    }
+
+    MotionEventBuilder& addFlag(uint32_t flags) {
+        mFlags |= flags;
+        return *this;
+    }
+
+    MotionEvent build() {
+        std::vector<PointerProperties> pointerProperties;
+        std::vector<PointerCoords> pointerCoords;
+        for (const PointerBuilder& pointer : mPointers) {
+            pointerProperties.push_back(pointer.buildProperties());
+            pointerCoords.push_back(pointer.buildCoords());
+        }
+
+        // Set mouse cursor position for the most common cases to avoid boilerplate.
+        if (mSource == AINPUT_SOURCE_MOUSE &&
+            !MotionEvent::isValidCursorPosition(mRawXCursorPosition, mRawYCursorPosition)) {
+            mRawXCursorPosition = pointerCoords[0].getX();
+            mRawYCursorPosition = pointerCoords[0].getY();
+        }
+
+        MotionEvent event;
+        static const ui::Transform kIdentityTransform;
+        event.initialize(InputEvent::nextId(), mDeviceId, mSource, mDisplayId, INVALID_HMAC,
+                         mAction, mActionButton, mFlags, /*edgeFlags=*/0, AMETA_NONE, mButtonState,
+                         MotionClassification::NONE, kIdentityTransform,
+                         /*xPrecision=*/0, /*yPrecision=*/0, mRawXCursorPosition,
+                         mRawYCursorPosition, kIdentityTransform, mDownTime, mEventTime,
+                         mPointers.size(), pointerProperties.data(), pointerCoords.data());
+        return event;
+    }
+
+private:
+    int32_t mAction;
+    int32_t mDeviceId{DEFAULT_DEVICE_ID};
+    int32_t mSource;
+    nsecs_t mDownTime;
+    nsecs_t mEventTime;
+    int32_t mDisplayId{ADISPLAY_ID_DEFAULT};
+    int32_t mActionButton{0};
+    int32_t mButtonState{0};
+    int32_t mFlags{0};
+    float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
+    float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
+
+    std::vector<PointerBuilder> mPointers;
+};
+
+} // namespace android
diff --git a/include/input/MotionPredictor.h b/include/input/MotionPredictor.h
index de8ddca..8797962 100644
--- a/include/input/MotionPredictor.h
+++ b/include/input/MotionPredictor.h
@@ -26,7 +26,9 @@
 #include <android-base/thread_annotations.h>
 #include <android/sysprop/InputProperties.sysprop.h>
 #include <input/Input.h>
+#include <input/MotionPredictorMetricsManager.h>
 #include <input/TfLiteMotionPredictor.h>
+#include <utils/Timers.h> // for nsecs_t
 
 namespace android {
 
@@ -69,6 +71,7 @@
      */
     MotionPredictor(nsecs_t predictionTimestampOffsetNanos,
                     std::function<bool()> checkEnableMotionPrediction = isMotionPredictionEnabled);
+
     /**
      * Record the actual motion received by the view. This event will be used for calculating the
      * predictions.
@@ -77,7 +80,9 @@
      * consistent with the previously recorded events.
      */
     android::base::Result<void> record(const MotionEvent& event);
+
     std::unique_ptr<MotionEvent> predict(nsecs_t timestamp);
+
     bool isPredictionAvailable(int32_t deviceId, int32_t source);
 
 private:
@@ -88,6 +93,8 @@
 
     std::unique_ptr<TfLiteMotionPredictorBuffers> mBuffers;
     std::optional<MotionEvent> mLastEvent;
+
+    std::optional<MotionPredictorMetricsManager> mMetricsManager;
 };
 
 } // namespace android
diff --git a/include/input/MotionPredictorMetricsManager.h b/include/input/MotionPredictorMetricsManager.h
new file mode 100644
index 0000000..6284f07
--- /dev/null
+++ b/include/input/MotionPredictorMetricsManager.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#include <utils/Timers.h>
+
+namespace android {
+
+/**
+ * Class to handle computing and reporting metrics for MotionPredictor.
+ *
+ * Currently an empty implementation, containing only the API.
+ */
+class MotionPredictorMetricsManager {
+public:
+    // Note: the MetricsManager assumes that the input interval equals the prediction interval.
+    MotionPredictorMetricsManager(nsecs_t /*predictionInterval*/, size_t /*maxNumPredictions*/) {}
+
+    void onRecord(const MotionEvent& /*inputEvent*/) {}
+
+    void onPredict(const MotionEvent& /*predictionEvent*/) {}
+};
+
+} // namespace android
diff --git a/include/input/TfLiteMotionPredictor.h b/include/input/TfLiteMotionPredictor.h
index a340bd0..fbd6026 100644
--- a/include/input/TfLiteMotionPredictor.h
+++ b/include/input/TfLiteMotionPredictor.h
@@ -25,6 +25,7 @@
 
 #include <android-base/mapped_file.h>
 #include <input/RingBuffer.h>
+#include <utils/Timers.h>
 
 #include <tensorflow/lite/core/api/error_reporter.h>
 #include <tensorflow/lite/interpreter.h>
@@ -109,6 +110,9 @@
     // Returns the length of the model's output buffers.
     size_t outputLength() const;
 
+    // Returns the time interval between predictions.
+    nsecs_t predictionInterval() const { return mPredictionInterval; }
+
     // Executes the model.
     // Returns true if the model successfully executed and the output tensors can be read.
     bool invoke();
@@ -127,7 +131,8 @@
     std::span<const float> outputPressure() const;
 
 private:
-    explicit TfLiteMotionPredictorModel(std::unique_ptr<android::base::MappedFile> model);
+    explicit TfLiteMotionPredictorModel(std::unique_ptr<android::base::MappedFile> model,
+                                        nsecs_t predictionInterval);
 
     void allocateTensors();
     void attachInputTensors();
@@ -148,6 +153,8 @@
     std::unique_ptr<tflite::FlatBufferModel> mModel;
     std::unique_ptr<tflite::Interpreter> mInterpreter;
     tflite::SignatureRunner* mRunner = nullptr;
+
+    const nsecs_t mPredictionInterval = 0;
 };
 
 } // namespace android
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 582437f..715822b 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -120,6 +120,16 @@
     return base::Join(soNames, ':');
 }
 
+static sp<IGpuService> getGpuService() {
+    static const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu"));
+    if (!binder) {
+        ALOGE("Failed to get gpu service");
+        return nullptr;
+    }
+
+    return interface_cast<IGpuService>(binder);
+}
+
 /*static*/ GraphicsEnv& GraphicsEnv::getInstance() {
     static GraphicsEnv env;
     return env;
@@ -142,6 +152,10 @@
     return appDebuggable || platformDebuggable;
 }
 
+/**
+ * APIs for updatable graphics drivers
+ */
+
 void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string& path,
                                                  const std::string& sphalLibraries) {
     if (!mDriverPath.empty() || !mSphalLibraries.empty()) {
@@ -156,6 +170,108 @@
     mSphalLibraries = sphalLibraries;
 }
 
+// Return true if all the required libraries from vndk and sphal namespace are
+// linked to the driver namespace correctly.
+bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* destNamespace,
+                                            android_namespace_t* vndkNamespace,
+                                            const std::string& sharedSphalLibraries) {
+    const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK);
+    if (llndkLibraries.empty()) {
+        return false;
+    }
+    if (!android_link_namespaces(destNamespace, nullptr, llndkLibraries.c_str())) {
+        ALOGE("Failed to link default namespace[%s]", dlerror());
+        return false;
+    }
+
+    const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP);
+    if (vndkspLibraries.empty()) {
+        return false;
+    }
+    if (!android_link_namespaces(destNamespace, vndkNamespace, vndkspLibraries.c_str())) {
+        ALOGE("Failed to link vndk namespace[%s]", dlerror());
+        return false;
+    }
+
+    if (sharedSphalLibraries.empty()) {
+        return true;
+    }
+
+    // Make additional libraries in sphal to be accessible
+    auto sphalNamespace = android_get_exported_namespace("sphal");
+    if (!sphalNamespace) {
+        ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace",
+              sharedSphalLibraries.c_str());
+        return false;
+    }
+
+    if (!android_link_namespaces(destNamespace, sphalNamespace, sharedSphalLibraries.c_str())) {
+        ALOGE("Failed to link sphal namespace[%s]", dlerror());
+        return false;
+    }
+
+    return true;
+}
+
+android_namespace_t* GraphicsEnv::getDriverNamespace() {
+    std::lock_guard<std::mutex> lock(mNamespaceMutex);
+
+    if (mDriverNamespace) {
+        return mDriverNamespace;
+    }
+
+    if (mDriverPath.empty()) {
+        // For an application process, driver path is empty means this application is not opted in
+        // to use updatable driver. Application process doesn't have the ability to set up
+        // environment variables and hence before `getenv` call will return.
+        // For a process that is not an application process, if it's run from an environment,
+        // for example shell, where environment variables can be set, then it can opt into using
+        // udpatable driver by setting UPDATABLE_GFX_DRIVER to 1. By setting to 1 the developer
+        // driver will be used currently.
+        // TODO(b/159240322) Support the production updatable driver.
+        const char* id = getenv("UPDATABLE_GFX_DRIVER");
+        if (id == nullptr || std::strcmp(id, "1") != 0) {
+            return nullptr;
+        }
+        const sp<IGpuService> gpuService = getGpuService();
+        if (!gpuService) {
+            return nullptr;
+        }
+        mDriverPath = gpuService->getUpdatableDriverPath();
+        if (mDriverPath.empty()) {
+            return nullptr;
+        }
+        mDriverPath.append(UPDATABLE_DRIVER_ABI);
+        ALOGI("Driver path is setup via UPDATABLE_GFX_DRIVER: %s", mDriverPath.c_str());
+    }
+
+    auto vndkNamespace = android_get_exported_namespace("vndk");
+    if (!vndkNamespace) {
+        return nullptr;
+    }
+
+    mDriverNamespace = android_create_namespace("updatable gfx driver",
+                                                mDriverPath.c_str(), // ld_library_path
+                                                mDriverPath.c_str(), // default_library_path
+                                                ANDROID_NAMESPACE_TYPE_ISOLATED,
+                                                nullptr, // permitted_when_isolated_path
+                                                nullptr);
+
+    if (!linkDriverNamespaceLocked(mDriverNamespace, vndkNamespace, mSphalLibraries)) {
+        mDriverNamespace = nullptr;
+    }
+
+    return mDriverNamespace;
+}
+
+std::string GraphicsEnv::getDriverPath() const {
+    return mDriverPath;
+}
+
+/**
+ * APIs for GpuStats
+ */
+
 void GraphicsEnv::hintActivityLaunch() {
     ATRACE_CALL();
 
@@ -310,16 +426,6 @@
                         extensionHashes, numStats);
 }
 
-static sp<IGpuService> getGpuService() {
-    static const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu"));
-    if (!binder) {
-        ALOGE("Failed to get gpu service");
-        return nullptr;
-    }
-
-    return interface_cast<IGpuService>(binder);
-}
-
 bool GraphicsEnv::readyToSendGpuStatsLocked() {
     // Only send stats for processes having at least one activity launched and that process doesn't
     // skip the GraphicsEnvironment setup.
@@ -392,6 +498,10 @@
     return true;
 }
 
+/**
+ * APIs for ANGLE
+ */
+
 bool GraphicsEnv::shouldUseAngle() {
     // Make sure we are init'ed
     if (mPackageName.empty()) {
@@ -399,47 +509,108 @@
         return false;
     }
 
-    return (mShouldUseAngle == YES) ? true : false;
+    return mShouldUseAngle;
 }
 
-void GraphicsEnv::updateShouldUseAngle() {
-    const char* ANGLE_PREFER_ANGLE = "angle";
-    const char* ANGLE_PREFER_NATIVE = "native";
-
-    mShouldUseAngle = NO;
-    if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) {
-        ALOGV("User set \"Developer Options\" to force the use of ANGLE");
-        mShouldUseAngle = YES;
-    } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) {
-        ALOGV("User set \"Developer Options\" to force the use of Native");
-    } else {
-        ALOGV("User set invalid \"Developer Options\": '%s'", mAngleDeveloperOptIn.c_str());
-    }
-}
-
-void GraphicsEnv::setAngleInfo(const std::string& path, const std::string& packageName,
-                               const std::string& developerOptIn,
+void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseSystemAngle,
+                               const std::string& packageName,
                                const std::vector<std::string> eglFeatures) {
-    if (mShouldUseAngle != UNKNOWN) {
-        // We've already figured out an answer for this app, so just return.
-        ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", packageName.c_str(),
-              (mShouldUseAngle == YES) ? "true" : "false");
+    if (mShouldUseAngle) {
+        // ANGLE is already set up for this application process, even if the application
+        // needs to switch from apk to system or vice versa, the application process must
+        // be killed and relaunch so that the loader can properly load ANGLE again.
+        // The architecture does not support runtime switch between drivers, so just return.
+        ALOGE("ANGLE is already set for %s", packageName.c_str());
         return;
     }
 
     mAngleEglFeatures = std::move(eglFeatures);
-
     ALOGV("setting ANGLE path to '%s'", path.c_str());
-    mAnglePath = path;
+    mAnglePath = std::move(path);
     ALOGV("setting app package name to '%s'", packageName.c_str());
-    mPackageName = packageName;
-    ALOGV("setting ANGLE application opt-in to '%s'", developerOptIn.c_str());
-    mAngleDeveloperOptIn = developerOptIn;
-
-    // Update the current status of whether we should use ANGLE or not
-    updateShouldUseAngle();
+    mPackageName = std::move(packageName);
+    mShouldUseAngle = true;
+    mShouldUseSystemAngle = shouldUseSystemAngle;
 }
 
+std::string& GraphicsEnv::getPackageName() {
+    return mPackageName;
+}
+
+const std::vector<std::string>& GraphicsEnv::getAngleEglFeatures() {
+    return mAngleEglFeatures;
+}
+
+android_namespace_t* GraphicsEnv::getAngleNamespace() {
+    std::lock_guard<std::mutex> lock(mNamespaceMutex);
+
+    if (mAngleNamespace) {
+        return mAngleNamespace;
+    }
+
+    if (mAnglePath.empty() && !mShouldUseSystemAngle) {
+        ALOGV("mAnglePath is empty and not using system ANGLE, abort creating ANGLE namespace");
+        return nullptr;
+    }
+
+    // Construct the search paths for system ANGLE.
+    const char* const defaultLibraryPaths =
+#if defined(__LP64__)
+            "/vendor/lib64/egl:/system/lib64/egl";
+#else
+            "/vendor/lib/egl:/system/lib/egl";
+#endif
+
+    // If the application process will run on top of system ANGLE, construct the namespace
+    // with sphal namespace being the parent namespace so that search paths and libraries
+    // are properly inherited.
+    mAngleNamespace =
+            android_create_namespace("ANGLE",
+                                     mShouldUseSystemAngle ? defaultLibraryPaths
+                                                           : mAnglePath.c_str(), // ld_library_path
+                                     mShouldUseSystemAngle
+                                             ? defaultLibraryPaths
+                                             : mAnglePath.c_str(), // default_library_path
+                                     ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED,
+                                     nullptr, // permitted_when_isolated_path
+                                     mShouldUseSystemAngle ? android_get_exported_namespace("sphal")
+                                                           : nullptr); // parent
+
+    ALOGD_IF(!mAngleNamespace, "Could not create ANGLE namespace from default");
+
+    if (!mShouldUseSystemAngle) {
+        return mAngleNamespace;
+    }
+
+    auto vndkNamespace = android_get_exported_namespace("vndk");
+    if (!vndkNamespace) {
+        return nullptr;
+    }
+
+    if (!linkDriverNamespaceLocked(mAngleNamespace, vndkNamespace, "")) {
+        mAngleNamespace = nullptr;
+    }
+
+    return mAngleNamespace;
+}
+
+void GraphicsEnv::nativeToggleAngleAsSystemDriver(bool enabled) {
+    const sp<IGpuService> gpuService = getGpuService();
+    if (!gpuService) {
+        ALOGE("No GPU service");
+        return;
+    }
+    gpuService->toggleAngleAsSystemDriver(enabled);
+}
+
+bool GraphicsEnv::shouldUseSystemAngle() {
+    return mShouldUseSystemAngle;
+}
+
+/**
+ * APIs for debuggable layers
+ */
+
 void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace,
                                 const std::string& layerPaths) {
     if (mLayerPaths.empty()) {
@@ -455,14 +626,6 @@
     return mAppNamespace;
 }
 
-std::string& GraphicsEnv::getPackageName() {
-    return mPackageName;
-}
-
-const std::vector<std::string>& GraphicsEnv::getAngleEglFeatures() {
-    return mAngleEglFeatures;
-}
-
 const std::string& GraphicsEnv::getLayerPaths() {
     return mLayerPaths;
 }
@@ -483,133 +646,4 @@
     mDebugLayersGLES = layers;
 }
 
-// Return true if all the required libraries from vndk and sphal namespace are
-// linked to the updatable gfx driver namespace correctly.
-bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace) {
-    const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK);
-    if (llndkLibraries.empty()) {
-        return false;
-    }
-    if (!android_link_namespaces(mDriverNamespace, nullptr, llndkLibraries.c_str())) {
-        ALOGE("Failed to link default namespace[%s]", dlerror());
-        return false;
-    }
-
-    const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP);
-    if (vndkspLibraries.empty()) {
-        return false;
-    }
-    if (!android_link_namespaces(mDriverNamespace, vndkNamespace, vndkspLibraries.c_str())) {
-        ALOGE("Failed to link vndk namespace[%s]", dlerror());
-        return false;
-    }
-
-    if (mSphalLibraries.empty()) {
-        return true;
-    }
-
-    // Make additional libraries in sphal to be accessible
-    auto sphalNamespace = android_get_exported_namespace("sphal");
-    if (!sphalNamespace) {
-        ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace",
-              mSphalLibraries.c_str());
-        return false;
-    }
-
-    if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) {
-        ALOGE("Failed to link sphal namespace[%s]", dlerror());
-        return false;
-    }
-
-    return true;
-}
-
-android_namespace_t* GraphicsEnv::getDriverNamespace() {
-    std::lock_guard<std::mutex> lock(mNamespaceMutex);
-
-    if (mDriverNamespace) {
-        return mDriverNamespace;
-    }
-
-    if (mDriverPath.empty()) {
-        // For an application process, driver path is empty means this application is not opted in
-        // to use updatable driver. Application process doesn't have the ability to set up
-        // environment variables and hence before `getenv` call will return.
-        // For a process that is not an application process, if it's run from an environment,
-        // for example shell, where environment variables can be set, then it can opt into using
-        // udpatable driver by setting UPDATABLE_GFX_DRIVER to 1. By setting to 1 the developer
-        // driver will be used currently.
-        // TODO(b/159240322) Support the production updatable driver.
-        const char* id = getenv("UPDATABLE_GFX_DRIVER");
-        if (id == nullptr || std::strcmp(id, "1")) {
-            return nullptr;
-        }
-        const sp<IGpuService> gpuService = getGpuService();
-        if (!gpuService) {
-            return nullptr;
-        }
-        mDriverPath = gpuService->getUpdatableDriverPath();
-        if (mDriverPath.empty()) {
-            return nullptr;
-        }
-        mDriverPath.append(UPDATABLE_DRIVER_ABI);
-        ALOGI("Driver path is setup via UPDATABLE_GFX_DRIVER: %s", mDriverPath.c_str());
-    }
-
-    auto vndkNamespace = android_get_exported_namespace("vndk");
-    if (!vndkNamespace) {
-        return nullptr;
-    }
-
-    mDriverNamespace = android_create_namespace("gfx driver",
-                                                mDriverPath.c_str(), // ld_library_path
-                                                mDriverPath.c_str(), // default_library_path
-                                                ANDROID_NAMESPACE_TYPE_ISOLATED,
-                                                nullptr, // permitted_when_isolated_path
-                                                nullptr);
-
-    if (!linkDriverNamespaceLocked(vndkNamespace)) {
-        mDriverNamespace = nullptr;
-    }
-
-    return mDriverNamespace;
-}
-
-std::string GraphicsEnv::getDriverPath() const {
-    return mDriverPath;
-}
-
-android_namespace_t* GraphicsEnv::getAngleNamespace() {
-    std::lock_guard<std::mutex> lock(mNamespaceMutex);
-
-    if (mAngleNamespace) {
-        return mAngleNamespace;
-    }
-
-    if (mAnglePath.empty()) {
-        ALOGV("mAnglePath is empty, not creating ANGLE namespace");
-        return nullptr;
-    }
-
-    mAngleNamespace = android_create_namespace("ANGLE",
-                                               nullptr,            // ld_library_path
-                                               mAnglePath.c_str(), // default_library_path
-                                               ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED,
-                                               nullptr, // permitted_when_isolated_path
-                                               nullptr);
-
-    ALOGD_IF(!mAngleNamespace, "Could not create ANGLE namespace from default");
-
-    return mAngleNamespace;
-}
-
-void GraphicsEnv::nativeToggleAngleAsSystemDriver(bool enabled) {
-    const sp<IGpuService> gpuService = getGpuService();
-    if (!gpuService) {
-        ALOGE("No GPU service");
-        return;
-    }
-    gpuService->toggleAngleAsSystemDriver(enabled);
-}
-
 } // namespace android
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index a1b5e50..fbf2902 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -29,6 +29,11 @@
 
 struct NativeLoaderNamespace;
 
+// The GraphicsEnv is a singleton per application process and is used to properly set up the
+// graphics drivers for the application process during application starts. The architecture of
+// the graphics driver loader does not support runtime switch and only supports switch to different
+// graphics drivers when application process launches and hence the only way to switch to different
+// graphics drivers is to completely kill the application process and relaunch the application.
 class GraphicsEnv {
 public:
     static GraphicsEnv& getInstance();
@@ -103,8 +108,8 @@
     // (libraries must be stored uncompressed and page aligned); such elements
     // in the search path must have a '!' after the zip filename, e.g.
     //     /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
-    void setAngleInfo(const std::string& path, const std::string& packageName,
-                      const std::string& devOptIn, const std::vector<std::string> eglFeatures);
+    void setAngleInfo(const std::string& path, const bool useSystemAngle,
+                      const std::string& packageName, const std::vector<std::string> eglFeatures);
     // Get the ANGLE driver namespace.
     android_namespace_t* getAngleNamespace();
     // Get the app package name.
@@ -112,6 +117,7 @@
     const std::vector<std::string>& getAngleEglFeatures();
     // Set the persist.graphics.egl system property value.
     void nativeToggleAngleAsSystemDriver(bool enabled);
+    bool shouldUseSystemAngle();
 
     /*
      * Apis for debug layer
@@ -132,12 +138,10 @@
     const std::string& getDebugLayersGLES();
 
 private:
-    enum UseAngle { UNKNOWN, YES, NO };
-
-    // Update whether ANGLE should be used.
-    void updateShouldUseAngle();
     // Link updatable driver namespace with llndk and vndk-sp libs.
-    bool linkDriverNamespaceLocked(android_namespace_t* vndkNamespace);
+    bool linkDriverNamespaceLocked(android_namespace_t* destNamespace,
+                                   android_namespace_t* vndkNamespace,
+                                   const std::string& sharedSphalLibraries);
     // Check whether this process is ready to send stats.
     bool readyToSendGpuStatsLocked();
     // Send the initial complete GpuStats to GpuService.
@@ -165,12 +169,12 @@
     std::string mAnglePath;
     // App's package name.
     std::string mPackageName;
-    // ANGLE developer opt in status.
-    std::string mAngleDeveloperOptIn;
     // ANGLE EGL features;
     std::vector<std::string> mAngleEglFeatures;
-    // Use ANGLE flag.
-    UseAngle mShouldUseAngle = UNKNOWN;
+    // Whether ANGLE should be used.
+    bool mShouldUseAngle = false;
+    // Whether loader should load system ANGLE.
+    bool mShouldUseSystemAngle = false;
     // ANGLE namespace.
     android_namespace_t* mAngleNamespace = nullptr;
 
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 9ac1829..8a17d8a 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -215,6 +215,7 @@
         "libcutils",
         "liblog",
         "libPlatformProperties",
+        "libtinyxml2",
         "libvintf",
     ],
 
@@ -271,6 +272,7 @@
 
             required: [
                 "motion_predictor_model_prebuilt",
+                "motion_predictor_model_config",
             ],
         },
         host: {
diff --git a/libs/input/MotionPredictor.cpp b/libs/input/MotionPredictor.cpp
index 3037573..68e6888 100644
--- a/libs/input/MotionPredictor.cpp
+++ b/libs/input/MotionPredictor.cpp
@@ -36,9 +36,6 @@
 namespace android {
 namespace {
 
-const int64_t PREDICTION_INTERVAL_NANOS =
-        12500000 / 3; // TODO(b/266747937): Get this from the model.
-
 /**
  * Log debug messages about predictions.
  * Enable this via "adb shell setprop log.tag.MotionPredictor DEBUG"
@@ -70,7 +67,7 @@
 android::base::Result<void> MotionPredictor::record(const MotionEvent& event) {
     if (mLastEvent && mLastEvent->getDeviceId() != event.getDeviceId()) {
         // We still have an active gesture for another device. The provided MotionEvent is not
-        // consistent the previous gesture.
+        // consistent with the previous gesture.
         LOG(ERROR) << "Inconsistent event stream: last event is " << *mLastEvent << ", but "
                    << __func__ << " is called with " << event;
         return android::base::Error()
@@ -86,9 +83,10 @@
     // Initialise the model now that it's likely to be used.
     if (!mModel) {
         mModel = TfLiteMotionPredictorModel::create();
+        LOG_ALWAYS_FATAL_IF(!mModel);
     }
 
-    if (mBuffers == nullptr) {
+    if (!mBuffers) {
         mBuffers = std::make_unique<TfLiteMotionPredictorBuffers>(mModel->inputLength());
     }
 
@@ -136,6 +134,15 @@
         mLastEvent = MotionEvent();
     }
     mLastEvent->copyFrom(&event, /*keepHistory=*/false);
+
+    // Pass input event to the MetricsManager.
+    if (!mMetricsManager) {
+        mMetricsManager =
+                std::make_optional<MotionPredictorMetricsManager>(mModel->predictionInterval(),
+                                                                  mModel->outputLength());
+    }
+    mMetricsManager->onRecord(event);
+
     return {};
 }
 
@@ -177,19 +184,20 @@
     const int64_t futureTime = timestamp + mPredictionTimestampOffsetNanos;
 
     for (int i = 0; i < predictedR.size() && predictionTime <= futureTime; ++i) {
-        const TfLiteMotionPredictorSample::Point point =
-                convertPrediction(axisFrom, axisTo, predictedR[i], predictedPhi[i]);
-        // TODO(b/266747654): Stop predictions if confidence is < some threshold.
+        // TODO(b/266747654): Stop predictions if confidence and/or predicted pressure are below
+        // some thresholds.
 
-        ALOGD_IF(isDebug(), "prediction %d: %f, %f", i, point.x, point.y);
+        const TfLiteMotionPredictorSample::Point predictedPoint =
+                convertPrediction(axisFrom, axisTo, predictedR[i], predictedPhi[i]);
+
+        ALOGD_IF(isDebug(), "prediction %d: %f, %f", i, predictedPoint.x, predictedPoint.y);
         PointerCoords coords;
         coords.clear();
-        coords.setAxisValue(AMOTION_EVENT_AXIS_X, point.x);
-        coords.setAxisValue(AMOTION_EVENT_AXIS_Y, point.y);
-        // TODO(b/266747654): Stop predictions if predicted pressure is < some threshold.
+        coords.setAxisValue(AMOTION_EVENT_AXIS_X, predictedPoint.x);
+        coords.setAxisValue(AMOTION_EVENT_AXIS_Y, predictedPoint.y);
         coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, predictedPressure[i]);
 
-        predictionTime += PREDICTION_INTERVAL_NANOS;
+        predictionTime += mModel->predictionInterval();
         if (i == 0) {
             hasPredictions = true;
             prediction->initialize(InputEvent::nextId(), event.getDeviceId(), event.getSource(),
@@ -206,12 +214,17 @@
         }
 
         axisFrom = axisTo;
-        axisTo = point;
+        axisTo = predictedPoint;
     }
-    // TODO(b/266747511): Interpolate to futureTime?
+
     if (!hasPredictions) {
         return nullptr;
     }
+
+    // Pass predictions to the MetricsManager.
+    LOG_ALWAYS_FATAL_IF(!mMetricsManager);
+    mMetricsManager->onPredict(*prediction);
+
     return prediction;
 }
 
diff --git a/libs/input/TfLiteMotionPredictor.cpp b/libs/input/TfLiteMotionPredictor.cpp
index 85fa176..9f4aaa8 100644
--- a/libs/input/TfLiteMotionPredictor.cpp
+++ b/libs/input/TfLiteMotionPredictor.cpp
@@ -36,6 +36,7 @@
 #define ATRACE_TAG ATRACE_TAG_INPUT
 #include <cutils/trace.h>
 #include <log/log.h>
+#include <utils/Timers.h>
 
 #include "tensorflow/lite/core/api/error_reporter.h"
 #include "tensorflow/lite/core/api/op_resolver.h"
@@ -44,6 +45,8 @@
 #include "tensorflow/lite/model.h"
 #include "tensorflow/lite/mutable_op_resolver.h"
 
+#include "tinyxml2.h"
+
 namespace android {
 namespace {
 
@@ -72,16 +75,31 @@
 
 std::string getModelPath() {
 #if defined(__ANDROID__)
-    static const char* oemModel = "/vendor/etc/motion_predictor_model.fb";
+    static const char* oemModel = "/vendor/etc/motion_predictor_model.tflite";
     if (fileExists(oemModel)) {
         return oemModel;
     }
-    return "/system/etc/motion_predictor_model.fb";
+    return "/system/etc/motion_predictor_model.tflite";
 #else
-    return base::GetExecutableDirectory() + "/motion_predictor_model.fb";
+    return base::GetExecutableDirectory() + "/motion_predictor_model.tflite";
 #endif
 }
 
+std::string getConfigPath() {
+    // The config file should be alongside the model file.
+    return base::Dirname(getModelPath()) + "/motion_predictor_config.xml";
+}
+
+int64_t parseXMLInt64(const tinyxml2::XMLElement& configRoot, const char* elementName) {
+    const tinyxml2::XMLElement* element = configRoot.FirstChildElement(elementName);
+    LOG_ALWAYS_FATAL_IF(!element, "Could not find '%s' element", elementName);
+
+    int64_t value = 0;
+    LOG_ALWAYS_FATAL_IF(element->QueryInt64Text(&value) != tinyxml2::XML_SUCCESS,
+                        "Failed to parse %s: %s", elementName, element->GetText());
+    return value;
+}
+
 // A TFLite ErrorReporter that logs to logcat.
 class LoggingErrorReporter : public tflite::ErrorReporter {
 public:
@@ -246,13 +264,23 @@
         PLOG(FATAL) << "Failed to mmap model";
     }
 
+    const std::string configPath = getConfigPath();
+    tinyxml2::XMLDocument configDocument;
+    LOG_ALWAYS_FATAL_IF(configDocument.LoadFile(configPath.c_str()) != tinyxml2::XML_SUCCESS,
+                        "Failed to load config file from %s", configPath.c_str());
+
+    // Parse configuration file.
+    const tinyxml2::XMLElement* configRoot = configDocument.FirstChildElement("motion-predictor");
+    LOG_ALWAYS_FATAL_IF(!configRoot);
+    const nsecs_t predictionInterval = parseXMLInt64(*configRoot, "prediction-interval");
+
     return std::unique_ptr<TfLiteMotionPredictorModel>(
-            new TfLiteMotionPredictorModel(std::move(modelBuffer)));
+            new TfLiteMotionPredictorModel(std::move(modelBuffer), predictionInterval));
 }
 
 TfLiteMotionPredictorModel::TfLiteMotionPredictorModel(
-        std::unique_ptr<android::base::MappedFile> model)
-      : mFlatBuffer(std::move(model)) {
+        std::unique_ptr<android::base::MappedFile> model, nsecs_t predictionInterval)
+      : mFlatBuffer(std::move(model)), mPredictionInterval(predictionInterval) {
     CHECK(mFlatBuffer);
     mErrorReporter = std::make_unique<LoggingErrorReporter>();
     mModel = tflite::FlatBufferModel::VerifyAndBuildFromBuffer(mFlatBuffer->data(),
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 6aae25d..cadac88 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -64,12 +64,13 @@
         "libcutils",
         "liblog",
         "libPlatformProperties",
+        "libtinyxml2",
         "libutils",
         "libvintf",
     ],
     data: [
         "data/*",
-        ":motion_predictor_model.fb",
+        ":motion_predictor_model",
     ],
     test_options: {
         unit_test: true,
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
index b99e385..c16586b 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
@@ -263,7 +263,7 @@
     VK_GET_INST_PROC(instance, EnumerateDeviceExtensionProperties);
     VK_GET_INST_PROC(instance, GetPhysicalDeviceProperties2);
     VK_GET_INST_PROC(instance, GetPhysicalDeviceExternalSemaphoreProperties);
-    VK_GET_INST_PROC(instance, GetPhysicalDeviceQueueFamilyProperties);
+    VK_GET_INST_PROC(instance, GetPhysicalDeviceQueueFamilyProperties2);
     VK_GET_INST_PROC(instance, GetPhysicalDeviceFeatures2);
     VK_GET_INST_PROC(instance, CreateDevice);
 
@@ -342,17 +342,37 @@
     }
 
     uint32_t queueCount;
-    vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, nullptr);
+    vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, nullptr);
     if (queueCount == 0) {
         BAIL("Could not find queues for physical device");
     }
 
-    std::vector<VkQueueFamilyProperties> queueProps(queueCount);
-    vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProps.data());
+    std::vector<VkQueueFamilyProperties2> queueProps(queueCount);
+    std::vector<VkQueueFamilyGlobalPriorityPropertiesEXT> queuePriorityProps(queueCount);
+    VkQueueGlobalPriorityKHR queuePriority = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR;
+    // Even though we don't yet know if the VK_EXT_global_priority extension is available,
+    // we can safely add the request to the pNext chain, and if the extension is not
+    // available, it will be ignored.
+    for (uint32_t i = 0; i < queueCount; ++i) {
+        queuePriorityProps[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT;
+        queuePriorityProps[i].pNext = nullptr;
+        queueProps[i].pNext = &queuePriorityProps[i];
+    }
+    vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, queueProps.data());
 
     int graphicsQueueIndex = -1;
     for (uint32_t i = 0; i < queueCount; ++i) {
-        if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+        // Look at potential answers to the VK_EXT_global_priority query.  If answers were
+        // provided, we may adjust the queuePriority.
+        if (queueProps[i].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+            for (uint32_t j = 0; j < queuePriorityProps[i].priorityCount; j++) {
+                if (queuePriorityProps[i].priorities[j] > queuePriority) {
+                    queuePriority = queuePriorityProps[i].priorities[j];
+                }
+            }
+            if (queuePriority == VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR) {
+                interface.isRealtimePriority = true;
+            }
             graphicsQueueIndex = i;
             break;
         }
@@ -419,12 +439,11 @@
             VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT,
             nullptr,
             // If queue priority is supported, RE should always have realtime priority.
-            VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT,
+            queuePriority,
     };
 
     if (interface.grExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) {
         queueNextPtr = &queuePriorityCreateInfo;
-        interface.isRealtimePriority = true;
     }
 
     VkDeviceQueueCreateFlags deviceQueueCreateFlags =
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index b4fc5f0..8d0eb59 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -161,7 +161,12 @@
     // Return true if ANGLE namespace is set.
     android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
     if (ns) {
-        return true;
+        // Unless the default GLES driver is ANGLE and the process should use system ANGLE, since
+        // the intended GLES driver is already loaded.
+        // This should be updated in a later patch that cleans up namespaces
+        if (!(cnx->angleLoaded && android::GraphicsEnv::getInstance().shouldUseSystemAngle())) {
+            return true;
+        }
     }
 
     // Return true if updated driver namespace is set.
@@ -206,17 +211,17 @@
             do_android_unload_sphal_library(hnd->dso[0]);
         }
         cnx->dso = nullptr;
+        cnx->angleLoaded = false;
     }
 
     cnx->systemDriverUnloaded = true;
 }
 
-void* Loader::open(egl_connection_t* cnx)
-{
+void* Loader::open(egl_connection_t* cnx) {
     ATRACE_CALL();
     const nsecs_t openTime = systemTime();
 
-    if (should_unload_system_driver(cnx)) {
+    if (cnx->dso && should_unload_system_driver(cnx)) {
         unload_system_driver(cnx);
     }
 
@@ -225,8 +230,12 @@
         return cnx->dso;
     }
 
-    // Firstly, try to load ANGLE driver.
-    driver_t* hnd = attempt_to_load_angle(cnx);
+    driver_t* hnd = nullptr;
+    // Firstly, try to load ANGLE driver, if ANGLE should be loaded and fail, abort.
+    if (android::GraphicsEnv::getInstance().shouldUseAngle()) {
+        hnd = attempt_to_load_angle(cnx);
+        LOG_ALWAYS_FATAL_IF(!hnd, "Failed to load ANGLE.");
+    }
 
     if (!hnd) {
         // Secondly, try to load from driver apk.
@@ -541,10 +550,6 @@
 Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) {
     ATRACE_CALL();
 
-    if (!android::GraphicsEnv::getInstance().shouldUseAngle()) {
-        return nullptr;
-    }
-
     android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
     if (!ns) {
         return nullptr;
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index fba64c7..052efb6b 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -71,6 +71,7 @@
 cc_library_shared {
     name: "libgpuservice",
     defaults: ["libgpuservice_production_defaults"],
+    export_include_dirs: ["include"],
     srcs: [
         ":libgpuservice_sources",
     ],
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 5e7b2e8..4a08c11 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -16,7 +16,7 @@
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include "GpuService.h"
+#include "gpuservice/GpuService.h"
 
 #include <android-base/stringprintf.h>
 #include <android-base/properties.h>
@@ -35,6 +35,7 @@
 #include <vkjson.h>
 
 #include <thread>
+#include <memory>
 
 namespace android {
 
@@ -58,18 +59,21 @@
         mGpuStats(std::make_unique<GpuStats>()),
         mGpuMemTracer(std::make_unique<GpuMemTracer>()) {
 
-    std::thread gpuMemAsyncInitThread([this]() {
+    mGpuMemAsyncInitThread = std::make_unique<std::thread>([this] (){
         mGpuMem->initialize();
         mGpuMemTracer->initialize(mGpuMem);
     });
-    gpuMemAsyncInitThread.detach();
 
-    std::thread gpuWorkAsyncInitThread([this]() {
+    mGpuWorkAsyncInitThread = std::make_unique<std::thread>([this]() {
         mGpuWork->initialize();
     });
-    gpuWorkAsyncInitThread.detach();
 };
 
+GpuService::~GpuService() {
+    mGpuWorkAsyncInitThread->join();
+    mGpuMemAsyncInitThread->join();
+}
+
 void GpuService::setGpuStats(const std::string& driverPackageName,
                              const std::string& driverVersionName, uint64_t driverVersionCode,
                              int64_t driverBuildTime, const std::string& appPackageName,
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/include/gpuservice/GpuService.h
similarity index 95%
rename from services/gpuservice/GpuService.h
rename to services/gpuservice/include/gpuservice/GpuService.h
index 0e559f2..54f8f66 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/include/gpuservice/GpuService.h
@@ -24,6 +24,7 @@
 #include <serviceutils/PriorityDumper.h>
 
 #include <mutex>
+#include <thread>
 #include <vector>
 
 namespace android {
@@ -41,6 +42,7 @@
     static const char* const SERVICE_NAME ANDROID_API;
 
     GpuService() ANDROID_API;
+    ~GpuService();
 
 protected:
     status_t shellCommand(int in, int out, int err, std::vector<String16>& args) override;
@@ -90,6 +92,8 @@
     std::unique_ptr<GpuMemTracer> mGpuMemTracer;
     std::mutex mLock;
     std::string mDeveloperDriverPath;
+    std::unique_ptr<std::thread> mGpuMemAsyncInitThread;
+    std::unique_ptr<std::thread> mGpuWorkAsyncInitThread;
 };
 
 } // namespace android
diff --git a/services/gpuservice/main_gpuservice.cpp b/services/gpuservice/main_gpuservice.cpp
index 64aafca..2002372 100644
--- a/services/gpuservice/main_gpuservice.cpp
+++ b/services/gpuservice/main_gpuservice.cpp
@@ -18,7 +18,7 @@
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <sys/resource.h>
-#include "GpuService.h"
+#include "gpuservice/GpuService.h"
 
 using namespace android;
 
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index 51642f9..c870b17 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -28,6 +28,7 @@
         "GpuMemTest.cpp",
         "GpuMemTracerTest.cpp",
         "GpuStatsTest.cpp",
+        "GpuServiceTest.cpp",
     ],
     header_libs: ["bpf_headers"],
     shared_libs: [
@@ -45,6 +46,7 @@
         "libstatslog",
         "libstatspull",
         "libutils",
+        "libgpuservice",
     ],
     static_libs: [
         "libgmock",
diff --git a/services/gpuservice/tests/unittests/GpuServiceTest.cpp b/services/gpuservice/tests/unittests/GpuServiceTest.cpp
new file mode 100644
index 0000000..62b3e53
--- /dev/null
+++ b/services/gpuservice/tests/unittests/GpuServiceTest.cpp
@@ -0,0 +1,52 @@
+#undef LOG_TAG
+#define LOG_TAG "gpuservice_unittest"
+
+#include "gpuservice/GpuService.h"
+
+#include <gtest/gtest.h>
+#include <log/log_main.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace {
+
+class GpuServiceTest : public testing::Test {
+public:
+    GpuServiceTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+
+    ~GpuServiceTest() {
+        const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+
+};
+
+
+/*
+* The behaviour before this test + fixes was UB caused by threads accessing deallocated memory.
+*
+* This test creates the service (which initializes the culprit threads),
+* deallocates it immediately and sleeps.
+*
+* GpuService's destructor gets called and joins the threads.
+* If we haven't crashed by the time the sleep time has elapsed, we're good
+* Let the test pass.
+*/
+TEST_F(GpuServiceTest, onInitializeShouldNotCauseUseAfterFree) {
+    sp<GpuService> service = new GpuService();
+    service.clear();
+    std::this_thread::sleep_for(std::chrono::seconds(3));
+
+    // If we haven't crashed yet due to threads accessing freed up memory, let the test pass
+    EXPECT_TRUE(true);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/inputflinger/InputDeviceMetricsCollector.cpp b/services/inputflinger/InputDeviceMetricsCollector.cpp
index 999e175..7c99a1c 100644
--- a/services/inputflinger/InputDeviceMetricsCollector.cpp
+++ b/services/inputflinger/InputDeviceMetricsCollector.cpp
@@ -39,6 +39,8 @@
  */
 const bool DEBUG = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
 
+constexpr size_t INTERACTIONS_QUEUE_CAPACITY = 500;
+
 int32_t linuxBusToInputDeviceBusEnum(int32_t linuxBus) {
     // When adding cases to this switch, also add them to the copy of this method in
     // TouchpadInputMapper.cpp.
@@ -201,7 +203,10 @@
 InputDeviceMetricsCollector::InputDeviceMetricsCollector(InputListenerInterface& listener,
                                                          InputDeviceMetricsLogger& logger,
                                                          nanoseconds usageSessionTimeout)
-      : mNextListener(listener), mLogger(logger), mUsageSessionTimeout(usageSessionTimeout) {}
+      : mNextListener(listener),
+        mLogger(logger),
+        mUsageSessionTimeout(usageSessionTimeout),
+        mInteractionsQueue(INTERACTIONS_QUEUE_CAPACITY) {}
 
 void InputDeviceMetricsCollector::notifyInputDevicesChanged(
         const NotifyInputDevicesChangedArgs& args) {
@@ -262,6 +267,9 @@
 
 void InputDeviceMetricsCollector::notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
                                                           const std::set<Uid>& uids) {
+    if (isIgnoredInputDeviceId(deviceId)) {
+        return;
+    }
     mInteractionsQueue.push(DeviceId{deviceId}, timestamp, uids);
 }
 
diff --git a/services/inputflinger/SyncQueue.h b/services/inputflinger/SyncQueue.h
index 62efd55..84ccace 100644
--- a/services/inputflinger/SyncQueue.h
+++ b/services/inputflinger/SyncQueue.h
@@ -27,6 +27,10 @@
 template <class T>
 class SyncQueue {
 public:
+    SyncQueue() = default;
+
+    SyncQueue(size_t capacity) : mCapacity(capacity) {}
+
     /** Retrieve and remove the oldest object. Returns std::nullopt if the queue is empty. */
     std::optional<T> pop() {
         std::scoped_lock lock(mLock);
@@ -38,14 +42,23 @@
         return t;
     };
 
-    /** Add a new object to the queue. */
+    /**
+     * Add a new object to the queue.
+     * Return true if an element was successfully added.
+     * Return false if the queue is full.
+     */
     template <class... Args>
-    void push(Args&&... args) {
+    bool push(Args&&... args) {
         std::scoped_lock lock(mLock);
+        if (mCapacity && mQueue.size() == mCapacity) {
+            return false;
+        }
         mQueue.emplace_back(args...);
+        return true;
     };
 
 private:
+    const std::optional<size_t> mCapacity;
     std::mutex mLock;
     std::list<T> mQueue GUARDED_BY(mLock);
 };
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index f0b1072..cdc4c08 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -49,15 +49,38 @@
       "name": "CtsViewTestCases",
       "options": [
         {
-          "include-filter": "android.view.cts.input",
-          "include-filter": "android.view.cts.HoverTest",
-          "include-filter": "android.view.cts.MotionEventTest",
-          "include-filter": "android.view.cts.PointerCaptureTest",
-          "include-filter": "android.view.cts.TooltipTest",
-          "include-filter": "android.view.cts.TouchDelegateTest",
-          "include-filter": "android.view.cts.VelocityTrackerTest",
-          "include-filter": "android.view.cts.VerifyInputEventTest",
-          "include-filter": "android.view.cts.ViewTest",
+          "include-filter": "android.view.cts.input"
+        }
+      ]
+    },
+    {
+      "name": "CtsViewTestCases",
+      "options": [
+        {
+          "include-filter": "android.view.cts.HoverTest"
+        },
+        {
+          "include-filter": "android.view.cts.MotionEventTest"
+        },
+        {
+          "include-filter": "android.view.cts.PointerCaptureTest"
+        },
+        {
+          "include-filter": "android.view.cts.TooltipTest"
+        },
+        {
+          "include-filter": "android.view.cts.TouchDelegateTest"
+        },
+        {
+          "include-filter": "android.view.cts.VelocityTrackerTest"
+        },
+        {
+          "include-filter": "android.view.cts.VerifyInputEventTest"
+        },
+        {
+          "include-filter": "android.view.cts.ViewTest"
+        },
+        {
           "include-filter": "android.view.cts.ViewUnbufferedTest"
         }
       ]
@@ -66,7 +89,9 @@
       "name": "CtsWidgetTestCases",
       "options": [
         {
-          "include-filter": "android.widget.cts.NumberPickerTest",
+          "include-filter": "android.widget.cts.NumberPickerTest"
+        },
+        {
           "include-filter": "android.widget.cts.SeekBarTest"
         }
       ]
@@ -75,8 +100,17 @@
       "name": "FrameworksCoreTests",
       "options": [
         {
-          "include-filter": "android.hardware.input",
-          "include-filter": "android.view.VerifiedKeyEventTest",
+          "include-filter": "android.hardware.input"
+        }
+      ]
+    },
+    {
+      "name": "FrameworksCoreTests",
+      "options": [
+        {
+          "include-filter": "android.view.VerifiedKeyEventTest"
+        },
+        {
           "include-filter": "android.view.VerifiedMotionEventTest"
         }
       ]
@@ -153,15 +187,38 @@
       "name": "CtsViewTestCases",
       "options": [
         {
-          "include-filter": "android.view.cts.input",
-          "include-filter": "android.view.cts.HoverTest",
-          "include-filter": "android.view.cts.MotionEventTest",
-          "include-filter": "android.view.cts.PointerCaptureTest",
-          "include-filter": "android.view.cts.TooltipTest",
-          "include-filter": "android.view.cts.TouchDelegateTest",
-          "include-filter": "android.view.cts.VelocityTrackerTest",
-          "include-filter": "android.view.cts.VerifyInputEventTest",
-          "include-filter": "android.view.cts.ViewTest",
+          "include-filter": "android.view.cts.input"
+        }
+      ]
+    },
+    {
+      "name": "CtsViewTestCases",
+      "options": [
+        {
+          "include-filter": "android.view.cts.HoverTest"
+        },
+        {
+          "include-filter": "android.view.cts.MotionEventTest"
+        },
+        {
+          "include-filter": "android.view.cts.PointerCaptureTest"
+        },
+        {
+          "include-filter": "android.view.cts.TooltipTest"
+        },
+        {
+          "include-filter": "android.view.cts.TouchDelegateTest"
+        },
+        {
+          "include-filter": "android.view.cts.VelocityTrackerTest"
+        },
+        {
+          "include-filter": "android.view.cts.VerifyInputEventTest"
+        },
+        {
+          "include-filter": "android.view.cts.ViewTest"
+        },
+        {
           "include-filter": "android.view.cts.ViewUnbufferedTest"
         }
       ]
@@ -170,7 +227,9 @@
       "name": "CtsWidgetTestCases",
       "options": [
         {
-          "include-filter": "android.widget.cts.NumberPickerTest",
+          "include-filter": "android.widget.cts.NumberPickerTest"
+        },
+        {
           "include-filter": "android.widget.cts.SeekBarTest"
         }
       ]
@@ -179,7 +238,9 @@
       "name": "FrameworksCoreTests",
       "options": [
         {
-          "include-filter": "android.view.VerifiedKeyEventTest",
+          "include-filter": "android.view.VerifiedKeyEventTest"
+        },
+        {
           "include-filter": "android.view.VerifiedMotionEventTest"
         }
       ]
diff --git a/include/input/EventBuilders.h b/services/inputflinger/include/NotifyArgsBuilders.h
similarity index 60%
rename from include/input/EventBuilders.h
rename to services/inputflinger/include/NotifyArgsBuilders.h
index 09438e9..e4363a4 100644
--- a/include/input/EventBuilders.h
+++ b/services/inputflinger/include/NotifyArgsBuilders.h
@@ -19,145 +19,15 @@
 #include <NotifyArgs.h>
 #include <android/input.h>
 #include <attestation/HmacKeyManager.h>
+#include <gui/constants.h>
 #include <input/Input.h>
+#include <input/InputEventBuilders.h>
+#include <utils/Timers.h> // for nsecs_t, systemTime
+
 #include <vector>
 
 namespace android {
 
-// An arbitrary device id.
-static constexpr uint32_t DEFAULT_DEVICE_ID = 1;
-
-// The default policy flags to use for event injection by tests.
-static constexpr uint32_t DEFAULT_POLICY_FLAGS = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
-
-class PointerBuilder {
-public:
-    PointerBuilder(int32_t id, ToolType toolType) {
-        mProperties.clear();
-        mProperties.id = id;
-        mProperties.toolType = toolType;
-        mCoords.clear();
-    }
-
-    PointerBuilder& x(float x) { return axis(AMOTION_EVENT_AXIS_X, x); }
-
-    PointerBuilder& y(float y) { return axis(AMOTION_EVENT_AXIS_Y, y); }
-
-    PointerBuilder& axis(int32_t axis, float value) {
-        mCoords.setAxisValue(axis, value);
-        return *this;
-    }
-
-    PointerProperties buildProperties() const { return mProperties; }
-
-    PointerCoords buildCoords() const { return mCoords; }
-
-private:
-    PointerProperties mProperties;
-    PointerCoords mCoords;
-};
-
-class MotionEventBuilder {
-public:
-    MotionEventBuilder(int32_t action, int32_t source) {
-        mAction = action;
-        mSource = source;
-        mEventTime = systemTime(SYSTEM_TIME_MONOTONIC);
-        mDownTime = mEventTime;
-    }
-
-    MotionEventBuilder& deviceId(int32_t deviceId) {
-        mDeviceId = deviceId;
-        return *this;
-    }
-
-    MotionEventBuilder& downTime(nsecs_t downTime) {
-        mDownTime = downTime;
-        return *this;
-    }
-
-    MotionEventBuilder& eventTime(nsecs_t eventTime) {
-        mEventTime = eventTime;
-        return *this;
-    }
-
-    MotionEventBuilder& displayId(int32_t displayId) {
-        mDisplayId = displayId;
-        return *this;
-    }
-
-    MotionEventBuilder& actionButton(int32_t actionButton) {
-        mActionButton = actionButton;
-        return *this;
-    }
-
-    MotionEventBuilder& buttonState(int32_t buttonState) {
-        mButtonState = buttonState;
-        return *this;
-    }
-
-    MotionEventBuilder& rawXCursorPosition(float rawXCursorPosition) {
-        mRawXCursorPosition = rawXCursorPosition;
-        return *this;
-    }
-
-    MotionEventBuilder& rawYCursorPosition(float rawYCursorPosition) {
-        mRawYCursorPosition = rawYCursorPosition;
-        return *this;
-    }
-
-    MotionEventBuilder& pointer(PointerBuilder pointer) {
-        mPointers.push_back(pointer);
-        return *this;
-    }
-
-    MotionEventBuilder& addFlag(uint32_t flags) {
-        mFlags |= flags;
-        return *this;
-    }
-
-    MotionEvent build() {
-        std::vector<PointerProperties> pointerProperties;
-        std::vector<PointerCoords> pointerCoords;
-        for (const PointerBuilder& pointer : mPointers) {
-            pointerProperties.push_back(pointer.buildProperties());
-            pointerCoords.push_back(pointer.buildCoords());
-        }
-
-        // Set mouse cursor position for the most common cases to avoid boilerplate.
-        if (mSource == AINPUT_SOURCE_MOUSE &&
-            !MotionEvent::isValidCursorPosition(mRawXCursorPosition, mRawYCursorPosition)) {
-            mRawXCursorPosition = pointerCoords[0].getX();
-            mRawYCursorPosition = pointerCoords[0].getY();
-        }
-
-        MotionEvent event;
-        static const ui::Transform kIdentityTransform;
-        event.initialize(InputEvent::nextId(), mDeviceId, mSource, mDisplayId, INVALID_HMAC,
-                         mAction, mActionButton, mFlags, /*edgeFlags=*/0, AMETA_NONE, mButtonState,
-                         MotionClassification::NONE, kIdentityTransform,
-                         /*xPrecision=*/0, /*yPrecision=*/0, mRawXCursorPosition,
-                         mRawYCursorPosition, kIdentityTransform, mDownTime, mEventTime,
-                         mPointers.size(), pointerProperties.data(), pointerCoords.data());
-        return event;
-    }
-
-private:
-    int32_t mAction;
-    int32_t mDeviceId{DEFAULT_DEVICE_ID};
-    int32_t mSource;
-    nsecs_t mDownTime;
-    nsecs_t mEventTime;
-    int32_t mDisplayId{ADISPLAY_ID_DEFAULT};
-    int32_t mActionButton{0};
-    int32_t mButtonState{0};
-    int32_t mFlags{0};
-    float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
-    float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
-
-    std::vector<PointerBuilder> mPointers;
-};
-
 class MotionArgsBuilder {
 public:
     MotionArgsBuilder(int32_t action, int32_t source) {
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index ca4dd1e..986dabb 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -58,13 +58,14 @@
 };
 
 const std::vector<CurveSegment> segments = {
-        {10.922, 3.19, 0},
-        {31.750, 4.79, -17.526},
-        {98.044, 7.28, -96.52},
-        {std::numeric_limits<double>::infinity(), 15.04, -857.758},
+        {32.002, 3.19, 0},
+        {52.83, 4.79, -51.254},
+        {119.124, 7.28, -182.737},
+        {std::numeric_limits<double>::infinity(), 15.04, -1107.556},
 };
 
-const std::vector<double> sensitivityFactors = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 18};
+const std::vector<double> sensitivityFactors = {1,  2,  4,  6,  7,  8,  9, 10,
+                                                11, 12, 13, 14, 16, 18, 20};
 
 std::vector<double> createAccelerationCurveForSensitivity(int32_t sensitivity,
                                                           size_t propertySize) {
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index 1088821..e826341 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -239,6 +239,11 @@
         out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP, /* actionButton= */ 0,
                                      newButtonState, /* pointerCount= */ 1, mFingerProps.data(),
                                      &coords, xCursorPosition, yCursorPosition));
+        // Send a HOVER_MOVE to tell the application that the mouse is hovering again.
+        out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_HOVER_MOVE,
+                                     /*actionButton=*/0, newButtonState, /*pointerCount=*/1,
+                                     mFingerProps.data(), &coords, xCursorPosition,
+                                     yCursorPosition));
     }
     mButtonState = newButtonState;
     return out;
diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index a3994f0..482a266 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -169,7 +169,7 @@
                            /* down= */ GESTURES_BUTTON_NONE, /* up= */ GESTURES_BUTTON_RIGHT,
                            /* is_tap= */ false);
     args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, rightUpGesture);
-    ASSERT_EQ(2u, args.size());
+    ASSERT_EQ(3u, args.size());
 
     ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()),
                 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
@@ -181,6 +181,10 @@
                 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0),
                       WithCoords(POINTER_X, POINTER_Y),
                       WithToolType(ToolType::FINGER)));
+    args.pop_front();
+    ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()),
+                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithButtonState(0),
+                      WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER)));
 }
 
 TEST_F(GestureConverterTest, DragWithButton) {
@@ -225,7 +229,7 @@
                       /* down= */ GESTURES_BUTTON_NONE, /* up= */ GESTURES_BUTTON_LEFT,
                       /* is_tap= */ false);
     args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, upGesture);
-    ASSERT_EQ(2u, args.size());
+    ASSERT_EQ(3u, args.size());
 
     ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()),
                 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
@@ -237,6 +241,10 @@
                 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0),
                       WithCoords(POINTER_X - 5, POINTER_Y + 10),
                       WithToolType(ToolType::FINGER)));
+    args.pop_front();
+    ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()),
+                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithButtonState(0),
+                      WithCoords(POINTER_X - 5, POINTER_Y + 10), WithToolType(ToolType::FINGER)));
 }
 
 TEST_F(GestureConverterTest, Scroll) {
diff --git a/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp b/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp
index 0aa5e23..2ff64c8 100644
--- a/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp
+++ b/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp
@@ -16,9 +16,10 @@
 
 #include "../InputDeviceMetricsCollector.h"
 
+#include <NotifyArgsBuilders.h>
 #include <gtest/gtest.h>
 #include <gui/constants.h>
-#include <input/EventBuilders.h>
+#include <input/InputEventBuilders.h>
 #include <linux/input.h>
 
 #include <array>
@@ -421,6 +422,7 @@
         // Device was used.
         mMetricsCollector.notifyMotion(generateMotionArgs(ignoredDeviceId));
         mTestListener.assertNotifyMotionWasCalled();
+        mMetricsCollector.notifyDeviceInteraction(ignoredDeviceId, TIME.count(), uids({0, 1, 2}));
         ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
 
         // Device was used again after the usage timeout expired, but we still don't log usage.
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 5af9999..51202b7 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -17,6 +17,7 @@
 #include "../dispatcher/InputDispatcher.h"
 #include "../BlockingQueue.h"
 
+#include <NotifyArgsBuilders.h>
 #include <android-base/properties.h>
 #include <android-base/silent_death_test.h>
 #include <android-base/stringprintf.h>
@@ -25,7 +26,6 @@
 #include <fcntl.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-#include <input/EventBuilders.h>
 #include <input/Input.h>
 #include <linux/input.h>
 #include <sys/epoll.h>
diff --git a/services/inputflinger/tests/SyncQueue_test.cpp b/services/inputflinger/tests/SyncQueue_test.cpp
index af2f961..b57ccc2 100644
--- a/services/inputflinger/tests/SyncQueue_test.cpp
+++ b/services/inputflinger/tests/SyncQueue_test.cpp
@@ -50,6 +50,18 @@
     }
 }
 
+// Make sure the queue has strict capacity limits.
+TEST(SyncQueueTest, QueueReachesCapacity) {
+    constexpr size_t capacity = 3;
+    SyncQueue<int> queue(capacity);
+
+    // First 3 elements should be added successfully
+    ASSERT_TRUE(queue.push(1));
+    ASSERT_TRUE(queue.push(2));
+    ASSERT_TRUE(queue.push(3));
+    ASSERT_FALSE(queue.push(4)) << "Queue should reach capacity at size " << capacity;
+}
+
 TEST(SyncQueueTest, AllowsMultipleThreads) {
     SyncQueue<int> queue;
 
diff --git a/services/inputflinger/tests/TouchpadInputMapper_test.cpp b/services/inputflinger/tests/TouchpadInputMapper_test.cpp
index 92cd462..02abf9f 100644
--- a/services/inputflinger/tests/TouchpadInputMapper_test.cpp
+++ b/services/inputflinger/tests/TouchpadInputMapper_test.cpp
@@ -139,7 +139,8 @@
                             VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)),
                             VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_PRESS)),
                             VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)),
-                            VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP))));
+                            VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)),
+                            VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE))));
 
     // Liftoff
     args.clear();
diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp
index 09dac23..b345913 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.cpp
+++ b/services/surfaceflinger/ScreenCaptureOutput.cpp
@@ -24,6 +24,24 @@
 
 namespace android {
 
+namespace {
+
+ui::Size getDisplaySize(ui::Rotation orientation, const Rect& sourceCrop) {
+    if (orientation == ui::Rotation::Rotation90 || orientation == ui::Rotation::Rotation270) {
+        return {sourceCrop.getHeight(), sourceCrop.getWidth()};
+    }
+    return {sourceCrop.getWidth(), sourceCrop.getHeight()};
+}
+
+Rect getOrientedDisplaySpaceRect(ui::Rotation orientation, int reqWidth, int reqHeight) {
+    if (orientation == ui::Rotation::Rotation90 || orientation == ui::Rotation::Rotation270) {
+        return {reqHeight, reqWidth};
+    }
+    return {reqWidth, reqHeight};
+}
+
+} // namespace
+
 std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutputArgs args) {
     std::shared_ptr<ScreenCaptureOutput> output = compositionengine::impl::createOutputTemplated<
             ScreenCaptureOutput, compositionengine::CompositionEngine, const RenderArea&,
@@ -45,10 +63,10 @@
 
     const Rect& sourceCrop = args.renderArea.getSourceCrop();
     const ui::Rotation orientation = ui::Transform::toRotation(args.renderArea.getRotationFlags());
-    const Rect orientedDisplaySpaceRect{args.renderArea.getReqWidth(),
-                                        args.renderArea.getReqHeight()};
-    output->setProjection(orientation, sourceCrop, orientedDisplaySpaceRect);
-    output->setDisplaySize({sourceCrop.getWidth(), sourceCrop.getHeight()});
+    output->setDisplaySize(getDisplaySize(orientation, sourceCrop));
+    output->setProjection(orientation, sourceCrop,
+                          getOrientedDisplaySpaceRect(orientation, args.renderArea.getReqWidth(),
+                                                      args.renderArea.getReqHeight()));
 
     {
         std::string name = args.regionSampling ? "RegionSampling" : "ScreenCaptureOutput";
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 013694f..96cc333 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -19,6 +19,7 @@
 #pragma clang diagnostic ignored "-Wconversion"
 
 #include <private/android_filesystem_config.h>
+#include <ui/DisplayState.h>
 
 #include "LayerTransactionTest.h"
 
@@ -32,11 +33,11 @@
 
         const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
         ASSERT_FALSE(ids.empty());
-        const auto display = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
-        ASSERT_FALSE(display == nullptr);
+        mDisplayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
+        ASSERT_FALSE(mDisplayToken == nullptr);
 
         ui::DisplayMode mode;
-        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(mDisplayToken, &mode));
         const ui::Size& resolution = mode.resolution;
 
         mDisplaySize = resolution;
@@ -57,7 +58,7 @@
         TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
 
         asTransaction([&](Transaction& t) {
-            t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
+            t.setDisplayLayerStack(mDisplayToken, ui::DEFAULT_LAYER_STACK);
 
             t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl);
 
@@ -71,11 +72,18 @@
         LayerTransactionTest::TearDown();
         mBGSurfaceControl = 0;
         mFGSurfaceControl = 0;
+
+        // Restore display rotation
+        asTransaction([&](Transaction& t) {
+            Rect displayBounds{mDisplaySize};
+            t.setDisplayProjection(mDisplayToken, ui::ROTATION_0, displayBounds, displayBounds);
+        });
     }
 
     sp<SurfaceControl> mBGSurfaceControl;
     sp<SurfaceControl> mFGSurfaceControl;
     std::unique_ptr<ScreenCapture> mCapture;
+    sp<IBinder> mDisplayToken;
     ui::Size mDisplaySize;
 };
 
@@ -870,6 +878,42 @@
     mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED);
 }
 
+TEST_F(ScreenCaptureTest, CaptureDisplayWith90DegRotation) {
+    asTransaction([&](Transaction& t) {
+        Rect newDisplayBounds{mDisplaySize.height, mDisplaySize.width};
+        t.setDisplayProjection(mDisplayToken, ui::ROTATION_90, newDisplayBounds, newDisplayBounds);
+    });
+
+    DisplayCaptureArgs displayCaptureArgs;
+    displayCaptureArgs.displayToken = mDisplayToken;
+    displayCaptureArgs.width = mDisplaySize.width;
+    displayCaptureArgs.height = mDisplaySize.height;
+    displayCaptureArgs.useIdentityTransform = true;
+    ScreenCapture::captureDisplay(&mCapture, displayCaptureArgs);
+
+    mCapture->expectBGColor(0, 0);
+    mCapture->expectFGColor(mDisplaySize.width - 65, 65);
+}
+
+TEST_F(ScreenCaptureTest, CaptureDisplayWith270DegRotation) {
+    asTransaction([&](Transaction& t) {
+        Rect newDisplayBounds{mDisplaySize.height, mDisplaySize.width};
+        t.setDisplayProjection(mDisplayToken, ui::ROTATION_270, newDisplayBounds, newDisplayBounds);
+    });
+
+    DisplayCaptureArgs displayCaptureArgs;
+    displayCaptureArgs.displayToken = mDisplayToken;
+    displayCaptureArgs.width = mDisplaySize.width;
+    displayCaptureArgs.height = mDisplaySize.height;
+    displayCaptureArgs.useIdentityTransform = true;
+    ScreenCapture::captureDisplay(&mCapture, displayCaptureArgs);
+
+    std::this_thread::sleep_for(std::chrono::seconds{5});
+
+    mCapture->expectBGColor(mDisplayWidth - 1, mDisplaySize.height - 1);
+    mCapture->expectFGColor(65, mDisplaySize.height - 65);
+}
+
 TEST_F(ScreenCaptureTest, CaptureNonHdrLayer) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32,