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,