diff options
87 files changed, 1363 insertions, 850 deletions
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp index e61eb6e52f..d236f76645 100644 --- a/cmds/installd/tests/installd_utils_test.cpp +++ b/cmds/installd/tests/installd_utils_test.cpp @@ -104,12 +104,12 @@ TEST_F(UtilsTest, IsValidApkPath_Internal) { EXPECT_EQ(-1, validate_apk_path(badint2)) << badint2 << " should be rejected as a invalid path"; - // Only one subdir should be allowed. - const char *bad_path3 = TEST_APP_DIR "example.com/subdir/pkg.apk"; + // Should not have more than two sub directories + const char *bad_path3 = TEST_APP_DIR "random/example.com/subdir/pkg.apk"; EXPECT_EQ(-1, validate_apk_path(bad_path3)) << bad_path3 << " should be rejected as a invalid path"; - const char *bad_path4 = TEST_APP_DIR "example.com/subdir/../pkg.apk"; + const char *bad_path4 = TEST_APP_DIR "random/example.com/subdir/pkg.apk"; EXPECT_EQ(-1, validate_apk_path(bad_path4)) << bad_path4 << " should be rejected as a invalid path"; @@ -120,6 +120,7 @@ TEST_F(UtilsTest, IsValidApkPath_Internal) { TEST_F(UtilsTest, IsValidApkPath_TopDir) { EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/com.example")); + EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/random/com.example")); EXPECT_EQ(0, validate_apk_path(TEST_EXPAND_DIR "app/com.example")); EXPECT_EQ(-1, validate_apk_path(TEST_DATA_DIR "data/com.example")); EXPECT_EQ(-1, validate_apk_path(TEST_EXPAND_DIR "data/com.example")); @@ -127,6 +128,7 @@ TEST_F(UtilsTest, IsValidApkPath_TopDir) { TEST_F(UtilsTest, IsValidApkPath_TopFile) { EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/com.example/base.apk")); + EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/random/com.example/base.apk")); EXPECT_EQ(0, validate_apk_path(TEST_EXPAND_DIR "app/com.example/base.apk")); EXPECT_EQ(-1, validate_apk_path(TEST_DATA_DIR "data/com.example/base.apk")); EXPECT_EQ(-1, validate_apk_path(TEST_EXPAND_DIR "data/com.example/base.apk")); @@ -134,6 +136,7 @@ TEST_F(UtilsTest, IsValidApkPath_TopFile) { TEST_F(UtilsTest, IsValidApkPath_OatDir) { EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat")); + EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/random/com.example/oat")); EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat")); EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat")); EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat")); @@ -141,6 +144,7 @@ TEST_F(UtilsTest, IsValidApkPath_OatDir) { TEST_F(UtilsTest, IsValidApkPath_OatDirDir) { EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat/arm64")); + EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/random/com.example/oat/arm64")); EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat/arm64")); EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat/arm64")); EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat/arm64")); @@ -148,6 +152,7 @@ TEST_F(UtilsTest, IsValidApkPath_OatDirDir) { TEST_F(UtilsTest, IsValidApkPath_OatDirDirFile) { EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat/arm64/base.odex")); + EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/random/com.example/oat/arm64/base.odex")); EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat/arm64/base.odex")); EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat/arm64/base.odex")); EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat/arm64/base.odex")); @@ -164,6 +169,10 @@ TEST_F(UtilsTest, IsValidApkPath_Private) { EXPECT_EQ(0, validate_apk_path(path2)) << path2 << " should be allowed as a valid path"; + const char *path3 = TEST_APP_DIR "random/example.com/example.apk"; + EXPECT_EQ(0, validate_apk_path(path3)) + << path3 << " should be allowed as a valid path"; + const char *badpriv1 = TEST_APP_PRIVATE_DIR "../example.apk"; EXPECT_EQ(-1, validate_apk_path(badpriv1)) << badpriv1 << " should be rejected as a invalid path"; @@ -172,16 +181,16 @@ TEST_F(UtilsTest, IsValidApkPath_Private) { EXPECT_EQ(-1, validate_apk_path(badpriv2)) << badpriv2 << " should be rejected as a invalid path"; - // Only one subdir should be allowed. - const char *bad_path3 = TEST_APP_PRIVATE_DIR "example.com/subdir/pkg.apk"; + // Only one or two subdir should be allowed. + const char *bad_path3 = TEST_APP_PRIVATE_DIR "random/example.com/subdir/pkg.apk"; EXPECT_EQ(-1, validate_apk_path(bad_path3)) << bad_path3 << " should be rejected as a invalid path"; - const char *bad_path4 = TEST_APP_PRIVATE_DIR "example.com/subdir/../pkg.apk"; + const char *bad_path4 = TEST_APP_PRIVATE_DIR "random/example.com/subdir/../pkg.apk"; EXPECT_EQ(-1, validate_apk_path(bad_path4)) << bad_path4 << " should be rejected as a invalid path"; - const char *bad_path5 = TEST_APP_PRIVATE_DIR "example.com1/../example.com2/pkg.apk"; + const char *bad_path5 = TEST_APP_PRIVATE_DIR "random/example.com1/../example.com2/pkg.apk"; EXPECT_EQ(-1, validate_apk_path(bad_path5)) << bad_path5 << " should be rejected as a invalid path"; } @@ -229,10 +238,16 @@ TEST_F(UtilsTest, IsValidApkPath_SubdirEscapeSingleFail) { << badasec6 << " should be rejected as a invalid path"; } -TEST_F(UtilsTest, IsValidApkPath_TwoSubdirFail) { - const char *badasec7 = TEST_ASEC_DIR "com.example.asec/subdir1/pkg.apk"; - EXPECT_EQ(-1, validate_apk_path(badasec7)) - << badasec7 << " should be rejected as a invalid path"; +TEST_F(UtilsTest, IsValidApkPath_TwoSubdir) { + const char *badasec7 = TEST_ASEC_DIR "random/com.example.asec/pkg.apk"; + EXPECT_EQ(0, validate_apk_path(badasec7)) + << badasec7 << " should be allowed as a valid path"; +} + +TEST_F(UtilsTest, IsValidApkPath_ThreeSubdirFail) { + const char *badasec8 = TEST_ASEC_DIR "random/com.example.asec/subdir/pkg.apk"; + EXPECT_EQ(-1, validate_apk_path(badasec8)) + << badasec8 << " should be rejcted as an invalid path"; } TEST_F(UtilsTest, CheckSystemApp_Dir1) { @@ -511,8 +526,8 @@ TEST_F(UtilsTest, ValidateApkPath) { EXPECT_EQ(0, validate_apk_path("/data/app/com.example")); EXPECT_EQ(0, validate_apk_path("/data/app/com.example/file")); EXPECT_EQ(0, validate_apk_path("/data/app/com.example//file")); - EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/")); - EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/file")); + EXPECT_EQ(0, validate_apk_path("/data/app/random/com.example/")); + EXPECT_EQ(0, validate_apk_path("/data/app/random/com.example/file")); EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/file")); EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir//file")); EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/dir/file")); @@ -527,8 +542,10 @@ TEST_F(UtilsTest, ValidateApkPathSubdirs) { EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/file")); EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/file")); EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir//file")); - EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir/file")); - EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir//file")); + EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir/file")); + EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir//file")); + EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir/dir/file")); + EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir/dir//file")); } TEST_F(UtilsTest, MatchExtension_Valid) { diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index 6012822f69..939cf90119 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -954,11 +954,11 @@ static int validate_apk_path_internal(const std::string& path, int maxSubdirs) { } int validate_apk_path(const char* path) { - return validate_apk_path_internal(path, 1 /* maxSubdirs */); + return validate_apk_path_internal(path, 2 /* maxSubdirs */); } int validate_apk_path_subdirs(const char* path) { - return validate_apk_path_internal(path, 3 /* maxSubdirs */); + return validate_apk_path_internal(path, 4 /* maxSubdirs */); } int ensure_config_user_dirs(userid_t userid) { diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index ae74ac3847..abe64365f3 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -423,11 +423,12 @@ ssize_t ServiceManager::Service::getNodeStrongRefCount() { void ServiceManager::handleClientCallbacks() { for (const auto& [name, service] : mNameToService) { - handleServiceClientCallback(name); + handleServiceClientCallback(name, true); } } -ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName) { +ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName, + bool isCalledOnInterval) { auto serviceIt = mNameToService.find(serviceName); if (serviceIt == mNameToService.end() || mNameToClientCallback.count(serviceName) < 1) { return -1; @@ -451,14 +452,17 @@ ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceNa service.guaranteeClient = false; } - if (hasClients && !service.hasClients) { - // client was retrieved in some other way - sendClientCallbackNotifications(serviceName, true); - } + // only send notifications if this was called via the interval checking workflow + if (isCalledOnInterval) { + if (hasClients && !service.hasClients) { + // client was retrieved in some other way + sendClientCallbackNotifications(serviceName, true); + } - // there are no more clients, but the callback has not been called yet - if (!hasClients && service.hasClients) { - sendClientCallbackNotifications(serviceName, false); + // there are no more clients, but the callback has not been called yet + if (!hasClients && service.hasClients) { + sendClientCallbackNotifications(serviceName, false); + } } return count; @@ -518,7 +522,7 @@ Status ServiceManager::tryUnregisterService(const std::string& name, const sp<IB return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } - int clients = handleServiceClientCallback(name); + int clients = handleServiceClientCallback(name, false); // clients < 0: feature not implemented or other error. Assume clients. // Otherwise: @@ -527,7 +531,7 @@ Status ServiceManager::tryUnregisterService(const std::string& name, const sp<IB // So, if clients > 2, then at least one other service on the system must hold a refcount. if (clients < 0 || clients > 2) { // client callbacks are either disabled or there are other clients - LOG(INFO) << "Tried to unregister " << name << " but there are clients: " << clients; + LOG(INFO) << "Tried to unregister " << name << ", but there are clients: " << clients; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h index 77f52506b9..a2fc5a84c5 100644 --- a/cmds/servicemanager/ServiceManager.h +++ b/cmds/servicemanager/ServiceManager.h @@ -75,7 +75,7 @@ private: void removeRegistrationCallback(const wp<IBinder>& who, ServiceCallbackMap::iterator* it, bool* found); - ssize_t handleServiceClientCallback(const std::string& serviceName); + ssize_t handleServiceClientCallback(const std::string& serviceName, bool isCalledOnInterval); // Also updates mHasClients (of what the last callback was) void sendClientCallbackNotifications(const std::string& serviceName, bool hasClients); // removes a callback from mNameToClientCallback, deleting the entry if the vector is empty diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h index da324b839a..0d943b7800 100644 --- a/include/android/imagedecoder.h +++ b/include/android/imagedecoder.h @@ -27,7 +27,7 @@ #define ANDROID_IMAGE_DECODER_H #include "bitmap.h" - +#include <android/rect.h> #include <stdint.h> #ifdef __cplusplus @@ -35,7 +35,6 @@ extern "C" { #endif struct AAsset; -struct ARect; #if __ANDROID_API__ >= 30 @@ -92,7 +91,8 @@ typedef struct AImageDecoder AImageDecoder; * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value * indicating reason for the failure. */ -int AImageDecoder_createFromAAsset(AAsset* asset, AImageDecoder** outDecoder) __INTRODUCED_IN(30); +int AImageDecoder_createFromAAsset(struct AAsset* asset, AImageDecoder** outDecoder) + __INTRODUCED_IN(30); /** * Create a new AImageDecoder from a file descriptor. diff --git a/include/input/Input.h b/include/input/Input.h index f8718479f9..cf0814cf2f 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -31,6 +31,7 @@ #include <utils/RefBase.h> #include <utils/Timers.h> #include <utils/Vector.h> +#include <array> #include <limits> #include <queue> @@ -258,6 +259,11 @@ const char* motionClassificationToString(MotionClassification classification); */ constexpr float AMOTION_EVENT_INVALID_CURSOR_POSITION = std::numeric_limits<float>::quiet_NaN(); +/** + * Invalid value of HMAC - SHA256. Any events with this HMAC value will be marked as not verified. + */ +constexpr std::array<uint8_t, 32> INVALID_HMAC = {0}; + /* * Pointer coordinate data. */ @@ -348,22 +354,25 @@ public: inline int32_t getDeviceId() const { return mDeviceId; } - inline int32_t getSource() const { return mSource; } + inline uint32_t getSource() const { return mSource; } - inline void setSource(int32_t source) { mSource = source; } + inline void setSource(uint32_t source) { mSource = source; } inline int32_t getDisplayId() const { return mDisplayId; } inline void setDisplayId(int32_t displayId) { mDisplayId = displayId; } + inline std::array<uint8_t, 32> getHmac() const { return mHmac; } protected: - void initialize(int32_t deviceId, int32_t source, int32_t displayId); + void initialize(int32_t deviceId, uint32_t source, int32_t displayId, + std::array<uint8_t, 32> hmac); void initialize(const InputEvent& from); int32_t mDeviceId; - int32_t mSource; + uint32_t mSource; int32_t mDisplayId; + std::array<uint8_t, 32> mHmac; }; /* @@ -396,18 +405,10 @@ public: static const char* getLabel(int32_t keyCode); static int32_t getKeyCodeFromLabel(const char* label); - void initialize( - int32_t deviceId, - int32_t source, - int32_t displayId, - int32_t action, - int32_t flags, - int32_t keyCode, - int32_t scanCode, - int32_t metaState, - int32_t repeatCount, - nsecs_t downTime, - nsecs_t eventTime); + void initialize(int32_t deviceId, uint32_t source, int32_t displayId, + std::array<uint8_t, 32> hmac, int32_t action, int32_t flags, int32_t keyCode, + int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime, + nsecs_t eventTime); void initialize(const KeyEvent& from); protected: @@ -463,6 +464,10 @@ public: inline void setActionButton(int32_t button) { mActionButton = button; } + inline float getXScale() const { return mXScale; } + + inline float getYScale() const { return mYScale; } + inline float getXOffset() const { return mXOffset; } inline float getYOffset() const { return mYOffset; } @@ -624,9 +629,10 @@ public: ssize_t findPointerIndex(int32_t pointerId) const; - void initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action, - int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, - int32_t buttonState, MotionClassification classification, float xOffset, + void initialize(int32_t deviceId, uint32_t source, int32_t displayId, + std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, + int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, + MotionClassification classification, float xScale, float yScale, float xOffset, float yOffset, float xPrecision, float yPrecision, float rawXCursorPosition, float rawYCursorPosition, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, @@ -651,7 +657,7 @@ public: status_t writeToParcel(Parcel* parcel) const; #endif - static bool isTouchEvent(int32_t source, int32_t action); + static bool isTouchEvent(uint32_t source, int32_t action); inline bool isTouchEvent() const { return isTouchEvent(mSource, mAction); } @@ -676,6 +682,8 @@ protected: int32_t mMetaState; int32_t mButtonState; MotionClassification mClassification; + float mXScale; + float mYScale; float mXOffset; float mYOffset; float mXPrecision; diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index ae47438ac8..06fd3bb364 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -76,6 +76,9 @@ struct InputMessage { } header; // Body *must* be 8 byte aligned. + // For keys and motions, rely on the fact that std::array takes up exactly as much space + // as the underlying data. This is not guaranteed by C++, but it simplifies the conversions. + static_assert(sizeof(std::array<uint8_t, 32>) == 32); union Body { struct Key { uint32_t seq; @@ -84,6 +87,7 @@ struct InputMessage { int32_t deviceId; int32_t source; int32_t displayId; + std::array<uint8_t, 32> hmac; int32_t action; int32_t flags; int32_t keyCode; @@ -103,6 +107,7 @@ struct InputMessage { int32_t deviceId; int32_t source; int32_t displayId; + std::array<uint8_t, 32> hmac; int32_t action; int32_t actionButton; int32_t flags; @@ -112,6 +117,8 @@ struct InputMessage { uint8_t empty2[3]; // 3 bytes to fill gap created by classification int32_t edgeFlags; nsecs_t downTime __attribute__((aligned(8))); + float xScale; + float yScale; float xOffset; float yOffset; float xPrecision; @@ -269,19 +276,10 @@ public: * Returns BAD_VALUE if seq is 0. * Other errors probably indicate that the channel is broken. */ - status_t publishKeyEvent( - uint32_t seq, - int32_t deviceId, - int32_t source, - int32_t displayId, - int32_t action, - int32_t flags, - int32_t keyCode, - int32_t scanCode, - int32_t metaState, - int32_t repeatCount, - nsecs_t downTime, - nsecs_t eventTime); + status_t publishKeyEvent(uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, + std::array<uint8_t, 32> hmac, int32_t action, int32_t flags, + int32_t keyCode, int32_t scanCode, int32_t metaState, + int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime); /* Publishes a motion event to the input channel. * @@ -292,9 +290,10 @@ public: * Other errors probably indicate that the channel is broken. */ status_t publishMotionEvent(uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, - int32_t action, int32_t actionButton, int32_t flags, - int32_t edgeFlags, int32_t metaState, int32_t buttonState, - MotionClassification classification, float xOffset, float yOffset, + std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, + int32_t flags, int32_t edgeFlags, int32_t metaState, + int32_t buttonState, MotionClassification classification, + float xScale, float yScale, float xOffset, float yOffset, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, const PointerProperties* pointerProperties, diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 238c9dcc7f..f16c39cdc1 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -435,7 +435,8 @@ void BpBinder::onLastStrongRef(const void* /*id*/) Vector<Obituary>* obits = mObituaries; if(obits != nullptr) { if (!obits->isEmpty()) { - ALOGI("onLastStrongRef automatically unlinking death recipients"); + ALOGI("onLastStrongRef automatically unlinking death recipients: %s", + mDescriptorCache.size() ? String8(mDescriptorCache).c_str() : "<uncached descriptor>"); } if (ipc) ipc->clearDeathNotification(mHandle, this); diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp index 824b56b7f3..8cf6097759 100644 --- a/libs/binder/BufferedTextOutput.cpp +++ b/libs/binder/BufferedTextOutput.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <binder/BufferedTextOutput.h> +#include "BufferedTextOutput.h" #include <binder/Debug.h> #include <cutils/atomic.h> diff --git a/libs/binder/include/binder/BufferedTextOutput.h b/libs/binder/BufferedTextOutput.h index 1b27bb2249..1b27bb2249 100644 --- a/libs/binder/include/binder/BufferedTextOutput.h +++ b/libs/binder/BufferedTextOutput.h diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp index dc9482c536..f064bd77ce 100644 --- a/libs/binder/LazyServiceRegistrar.cpp +++ b/libs/binder/LazyServiceRegistrar.cpp @@ -53,14 +53,13 @@ private: struct Service { sp<IBinder> service; - std::string name; bool allowIsolated; int dumpFlags; }; /** - * Number of services that have been registered. + * Map of registered names and services */ - std::vector<Service> mRegisteredServices; + std::map<std::string, Service> mRegisteredServices; }; bool ClientCounterCallback::registerService(const sp<IBinder>& service, const std::string& name, @@ -68,20 +67,24 @@ bool ClientCounterCallback::registerService(const sp<IBinder>& service, const st auto manager = interface_cast<AidlServiceManager>( ProcessState::self()->getContextObject(nullptr)); - ALOGI("Registering service %s", name.c_str()); + bool reRegister = mRegisteredServices.count(name) > 0; + std::string regStr = (reRegister) ? "Re-registering" : "Registering"; + ALOGI("%s service %s", regStr.c_str(), name.c_str()); if (!manager->addService(name.c_str(), service, allowIsolated, dumpFlags).isOk()) { ALOGE("Failed to register service %s", name.c_str()); return false; } - if (!manager->registerClientCallback(name, service, this).isOk()) - { - ALOGE("Failed to add client callback for service %s", name.c_str()); - return false; + if (!manager->registerClientCallback(name, service, this).isOk()) { + ALOGE("Failed to add client callback for service %s", name.c_str()); + return false; } - mRegisteredServices.push_back({service, name, allowIsolated, dumpFlags}); + if (!reRegister) { + // Only add this when a service is added for the first time, as it is not removed + mRegisteredServices[name] = {service, allowIsolated, dumpFlags}; + } return true; } @@ -119,10 +122,11 @@ void ClientCounterCallback::tryShutdown() { for (; unRegisterIt != mRegisteredServices.end(); ++unRegisterIt) { auto& entry = (*unRegisterIt); - bool success = manager->tryUnregisterService(entry.name, entry.service).isOk(); + bool success = manager->tryUnregisterService(entry.first, entry.second.service).isOk(); + if (!success) { - ALOGI("Failed to unregister service %s", entry.name.c_str()); + ALOGI("Failed to unregister service %s", entry.first.c_str()); break; } } @@ -137,7 +141,8 @@ void ClientCounterCallback::tryShutdown() { auto& entry = (*reRegisterIt); // re-register entry - if (!registerService(entry.service, entry.name, entry.allowIsolated, entry.dumpFlags)) { + if (!registerService(entry.second.service, entry.first, entry.second.allowIsolated, + entry.second.dumpFlags)) { // Must restart. Otherwise, clients will never be able to get a hold of this service. ALOGE("Bad state: could not re-register services"); } diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp index bd40536884..7a77f6de54 100644 --- a/libs/binder/Static.cpp +++ b/libs/binder/Static.cpp @@ -19,7 +19,7 @@ #include "Static.h" -#include <binder/BufferedTextOutput.h> +#include "BufferedTextOutput.h" #include <binder/IPCThreadState.h> #include <utils/Log.h> diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index b3afd817c1..7489afae29 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -19,7 +19,13 @@ "name": "binderStabilityTest" }, { + "name": "libbinder_ndk_unit_test" + }, + { "name": "CtsNdkBinderTestCases" + }, + { + "name": "aidl_lazy_test" } ] } diff --git a/libs/binder/ndk/runtests.sh b/libs/binder/ndk/runtests.sh deleted file mode 100755 index a0c49fb167..0000000000 --- a/libs/binder/ndk/runtests.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (C) 2018 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. - -if [ -z $ANDROID_BUILD_TOP ]; then - echo "You need to source and lunch before you can use this script" - exit 1 -fi - -set -ex - -function run_libbinder_ndk_test() { - adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server & - - # avoid getService 1s delay for most runs, non-critical - sleep 0.1 - - adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client; \ - adb shell killall libbinder_ndk_test_server -} - -[ "$1" != "--skip-build" ] && $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \ - MODULES-IN-frameworks-native-libs-binder-ndk - -adb root -adb wait-for-device -adb sync data - -# very simple unit tests, tests things outside of the NDK as well -run_libbinder_ndk_test - -# CTS tests (much more comprehensive, new tests should ideally go here) -atest android.binder.cts diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp index daaaa5aa7e..513d8c2eba 100644 --- a/libs/binder/ndk/test/Android.bp +++ b/libs/binder/ndk/test/Android.bp @@ -56,16 +56,17 @@ cc_defaults { // specifically the parts which are outside of the NDK. Actual users should // also instead use AIDL to generate these stubs. See android.binder.cts. cc_test { - name: "libbinder_ndk_test_client", + name: "libbinder_ndk_unit_test", defaults: ["test_libbinder_ndk_test_defaults"], - srcs: ["main_client.cpp"], -} + srcs: ["libbinder_ndk_unit_test.cpp"], + static_libs: [ + "IBinderNdkUnitTest-ndk_platform", + ], + test_suites: ["general-tests"], + require_root: true, -cc_test { - name: "libbinder_ndk_test_server", - defaults: ["test_libbinder_ndk_test_defaults"], - srcs: ["main_server.cpp"], - gtest: false, + // force since binderVendorDoubleLoadTest has its own + auto_gen_config: true, } cc_test { @@ -85,7 +86,7 @@ cc_test { "libbinder_ndk", "libutils", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], } aidl_interface { @@ -95,3 +96,11 @@ aidl_interface { "IBinderVendorDoubleLoadTest.aidl", ], } + +aidl_interface { + name: "IBinderNdkUnitTest", + srcs: [ + "IBinderNdkUnitTest.aidl", + "IEmpty.aidl", + ], +} diff --git a/libs/binder/ndk/test/IBinderNdkUnitTest.aidl b/libs/binder/ndk/test/IBinderNdkUnitTest.aidl new file mode 100644 index 0000000000..6e8e463ff1 --- /dev/null +++ b/libs/binder/ndk/test/IBinderNdkUnitTest.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020 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. + */ + +// This AIDL is to test things that can't be tested in CtsNdkBinderTestCases +// because it requires libbinder_ndk implementation details or APIs not +// available to apps. Please prefer adding tests to CtsNdkBinderTestCases +// over here. + +import IEmpty; + +interface IBinderNdkUnitTest { + void takeInterface(IEmpty test); + void forceFlushCommands(); +} diff --git a/libs/binder/ndk/test/IEmpty.aidl b/libs/binder/ndk/test/IEmpty.aidl new file mode 100644 index 0000000000..95e4341531 --- /dev/null +++ b/libs/binder/ndk/test/IEmpty.aidl @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2020 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. + */ + +interface IEmpty { } diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp index 8467734c75..51dd169ec0 100644 --- a/libs/binder/ndk/test/main_client.cpp +++ b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include <aidl/BnBinderNdkUnitTest.h> +#include <aidl/BnEmpty.h> #include <android-base/logging.h> #include <android/binder_ibinder_jni.h> #include <android/binder_manager.h> @@ -21,6 +23,11 @@ #include <gtest/gtest.h> #include <iface/iface.h> +// warning: this is assuming that libbinder_ndk is using the same copy +// of libbinder that we are. +#include <binder/IPCThreadState.h> + +#include <sys/prctl.h> #include <chrono> #include <condition_variable> #include <mutex> @@ -28,6 +35,65 @@ using ::android::sp; constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; +constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest"; + +class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest { + ndk::ScopedAStatus takeInterface(const std::shared_ptr<aidl::IEmpty>& empty) { + (void)empty; + return ndk::ScopedAStatus::ok(); + } + ndk::ScopedAStatus forceFlushCommands() { + // warning: this is assuming that libbinder_ndk is using the same copy + // of libbinder that we are. + android::IPCThreadState::self()->flushCommands(); + return ndk::ScopedAStatus::ok(); + } +}; + +int generatedService() { + ABinderProcess_setThreadPoolMaxThreadCount(0); + + auto service = ndk::SharedRefBase::make<MyBinderNdkUnitTest>(); + binder_status_t status = + AServiceManager_addService(service->asBinder().get(), kBinderNdkUnitTestService); + + if (status != STATUS_OK) { + LOG(FATAL) << "Could not register: " << status << " " << kBinderNdkUnitTestService; + } + + ABinderProcess_joinThreadPool(); + + return 1; // should not return +} + +// manually-written parceling class considered bad practice +class MyFoo : public IFoo { + binder_status_t doubleNumber(int32_t in, int32_t* out) override { + *out = 2 * in; + LOG(INFO) << "doubleNumber (" << in << ") => " << *out; + return STATUS_OK; + } + + binder_status_t die() override { + LOG(FATAL) << "IFoo::die called!"; + return STATUS_UNKNOWN_ERROR; + } +}; + +int manualService(const char* instance) { + ABinderProcess_setThreadPoolMaxThreadCount(0); + + // Strong reference to MyFoo kept by service manager. + binder_status_t status = (new MyFoo)->addService(instance); + + if (status != STATUS_OK) { + LOG(FATAL) << "Could not register: " << status << " " << instance; + } + + ABinderProcess_joinThreadPool(); + + return 1; // should not return +} // This is too slow // TEST(NdkBinder, GetServiceThatDoesntExist) { @@ -87,14 +153,14 @@ TEST(NdkBinder, DeathRecipient) { EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die()); foo = nullptr; - AIBinder_decStrong(binder); - binder = nullptr; std::unique_lock<std::mutex> lock(deathMutex); EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; })); EXPECT_TRUE(deathRecieved); AIBinder_DeathRecipient_delete(recipient); + AIBinder_decStrong(binder); + binder = nullptr; } TEST(NdkBinder, RetrieveNonNdkService) { @@ -196,9 +262,56 @@ TEST(NdkBinder, AddServiceMultipleTimes) { EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2)); } +TEST(NdkBinder, SentAidlBinderCanBeDestroyed) { + static volatile bool destroyed = false; + static std::mutex dMutex; + static std::condition_variable cv; + + class MyEmpty : public aidl::BnEmpty { + virtual ~MyEmpty() { + destroyed = true; + cv.notify_one(); + } + }; + + std::shared_ptr<MyEmpty> empty = ndk::SharedRefBase::make<MyEmpty>(); + + ndk::SpAIBinder binder(AServiceManager_getService(kBinderNdkUnitTestService)); + std::shared_ptr<aidl::IBinderNdkUnitTest> service = + aidl::IBinderNdkUnitTest::fromBinder(binder); + + EXPECT_FALSE(destroyed); + + service->takeInterface(empty); + service->forceFlushCommands(); + empty = nullptr; + + // give other binder thread time to process commands + { + using namespace std::chrono_literals; + std::unique_lock<std::mutex> lk(dMutex); + cv.wait_for(lk, 1s, [] { return destroyed; }); + } + + EXPECT_TRUE(destroyed); +} + int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); + if (fork() == 0) { + prctl(PR_SET_PDEATHSIG, SIGHUP); + return manualService(IFoo::kInstanceNameToDieFor); + } + if (fork() == 0) { + prctl(PR_SET_PDEATHSIG, SIGHUP); + return manualService(IFoo::kSomeInstanceName); + } + if (fork() == 0) { + prctl(PR_SET_PDEATHSIG, SIGHUP); + return generatedService(); + } + ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks ABinderProcess_startThreadPool(); diff --git a/libs/binder/ndk/test/main_server.cpp b/libs/binder/ndk/test/main_server.cpp deleted file mode 100644 index a6e17e8d98..0000000000 --- a/libs/binder/ndk/test/main_server.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2018 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 <android-base/logging.h> -#include <android/binder_process.h> -#include <iface/iface.h> - -using ::android::sp; - -class MyFoo : public IFoo { - binder_status_t doubleNumber(int32_t in, int32_t* out) override { - *out = 2 * in; - LOG(INFO) << "doubleNumber (" << in << ") => " << *out; - return STATUS_OK; - } - - binder_status_t die() override { - LOG(FATAL) << "IFoo::die called!"; - return STATUS_UNKNOWN_ERROR; - } -}; - -int service(const char* instance) { - ABinderProcess_setThreadPoolMaxThreadCount(0); - - // Strong reference to MyFoo kept by service manager. - binder_status_t status = (new MyFoo)->addService(instance); - - if (status != STATUS_OK) { - LOG(FATAL) << "Could not register: " << status << " " << instance; - } - - ABinderProcess_joinThreadPool(); - - return 1; // should not return -} - -int main() { - if (fork() == 0) { - return service(IFoo::kInstanceNameToDieFor); - } - - return service(IFoo::kSomeInstanceName); -} diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 3f359f537f..4e62da79ea 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -83,6 +83,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence if (stats.size() > 0) { mPendingReleaseItem.releaseFence = stats[0].previousReleaseFence; mTransformHint = stats[0].transformHint; + mBufferItemConsumer->setTransformHint(mTransformHint); } else { ALOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback"); mPendingReleaseItem.releaseFence = nullptr; @@ -151,7 +152,7 @@ void BLASTBufferQueue::processNextBufferLocked() { bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE); t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this)); - t->setFrame(mSurfaceControl, {0, 0, (int32_t)buffer->getWidth(), (int32_t)buffer->getHeight()}); + t->setFrame(mSurfaceControl, {0, 0, mWidth, mHeight}); t->setCrop(mSurfaceControl, computeCrop(bufferItem)); t->setTransform(mSurfaceControl, bufferItem.mTransform); t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse); diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index 3b0120b853..9e5d681b37 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -84,54 +84,54 @@ static status_t getProcessName(int pid, String8& name) { return INVALID_OPERATION; } -BufferQueueCore::BufferQueueCore() : - mMutex(), - mIsAbandoned(false), - mConsumerControlledByApp(false), - mConsumerName(getUniqueName()), - mConsumerListener(), - mConsumerUsageBits(0), - mConsumerIsProtected(false), - mConnectedApi(NO_CONNECTED_API), - mLinkedToDeath(), - mConnectedProducerListener(), - mBufferReleasedCbEnabled(false), - mSlots(), - mQueue(), - mFreeSlots(), - mFreeBuffers(), - mUnusedSlots(), - mActiveBuffers(), - mDequeueCondition(), - mDequeueBufferCannotBlock(false), - mQueueBufferCanDrop(false), - mLegacyBufferDrop(true), - mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), - mDefaultWidth(1), - mDefaultHeight(1), - mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN), - mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS), - mMaxAcquiredBufferCount(1), - mMaxDequeuedBufferCount(1), - mBufferHasBeenQueued(false), - mFrameCounter(0), - mTransformHint(0), - mIsAllocating(false), - mIsAllocatingCondition(), - mAllowAllocation(true), - mBufferAge(0), - mGenerationNumber(0), - mAsyncMode(false), - mSharedBufferMode(false), - mAutoRefresh(false), - mSharedBufferSlot(INVALID_BUFFER_SLOT), - mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE, - HAL_DATASPACE_UNKNOWN), - mLastQueuedSlot(INVALID_BUFFER_SLOT), - mUniqueId(getUniqueId()), - mAutoPrerotation(false), - mTransformHintInUse(0) -{ +BufferQueueCore::BufferQueueCore() + : mMutex(), + mIsAbandoned(false), + mConsumerControlledByApp(false), + mConsumerName(getUniqueName()), + mConsumerListener(), + mConsumerUsageBits(0), + mConsumerIsProtected(false), + mConnectedApi(NO_CONNECTED_API), + mLinkedToDeath(), + mConnectedProducerListener(), + mBufferReleasedCbEnabled(false), + mSlots(), + mQueue(), + mFreeSlots(), + mFreeBuffers(), + mUnusedSlots(), + mActiveBuffers(), + mDequeueCondition(), + mDequeueBufferCannotBlock(false), + mQueueBufferCanDrop(false), + mLegacyBufferDrop(true), + mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), + mDefaultWidth(1), + mDefaultHeight(1), + mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN), + mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS), + mMaxAcquiredBufferCount(1), + mMaxDequeuedBufferCount(1), + mBufferHasBeenQueued(false), + mFrameCounter(0), + mTransformHint(0), + mIsAllocating(false), + mIsAllocatingCondition(), + mAllowAllocation(true), + mBufferAge(0), + mGenerationNumber(0), + mAsyncMode(false), + mSharedBufferMode(false), + mAutoRefresh(false), + mSharedBufferSlot(INVALID_BUFFER_SLOT), + mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE, + HAL_DATASPACE_UNKNOWN), + mLastQueuedSlot(INVALID_BUFFER_SLOT), + mUniqueId(getUniqueId()), + mAutoPrerotation(false), + mTransformHintInUse(0), + mFrameRate(0) { int numStartingBuffers = getMaxBufferCountLocked(); for (int s = 0; s < numStartingBuffers; s++) { mFreeSlots.insert(s); diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 8ccbc7f650..85b0fd0ec7 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -57,16 +57,19 @@ const char* inputEventTypeToString(int32_t type) { return "UNKNOWN"; } -void InputEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId) { +void InputEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId, + std::array<uint8_t, 32> hmac) { mDeviceId = deviceId; mSource = source; mDisplayId = displayId; + mHmac = hmac; } void InputEvent::initialize(const InputEvent& from) { mDeviceId = from.mDeviceId; mSource = from.mSource; mDisplayId = from.mDisplayId; + mHmac = from.mHmac; } // --- KeyEvent --- @@ -79,19 +82,11 @@ int32_t KeyEvent::getKeyCodeFromLabel(const char* label) { return getKeyCodeByLabel(label); } -void KeyEvent::initialize( - int32_t deviceId, - int32_t source, - int32_t displayId, - int32_t action, - int32_t flags, - int32_t keyCode, - int32_t scanCode, - int32_t metaState, - int32_t repeatCount, - nsecs_t downTime, - nsecs_t eventTime) { - InputEvent::initialize(deviceId, source, displayId); +void KeyEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId, + std::array<uint8_t, 32> hmac, int32_t action, int32_t flags, + int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, + nsecs_t downTime, nsecs_t eventTime) { + InputEvent::initialize(deviceId, source, displayId, hmac); mAction = action; mFlags = flags; mKeyCode = keyCode; @@ -250,15 +245,16 @@ void PointerProperties::copyFrom(const PointerProperties& other) { // --- MotionEvent --- -void MotionEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action, - int32_t actionButton, int32_t flags, int32_t edgeFlags, - int32_t metaState, int32_t buttonState, - MotionClassification classification, float xOffset, float yOffset, - float xPrecision, float yPrecision, float rawXCursorPosition, - float rawYCursorPosition, nsecs_t downTime, nsecs_t eventTime, - size_t pointerCount, const PointerProperties* pointerProperties, +void MotionEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId, + std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, + int32_t flags, int32_t edgeFlags, int32_t metaState, + int32_t buttonState, MotionClassification classification, float xScale, + float yScale, float xOffset, float yOffset, float xPrecision, + float yPrecision, float rawXCursorPosition, float rawYCursorPosition, + nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { - InputEvent::initialize(deviceId, source, displayId); + InputEvent::initialize(deviceId, source, displayId, hmac); mAction = action; mActionButton = actionButton; mFlags = flags; @@ -266,6 +262,8 @@ void MotionEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId mMetaState = metaState; mButtonState = buttonState; mClassification = classification; + mXScale = xScale; + mYScale = yScale; mXOffset = xOffset; mYOffset = yOffset; mXPrecision = xPrecision; @@ -281,7 +279,7 @@ void MotionEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId } void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { - InputEvent::initialize(other->mDeviceId, other->mSource, other->mDisplayId); + InputEvent::initialize(other->mDeviceId, other->mSource, other->mDisplayId, other->mHmac); mAction = other->mAction; mActionButton = other->mActionButton; mFlags = other->mFlags; @@ -289,6 +287,8 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { mMetaState = other->mMetaState; mButtonState = other->mButtonState; mClassification = other->mClassification; + mXScale = other->mXScale; + mYScale = other->mYScale; mXOffset = other->mXOffset; mYOffset = other->mYOffset; mXPrecision = other->mXPrecision; @@ -321,17 +321,17 @@ void MotionEvent::addSample( float MotionEvent::getXCursorPosition() const { const float rawX = getRawXCursorPosition(); - return rawX + mXOffset; + return rawX * mXScale + mXOffset; } float MotionEvent::getYCursorPosition() const { const float rawY = getRawYCursorPosition(); - return rawY + mYOffset; + return rawY * mYScale + mYOffset; } void MotionEvent::setCursorPosition(float x, float y) { - mRawXCursorPosition = x - mXOffset; - mRawYCursorPosition = y - mYOffset; + mRawXCursorPosition = (x - mXOffset) / mXScale; + mRawYCursorPosition = (y - mYOffset) / mYScale; } const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const { @@ -346,9 +346,9 @@ float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const { float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis); switch (axis) { case AMOTION_EVENT_AXIS_X: - return value + mXOffset; + return value * mXScale + mXOffset; case AMOTION_EVENT_AXIS_Y: - return value + mYOffset; + return value * mYScale + mYOffset; } return value; } @@ -368,9 +368,9 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); switch (axis) { case AMOTION_EVENT_AXIS_X: - return value + mXOffset; + return value * mXScale + mXOffset; case AMOTION_EVENT_AXIS_Y: - return value + mYOffset; + return value * mYScale + mYOffset; } return value; } @@ -442,11 +442,11 @@ void MotionEvent::transform(const float matrix[9]) { float oldXOffset = mXOffset; float oldYOffset = mYOffset; float newX, newY; - float rawX = getRawX(0); - float rawY = getRawY(0); - transformPoint(matrix, rawX + oldXOffset, rawY + oldYOffset, &newX, &newY); - mXOffset = newX - rawX; - mYOffset = newY - rawY; + float scaledRawX = getRawX(0) * mXScale; + float scaledRawY = getRawY(0) * mYScale; + transformPoint(matrix, scaledRawX + oldXOffset, scaledRawY + oldYOffset, &newX, &newY); + mXOffset = newX - scaledRawX; + mYOffset = newY - scaledRawY; // Determine how the origin is transformed by the matrix so that we // can transform orientation vectors. @@ -455,22 +455,22 @@ void MotionEvent::transform(const float matrix[9]) { // Apply the transformation to cursor position. if (isValidCursorPosition(mRawXCursorPosition, mRawYCursorPosition)) { - float x = mRawXCursorPosition + oldXOffset; - float y = mRawYCursorPosition + oldYOffset; + float x = mRawXCursorPosition * mXScale + oldXOffset; + float y = mRawYCursorPosition * mYScale + oldYOffset; transformPoint(matrix, x, y, &x, &y); - mRawXCursorPosition = x - mXOffset; - mRawYCursorPosition = y - mYOffset; + mRawXCursorPosition = (x - mXOffset) / mXScale; + mRawYCursorPosition = (y - mYOffset) / mYScale; } // Apply the transformation to all samples. size_t numSamples = mSamplePointerCoords.size(); for (size_t i = 0; i < numSamples; i++) { PointerCoords& c = mSamplePointerCoords.editItemAt(i); - float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset; - float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset; + float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) * mXScale + oldXOffset; + float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) * mYScale + oldYOffset; transformPoint(matrix, x, y, &x, &y); - c.setAxisValue(AMOTION_EVENT_AXIS_X, x - mXOffset); - c.setAxisValue(AMOTION_EVENT_AXIS_Y, y - mYOffset); + c.setAxisValue(AMOTION_EVENT_AXIS_X, (x - mXOffset) / mXScale); + c.setAxisValue(AMOTION_EVENT_AXIS_Y, (y - mYOffset) / mYScale); float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, @@ -488,8 +488,14 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { } mDeviceId = parcel->readInt32(); - mSource = parcel->readInt32(); + mSource = parcel->readUint32(); mDisplayId = parcel->readInt32(); + std::vector<uint8_t> hmac; + status_t result = parcel->readByteVector(&hmac); + if (result != OK || hmac.size() != 32) { + return BAD_VALUE; + } + std::move(hmac.begin(), hmac.begin() + hmac.size(), mHmac.begin()); mAction = parcel->readInt32(); mActionButton = parcel->readInt32(); mFlags = parcel->readInt32(); @@ -497,6 +503,8 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mMetaState = parcel->readInt32(); mButtonState = parcel->readInt32(); mClassification = static_cast<MotionClassification>(parcel->readByte()); + mXScale = parcel->readFloat(); + mYScale = parcel->readFloat(); mXOffset = parcel->readFloat(); mYOffset = parcel->readFloat(); mXPrecision = parcel->readFloat(); @@ -541,8 +549,10 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeInt32(sampleCount); parcel->writeInt32(mDeviceId); - parcel->writeInt32(mSource); + parcel->writeUint32(mSource); parcel->writeInt32(mDisplayId); + std::vector<uint8_t> hmac(mHmac.begin(), mHmac.end()); + parcel->writeByteVector(hmac); parcel->writeInt32(mAction); parcel->writeInt32(mActionButton); parcel->writeInt32(mFlags); @@ -550,6 +560,8 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeInt32(mMetaState); parcel->writeInt32(mButtonState); parcel->writeByte(static_cast<int8_t>(mClassification)); + parcel->writeFloat(mXScale); + parcel->writeFloat(mYScale); parcel->writeFloat(mXOffset); parcel->writeFloat(mYOffset); parcel->writeFloat(mXPrecision); @@ -578,7 +590,7 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { } #endif -bool MotionEvent::isTouchEvent(int32_t source, int32_t action) { +bool MotionEvent::isTouchEvent(uint32_t source, int32_t action) { if (source & AINPUT_SOURCE_CLASS_POINTER) { // Specifically excludes HOVER_MOVE and SCROLL. switch (action & AMOTION_EVENT_ACTION_MASK) { @@ -607,7 +619,7 @@ int32_t MotionEvent::getAxisFromLabel(const char* label) { void FocusEvent::initialize(bool hasFocus, bool inTouchMode) { InputEvent::initialize(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, AINPUT_SOURCE_UNKNOWN, - ADISPLAY_ID_NONE); + ADISPLAY_ID_NONE, INVALID_HMAC); mHasFocus = hasFocus; mInTouchMode = inTouchMode; } diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index d53a557b28..d25a5cc0ef 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -147,6 +147,8 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { msg->body.key.source = body.key.source; // int32_t displayId msg->body.key.displayId = body.key.displayId; + // std::array<uint8_t, 32> hmac + msg->body.key.hmac = body.key.hmac; // int32_t action msg->body.key.action = body.key.action; // int32_t flags @@ -174,6 +176,8 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { msg->body.motion.source = body.motion.source; // int32_t displayId msg->body.motion.displayId = body.motion.displayId; + // std::array<uint8_t, 32> hmac + msg->body.motion.hmac = body.motion.hmac; // int32_t action msg->body.motion.action = body.motion.action; // int32_t actionButton @@ -190,6 +194,10 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { msg->body.motion.edgeFlags = body.motion.edgeFlags; // nsecs_t downTime msg->body.motion.downTime = body.motion.downTime; + // float xScale + msg->body.motion.xScale = body.motion.xScale; + // float yScale + msg->body.motion.yScale = body.motion.yScale; // float xOffset msg->body.motion.xOffset = body.motion.xOffset; // float yOffset @@ -424,19 +432,11 @@ InputPublisher::InputPublisher(const sp<InputChannel>& channel) : InputPublisher::~InputPublisher() { } -status_t InputPublisher::publishKeyEvent( - uint32_t seq, - int32_t deviceId, - int32_t source, - int32_t displayId, - int32_t action, - int32_t flags, - int32_t keyCode, - int32_t scanCode, - int32_t metaState, - int32_t repeatCount, - nsecs_t downTime, - nsecs_t eventTime) { +status_t InputPublisher::publishKeyEvent(uint32_t seq, int32_t deviceId, int32_t source, + int32_t displayId, std::array<uint8_t, 32> hmac, + int32_t action, int32_t flags, int32_t keyCode, + int32_t scanCode, int32_t metaState, int32_t repeatCount, + nsecs_t downTime, nsecs_t eventTime) { if (ATRACE_ENABLED()) { std::string message = StringPrintf("publishKeyEvent(inputChannel=%s, keyCode=%" PRId32 ")", mChannel->getName().c_str(), keyCode); @@ -461,6 +461,7 @@ status_t InputPublisher::publishKeyEvent( msg.body.key.deviceId = deviceId; msg.body.key.source = source; msg.body.key.displayId = displayId; + msg.body.key.hmac = hmac; msg.body.key.action = action; msg.body.key.flags = flags; msg.body.key.keyCode = keyCode; @@ -473,11 +474,12 @@ status_t InputPublisher::publishKeyEvent( } status_t InputPublisher::publishMotionEvent( - uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, int32_t action, - int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, - int32_t buttonState, MotionClassification classification, float xOffset, float yOffset, - float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, - nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, + uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, + std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags, + int32_t edgeFlags, int32_t metaState, int32_t buttonState, + MotionClassification classification, float xScale, float yScale, float xOffset, + float yOffset, float xPrecision, float yPrecision, float xCursorPosition, + float yCursorPosition, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { if (ATRACE_ENABLED()) { std::string message = StringPrintf( @@ -489,13 +491,14 @@ status_t InputPublisher::publishMotionEvent( ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, " "displayId=%" PRId32 ", " "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, " - "metaState=0x%x, buttonState=0x%x, classification=%s, xOffset=%f, yOffset=%f, " + "metaState=0x%x, buttonState=0x%x, classification=%s, xScale=%.1f, yScale=%.1f, " + "xOffset=%.1f, yOffset=%.1f, " "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", " "pointerCount=%" PRIu32, mChannel->getName().c_str(), seq, deviceId, source, displayId, action, actionButton, flags, edgeFlags, metaState, buttonState, - motionClassificationToString(classification), xOffset, yOffset, xPrecision, - yPrecision, downTime, eventTime, pointerCount); + motionClassificationToString(classification), xScale, yScale, xOffset, yOffset, + xPrecision, yPrecision, downTime, eventTime, pointerCount); } if (!seq) { @@ -515,6 +518,7 @@ status_t InputPublisher::publishMotionEvent( msg.body.motion.deviceId = deviceId; msg.body.motion.source = source; msg.body.motion.displayId = displayId; + msg.body.motion.hmac = hmac; msg.body.motion.action = action; msg.body.motion.actionButton = actionButton; msg.body.motion.flags = flags; @@ -522,6 +526,8 @@ status_t InputPublisher::publishMotionEvent( msg.body.motion.metaState = metaState; msg.body.motion.buttonState = buttonState; msg.body.motion.classification = classification; + msg.body.motion.xScale = xScale; + msg.body.motion.yScale = yScale; msg.body.motion.xOffset = xOffset; msg.body.motion.yOffset = yOffset; msg.body.motion.xPrecision = xPrecision; @@ -1136,18 +1142,10 @@ ssize_t InputConsumer::findTouchState(int32_t deviceId, int32_t source) const { } void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) { - event->initialize( - msg->body.key.deviceId, - msg->body.key.source, - msg->body.key.displayId, - msg->body.key.action, - msg->body.key.flags, - msg->body.key.keyCode, - msg->body.key.scanCode, - msg->body.key.metaState, - msg->body.key.repeatCount, - msg->body.key.downTime, - msg->body.key.eventTime); + event->initialize(msg->body.key.deviceId, msg->body.key.source, msg->body.key.displayId, + msg->body.key.hmac, msg->body.key.action, msg->body.key.flags, + msg->body.key.keyCode, msg->body.key.scanCode, msg->body.key.metaState, + msg->body.key.repeatCount, msg->body.key.downTime, msg->body.key.eventTime); } void InputConsumer::initializeFocusEvent(FocusEvent* event, const InputMessage* msg) { @@ -1164,15 +1162,15 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage } event->initialize(msg->body.motion.deviceId, msg->body.motion.source, - msg->body.motion.displayId, msg->body.motion.action, + msg->body.motion.displayId, msg->body.motion.hmac, msg->body.motion.action, msg->body.motion.actionButton, msg->body.motion.flags, msg->body.motion.edgeFlags, msg->body.motion.metaState, msg->body.motion.buttonState, msg->body.motion.classification, - msg->body.motion.xOffset, msg->body.motion.yOffset, - msg->body.motion.xPrecision, msg->body.motion.yPrecision, - msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition, - msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount, - pointerProperties, pointerCoords); + msg->body.motion.xScale, msg->body.motion.yScale, msg->body.motion.xOffset, + msg->body.motion.yOffset, msg->body.motion.xPrecision, + msg->body.motion.yPrecision, msg->body.motion.xCursorPosition, + msg->body.motion.yCursorPosition, msg->body.motion.downTime, + msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords); } void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) { diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index e189d20e28..6f9b162986 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -487,9 +487,9 @@ void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents, int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) { outEvents.push(); KeyEvent& event = outEvents.editTop(); - event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, - down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, - 0, keyCode, 0, metaState, 0, time, time); + event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC, + down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 0, keyCode, 0, metaState, + 0, time, time); } void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents, diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index b90857c99c..dce1f29124 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -26,7 +26,12 @@ namespace android { // Default display id. static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT; -class BaseTest : public testing::Test { }; +class BaseTest : public testing::Test { +protected: + static constexpr std::array<uint8_t, 32> HMAC = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; +}; // --- PointerCoordsTest --- @@ -176,16 +181,17 @@ TEST_F(KeyEventTest, Properties) { KeyEvent event; // Initialize and get properties. - const nsecs_t ARBITRARY_DOWN_TIME = 1; - const nsecs_t ARBITRARY_EVENT_TIME = 2; - event.initialize(2, AINPUT_SOURCE_GAMEPAD, DISPLAY_ID, AKEY_EVENT_ACTION_DOWN, - AKEY_EVENT_FLAG_FROM_SYSTEM, AKEYCODE_BUTTON_X, 121, - AMETA_ALT_ON, 1, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME); + constexpr nsecs_t ARBITRARY_DOWN_TIME = 1; + constexpr nsecs_t ARBITRARY_EVENT_TIME = 2; + event.initialize(2, AINPUT_SOURCE_GAMEPAD, DISPLAY_ID, HMAC, AKEY_EVENT_ACTION_DOWN, + AKEY_EVENT_FLAG_FROM_SYSTEM, AKEYCODE_BUTTON_X, 121, AMETA_ALT_ON, 1, + ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME); ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType()); ASSERT_EQ(2, event.getDeviceId()); - ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_GAMEPAD), event.getSource()); + ASSERT_EQ(AINPUT_SOURCE_GAMEPAD, event.getSource()); ASSERT_EQ(DISPLAY_ID, event.getDisplayId()); + EXPECT_EQ(HMAC, event.getHmac()); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, event.getAction()); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, event.getFlags()); ASSERT_EQ(AKEYCODE_BUTTON_X, event.getKeyCode()); @@ -197,7 +203,7 @@ TEST_F(KeyEventTest, Properties) { // Set source. event.setSource(AINPUT_SOURCE_JOYSTICK); - ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource()); + ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource()); // Set display id. constexpr int32_t newDisplayId = 2; @@ -210,19 +216,17 @@ TEST_F(KeyEventTest, Properties) { class MotionEventTest : public BaseTest { protected: - static const nsecs_t ARBITRARY_DOWN_TIME; - static const nsecs_t ARBITRARY_EVENT_TIME; - static const float X_OFFSET; - static const float Y_OFFSET; + static constexpr nsecs_t ARBITRARY_DOWN_TIME = 1; + static constexpr nsecs_t ARBITRARY_EVENT_TIME = 2; + static constexpr float X_SCALE = 2.0; + static constexpr float Y_SCALE = 3.0; + static constexpr float X_OFFSET = 1; + static constexpr float Y_OFFSET = 1.1; void initializeEventWithHistory(MotionEvent* event); void assertEqualsEventWithHistory(const MotionEvent* event); }; -const nsecs_t MotionEventTest::ARBITRARY_DOWN_TIME = 1; -const nsecs_t MotionEventTest::ARBITRARY_EVENT_TIME = 2; -const float MotionEventTest::X_OFFSET = 1.0f; -const float MotionEventTest::Y_OFFSET = 1.1f; void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { PointerProperties pointerProperties[2]; @@ -254,12 +258,13 @@ void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28); - event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0, + event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, HMAC, AMOTION_EVENT_ACTION_MOVE, 0, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, MotionClassification::NONE, - X_OFFSET, Y_OFFSET, 2.0f, 2.1f, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_DOWN_TIME, - ARBITRARY_EVENT_TIME, 2, pointerProperties, pointerCoords); + X_SCALE, Y_SCALE, X_OFFSET, Y_OFFSET, 2.0f, 2.1f, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, pointerProperties, + pointerCoords); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111); @@ -306,14 +311,17 @@ void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { // Check properties. ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType()); ASSERT_EQ(2, event->getDeviceId()); - ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_TOUCHSCREEN), event->getSource()); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event->getSource()); ASSERT_EQ(DISPLAY_ID, event->getDisplayId()); + EXPECT_EQ(HMAC, event->getHmac()); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction()); ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags()); ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags()); ASSERT_EQ(AMETA_ALT_ON, event->getMetaState()); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, event->getButtonState()); ASSERT_EQ(MotionClassification::NONE, event->getClassification()); + EXPECT_EQ(X_SCALE, event->getXScale()); + EXPECT_EQ(Y_SCALE, event->getYScale()); ASSERT_EQ(X_OFFSET, event->getXOffset()); ASSERT_EQ(Y_OFFSET, event->getYOffset()); ASSERT_EQ(2.0f, event->getXPrecision()); @@ -367,19 +375,19 @@ void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { ASSERT_EQ(211, event->getRawY(0)); ASSERT_EQ(221, event->getRawY(1)); - ASSERT_EQ(X_OFFSET + 10, event->getHistoricalX(0, 0)); - ASSERT_EQ(X_OFFSET + 20, event->getHistoricalX(1, 0)); - ASSERT_EQ(X_OFFSET + 110, event->getHistoricalX(0, 1)); - ASSERT_EQ(X_OFFSET + 120, event->getHistoricalX(1, 1)); - ASSERT_EQ(X_OFFSET + 210, event->getX(0)); - ASSERT_EQ(X_OFFSET + 220, event->getX(1)); + ASSERT_EQ(X_OFFSET + 10 * X_SCALE, event->getHistoricalX(0, 0)); + ASSERT_EQ(X_OFFSET + 20 * X_SCALE, event->getHistoricalX(1, 0)); + ASSERT_EQ(X_OFFSET + 110 * X_SCALE, event->getHistoricalX(0, 1)); + ASSERT_EQ(X_OFFSET + 120 * X_SCALE, event->getHistoricalX(1, 1)); + ASSERT_EQ(X_OFFSET + 210 * X_SCALE, event->getX(0)); + ASSERT_EQ(X_OFFSET + 220 * X_SCALE, event->getX(1)); - ASSERT_EQ(Y_OFFSET + 11, event->getHistoricalY(0, 0)); - ASSERT_EQ(Y_OFFSET + 21, event->getHistoricalY(1, 0)); - ASSERT_EQ(Y_OFFSET + 111, event->getHistoricalY(0, 1)); - ASSERT_EQ(Y_OFFSET + 121, event->getHistoricalY(1, 1)); - ASSERT_EQ(Y_OFFSET + 211, event->getY(0)); - ASSERT_EQ(Y_OFFSET + 221, event->getY(1)); + ASSERT_EQ(Y_OFFSET + 11 * Y_SCALE, event->getHistoricalY(0, 0)); + ASSERT_EQ(Y_OFFSET + 21 * Y_SCALE, event->getHistoricalY(1, 0)); + ASSERT_EQ(Y_OFFSET + 111 * Y_SCALE, event->getHistoricalY(0, 1)); + ASSERT_EQ(Y_OFFSET + 121 * Y_SCALE, event->getHistoricalY(1, 1)); + ASSERT_EQ(Y_OFFSET + 211 * Y_SCALE, event->getY(0)); + ASSERT_EQ(Y_OFFSET + 221 * Y_SCALE, event->getY(1)); ASSERT_EQ(12, event->getHistoricalPressure(0, 0)); ASSERT_EQ(22, event->getHistoricalPressure(1, 0)); @@ -440,7 +448,7 @@ TEST_F(MotionEventTest, Properties) { // Set source. event.setSource(AINPUT_SOURCE_JOYSTICK); - ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource()); + ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource()); // Set displayId. constexpr int32_t newDisplayId = 2; @@ -505,8 +513,8 @@ TEST_F(MotionEventTest, Scale) { ASSERT_EQ(210 * 2, event.getRawX(0)); ASSERT_EQ(211 * 2, event.getRawY(0)); - ASSERT_EQ((X_OFFSET + 210) * 2, event.getX(0)); - ASSERT_EQ((Y_OFFSET + 211) * 2, event.getY(0)); + ASSERT_EQ((X_OFFSET + 210 * X_SCALE) * 2, event.getX(0)); + ASSERT_EQ((Y_OFFSET + 211 * Y_SCALE) * 2, event.getY(0)); ASSERT_EQ(212, event.getPressure(0)); ASSERT_EQ(213, event.getSize(0)); ASSERT_EQ(214 * 2, event.getTouchMajor(0)); @@ -570,12 +578,13 @@ TEST_F(MotionEventTest, Transform) { pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle); } MotionEvent event; - event.initialize(0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, - 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, - 0 /*buttonState*/, MotionClassification::NONE, 0 /*xOffset*/, 0 /*yOffset*/, - 0 /*xPrecision*/, 0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/, - 2 /*yCursorPosition*/, 0 /*downTime*/, 0 /*eventTime*/, pointerCount, - pointerProperties, pointerCoords); + event.initialize(0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, INVALID_HMAC, + AMOTION_EVENT_ACTION_MOVE, 0 /*actionButton*/, 0 /*flags*/, + AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, + MotionClassification::NONE, 1 /*xScale*/, 1 /*yScale*/, 0 /*xOffset*/, + 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/, + 3 + RADIUS /*xCursorPosition*/, 2 /*yCursorPosition*/, 0 /*downTime*/, + 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); float originalRawX = 0 + 3; float originalRawY = -RADIUS + 2; @@ -634,9 +643,10 @@ TEST_F(MotionEventTest, Initialize_SetsClassification) { } for (MotionClassification classification : classifications) { - event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, + event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, - 0, classification, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + 0, classification, 1 /*xScale*/, 1 /*yScale*/, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(classification, event.getClassification()); @@ -654,9 +664,10 @@ TEST_F(MotionEventTest, Initialize_SetsCursorPosition) { pointerCoords[i].clear(); } - event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, - 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE, 0, - 0, 0, 0, 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, 0 /*downTime*/, + event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID, INVALID_HMAC, + AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, + MotionClassification::NONE, 1 /*xScale*/, 1 /*yScale*/, 0, 0, 0, 0, + 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); event.offsetLocation(20, 60); ASSERT_EQ(280, event.getRawXCursorPosition()); diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index 2fc77e97a0..d4bbf6c6ac 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -73,8 +73,11 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { constexpr uint32_t seq = 15; constexpr int32_t deviceId = 1; - constexpr int32_t source = AINPUT_SOURCE_KEYBOARD; + constexpr uint32_t source = AINPUT_SOURCE_KEYBOARD; constexpr int32_t displayId = ADISPLAY_ID_DEFAULT; + constexpr std::array<uint8_t, 32> hmac = {31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, + 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; constexpr int32_t action = AKEY_EVENT_ACTION_DOWN; constexpr int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM; constexpr int32_t keyCode = AKEYCODE_ENTER; @@ -84,8 +87,9 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { constexpr nsecs_t downTime = 3; constexpr nsecs_t eventTime = 4; - status = mPublisher->publishKeyEvent(seq, deviceId, source, displayId, action, flags, - keyCode, scanCode, metaState, repeatCount, downTime, eventTime); + status = mPublisher->publishKeyEvent(seq, deviceId, source, displayId, hmac, action, flags, + keyCode, scanCode, metaState, repeatCount, downTime, + eventTime); ASSERT_EQ(OK, status) << "publisher publishKeyEvent should return OK"; @@ -105,6 +109,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { EXPECT_EQ(deviceId, keyEvent->getDeviceId()); EXPECT_EQ(source, keyEvent->getSource()); EXPECT_EQ(displayId, keyEvent->getDisplayId()); + EXPECT_EQ(hmac, keyEvent->getHmac()); EXPECT_EQ(action, keyEvent->getAction()); EXPECT_EQ(flags, keyEvent->getFlags()); EXPECT_EQ(keyCode, keyEvent->getKeyCode()); @@ -134,8 +139,11 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { constexpr uint32_t seq = 15; constexpr int32_t deviceId = 1; - constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN; + constexpr uint32_t source = AINPUT_SOURCE_TOUCHSCREEN; constexpr int32_t displayId = ADISPLAY_ID_DEFAULT; + constexpr std::array<uint8_t, 32> hmac = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; constexpr int32_t action = AMOTION_EVENT_ACTION_MOVE; constexpr int32_t actionButton = 0; constexpr int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; @@ -143,6 +151,8 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { constexpr int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON; constexpr int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY; constexpr MotionClassification classification = MotionClassification::AMBIGUOUS_GESTURE; + constexpr float xScale = 2; + constexpr float yScale = 3; constexpr float xOffset = -10; constexpr float yOffset = -20; constexpr float xPrecision = 0.25; @@ -171,12 +181,12 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i); } - status = - mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton, - flags, edgeFlags, metaState, buttonState, classification, - xOffset, yOffset, xPrecision, yPrecision, - xCursorPosition, yCursorPosition, downTime, eventTime, - pointerCount, pointerProperties, pointerCoords); + status = mPublisher->publishMotionEvent(seq, deviceId, source, displayId, hmac, action, + actionButton, flags, edgeFlags, metaState, buttonState, + classification, xScale, yScale, xOffset, yOffset, + xPrecision, yPrecision, xCursorPosition, + yCursorPosition, downTime, eventTime, pointerCount, + pointerProperties, pointerCoords); ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK"; @@ -196,18 +206,23 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { EXPECT_EQ(deviceId, motionEvent->getDeviceId()); EXPECT_EQ(source, motionEvent->getSource()); EXPECT_EQ(displayId, motionEvent->getDisplayId()); + EXPECT_EQ(hmac, motionEvent->getHmac()); EXPECT_EQ(action, motionEvent->getAction()); EXPECT_EQ(flags, motionEvent->getFlags()); EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags()); EXPECT_EQ(metaState, motionEvent->getMetaState()); EXPECT_EQ(buttonState, motionEvent->getButtonState()); EXPECT_EQ(classification, motionEvent->getClassification()); + EXPECT_EQ(xScale, motionEvent->getXScale()); + EXPECT_EQ(yScale, motionEvent->getYScale()); + EXPECT_EQ(xOffset, motionEvent->getXOffset()); + EXPECT_EQ(yOffset, motionEvent->getYOffset()); EXPECT_EQ(xPrecision, motionEvent->getXPrecision()); EXPECT_EQ(yPrecision, motionEvent->getYPrecision()); EXPECT_EQ(xCursorPosition, motionEvent->getRawXCursorPosition()); EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition()); - EXPECT_EQ(xCursorPosition + xOffset, motionEvent->getXCursorPosition()); - EXPECT_EQ(yCursorPosition + yOffset, motionEvent->getYCursorPosition()); + EXPECT_EQ(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition()); + EXPECT_EQ(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition()); EXPECT_EQ(downTime, motionEvent->getDownTime()); EXPECT_EQ(eventTime, motionEvent->getEventTime()); EXPECT_EQ(pointerCount, motionEvent->getPointerCount()); @@ -222,10 +237,10 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { motionEvent->getRawX(i)); EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), motionEvent->getRawY(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset, - motionEvent->getX(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset, - motionEvent->getY(i)); + EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) * xScale + xOffset, + motionEvent->getX(i)); + EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) * yScale + yOffset, + motionEvent->getY(i)); EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), motionEvent->getPressure(i)); EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), @@ -316,11 +331,12 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZer pointerCoords[i].clear(); } - status = - mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, MotionClassification::NONE, - 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, - pointerCount, pointerProperties, pointerCoords); + status = mPublisher->publishMotionEvent(0, 0, 0, 0, INVALID_HMAC, 0, 0, 0, 0, 0, 0, + MotionClassification::NONE, 1 /* xScale */, + 1 /* yScale */, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -331,11 +347,12 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; - status = - mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, MotionClassification::NONE, - 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, - pointerCount, pointerProperties, pointerCoords); + status = mPublisher->publishMotionEvent(1, 0, 0, 0, INVALID_HMAC, 0, 0, 0, 0, 0, 0, + MotionClassification::NONE, 1 /* xScale */, + 1 /* yScale */, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -351,11 +368,12 @@ TEST_F(InputPublisherAndConsumerTest, pointerCoords[i].clear(); } - status = - mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, MotionClassification::NONE, - 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, - pointerCount, pointerProperties, pointerCoords); + status = mPublisher->publishMotionEvent(1, 0, 0, 0, INVALID_HMAC, 0, 0, 0, 0, 0, 0, + MotionClassification::NONE, 1 /* xScale */, + 1 /* yScale */, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index 9ab0dba08d..aa8a2d488f 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -39,35 +39,39 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Key, deviceId, 16); CHECK_OFFSET(InputMessage::Body::Key, source, 20); CHECK_OFFSET(InputMessage::Body::Key, displayId, 24); - CHECK_OFFSET(InputMessage::Body::Key, action, 28); - CHECK_OFFSET(InputMessage::Body::Key, flags, 32); - CHECK_OFFSET(InputMessage::Body::Key, keyCode, 36); - CHECK_OFFSET(InputMessage::Body::Key, scanCode, 40); - CHECK_OFFSET(InputMessage::Body::Key, metaState, 44); - CHECK_OFFSET(InputMessage::Body::Key, repeatCount, 48); - CHECK_OFFSET(InputMessage::Body::Key, downTime, 56); + CHECK_OFFSET(InputMessage::Body::Key, hmac, 28); + CHECK_OFFSET(InputMessage::Body::Key, action, 60); + CHECK_OFFSET(InputMessage::Body::Key, flags, 64); + CHECK_OFFSET(InputMessage::Body::Key, keyCode, 68); + CHECK_OFFSET(InputMessage::Body::Key, scanCode, 72); + CHECK_OFFSET(InputMessage::Body::Key, metaState, 76); + CHECK_OFFSET(InputMessage::Body::Key, repeatCount, 80); + CHECK_OFFSET(InputMessage::Body::Key, downTime, 88); CHECK_OFFSET(InputMessage::Body::Motion, seq, 0); CHECK_OFFSET(InputMessage::Body::Motion, eventTime, 8); CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16); CHECK_OFFSET(InputMessage::Body::Motion, source, 20); CHECK_OFFSET(InputMessage::Body::Motion, displayId, 24); - CHECK_OFFSET(InputMessage::Body::Motion, action, 28); - CHECK_OFFSET(InputMessage::Body::Motion, actionButton, 32); - CHECK_OFFSET(InputMessage::Body::Motion, flags, 36); - CHECK_OFFSET(InputMessage::Body::Motion, metaState, 40); - CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 44); - CHECK_OFFSET(InputMessage::Body::Motion, classification, 48); - CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 52); - CHECK_OFFSET(InputMessage::Body::Motion, downTime, 56); - CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 64); - CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 68); - CHECK_OFFSET(InputMessage::Body::Motion, xPrecision, 72); - CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 76); - CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 80); - CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 84); - CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 88); - CHECK_OFFSET(InputMessage::Body::Motion, pointers, 96); + CHECK_OFFSET(InputMessage::Body::Motion, hmac, 28); + CHECK_OFFSET(InputMessage::Body::Motion, action, 60); + CHECK_OFFSET(InputMessage::Body::Motion, actionButton, 64); + CHECK_OFFSET(InputMessage::Body::Motion, flags, 68); + CHECK_OFFSET(InputMessage::Body::Motion, metaState, 72); + CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 76); + CHECK_OFFSET(InputMessage::Body::Motion, classification, 80); + CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 84); + CHECK_OFFSET(InputMessage::Body::Motion, downTime, 88); + CHECK_OFFSET(InputMessage::Body::Motion, xScale, 96); + CHECK_OFFSET(InputMessage::Body::Motion, yScale, 100); + CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 104); + CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 108); + CHECK_OFFSET(InputMessage::Body::Motion, xPrecision, 112); + CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 116); + CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 120); + CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 124); + CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 128); + CHECK_OFFSET(InputMessage::Body::Motion, pointers, 136); CHECK_OFFSET(InputMessage::Body::Focus, seq, 0); CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 4); @@ -86,7 +90,7 @@ void TestHeaderSize() { * the Motion type, where "pointerCount" variable affects the size and can change at runtime. */ void TestBodySize() { - static_assert(sizeof(InputMessage::Body::Key) == 64); + static_assert(sizeof(InputMessage::Body::Key) == 96); static_assert(sizeof(InputMessage::Body::Motion) == offsetof(InputMessage::Body::Motion, pointers) + sizeof(InputMessage::Body::Motion::Pointer) * MAX_POINTERS); diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index 968e2fa6bc..731eb6a000 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -176,11 +176,11 @@ static std::vector<MotionEvent> createMotionEventStream( EXPECT_EQ(pointerIndex, pointerCount); MotionEvent event; - event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, action, - 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, - 0 /*buttonState*/, MotionClassification::NONE, 0 /*xOffset*/, - 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/, - AMOTION_EVENT_INVALID_CURSOR_POSITION, + event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, INVALID_HMAC, + action, 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, + AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, 1 /*xScale*/, + 1 /*yScale*/, 0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, + 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, entry.eventTime.count(), pointerCount, properties, coords); diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index 15d937efc0..58fff8fa00 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -60,7 +60,7 @@ public: void postFrameCallbackDelayed(AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay); void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data); - void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb); + void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data); enum { MSG_SCHEDULE_CALLBACKS = 0, @@ -152,21 +152,34 @@ void Choreographer::postFrameCallbackDelayed( void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) { { AutoMutex _l{mLock}; + for (const auto& callback : mRefreshRateCallbacks) { + // Don't re-add callbacks. + if (cb == callback.callback && data == callback.data) { + return; + } + } mRefreshRateCallbacks.emplace_back(RefreshRateCallback{cb, data}); toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedDispatch); } } -void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb) { +void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, + void* data) { { AutoMutex _l{mLock}; mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(), mRefreshRateCallbacks.end(), [&](const RefreshRateCallback& callback) { - return cb == callback.callback; - })); + return cb == callback.callback && + data == callback.data; + }), + mRefreshRateCallbacks.end()); if (mRefreshRateCallbacks.empty()) { toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedSuppress); + // If callbacks are empty then clear out the most recently seen + // vsync period so that when another callback is registered then the + // up-to-date refresh rate can be communicated to the app again. + mVsyncPeriod = 0; } } } @@ -224,9 +237,9 @@ void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId, int32_t, // on every single configuration change. if (mVsyncPeriod != vsyncPeriod) { cb.callback(vsyncPeriod, cb.data); - mVsyncPeriod = vsyncPeriod; } } + mVsyncPeriod = vsyncPeriod; } } @@ -285,8 +298,9 @@ void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer, AChoreographer_to_Choreographer(choreographer)->registerRefreshRateCallback(callback, data); } void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer, - AChoreographer_refreshRateCallback callback) { - AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback); + AChoreographer_refreshRateCallback callback, + void* data) { + AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback, data); } AChoreographer* AChoreographer_create() { diff --git a/libs/nativedisplay/include/android/choreographer.h b/libs/nativedisplay/include/android/choreographer.h index 0d97e8c066..5fd3de9f3c 100644 --- a/libs/nativedisplay/include/android/choreographer.h +++ b/libs/nativedisplay/include/android/choreographer.h @@ -54,6 +54,13 @@ typedef void (*AChoreographer_frameCallback)(long frameTimeNanos, void* data); */ typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* data); +/** + * Prototype of the function that is called when the display refresh rate + * changes. It's passed the new vsync period in nanoseconds, as well as the data + * pointer provided by the application that registered a callback. + */ +typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, void* data); + #if __ANDROID_API__ >= 24 /** @@ -102,6 +109,42 @@ void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer, #endif /* __ANDROID_API__ >= 29 */ +#if __ANDROID_API__ >= 30 + +/** + * Registers a callback to be run when the display refresh rate changes. The + * data pointer provided will be passed to the callback function when it's + * called. The same callback may be registered multiple times, provided that a + * different data pointer is provided each time. + * + * If an application registers a callback for this choreographer instance when + * no new callbacks were previously registered, that callback is guaranteed to + * be dispatched. However, if the callback and associated data pointer are + * unregistered prior to running the callback, then the callback may be silently + * dropped. + * + * This api is thread-safe. Any thread is allowed to register a new refresh + * rate callback for the choreographer instance. + */ +void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer, + AChoreographer_refreshRateCallback, void* data); + +/** + * Unregisters a callback to be run when the display refresh rate changes, along + * with the data pointer previously provided when registering the callback. The + * callback is only unregistered when the data pointer matches one that was + * previously registered. + * + * This api is thread-safe. Any thread is allowed to unregister an existing + * refresh rate callback for the choreographer instance. When a refresh rate + * callback and associated data pointer are unregistered, then there is a + * guarantee that when the unregistration completes that that callback will not + * be run with the data pointer passed. + */ +void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer, + AChoreographer_refreshRateCallback, void* data); +#endif /* __ANDROID_API__ >= 30 */ + __END_DECLS #endif // ANDROID_CHOREOGRAPHER_H diff --git a/libs/nativedisplay/include/apex/choreographer.h b/libs/nativedisplay/include/apex/choreographer.h index 5251fd365f..b17b49762c 100644 --- a/libs/nativedisplay/include/apex/choreographer.h +++ b/libs/nativedisplay/include/apex/choreographer.h @@ -22,25 +22,6 @@ __BEGIN_DECLS /** - * Prototype of the function that is called when the display refresh rate - * changes. It's passed the new vsync period in nanoseconds, as well as the data - * pointer provided by the application that registered a callback. - */ -typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, void* data); - -/** - * Registers a callback to be run when the display refresh rate changes. - */ -void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer, - AChoreographer_refreshRateCallback, void* data); - -/** - * Unregisters a callback to be run when the display refresh rate changes. - */ -void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer, - AChoreographer_refreshRateCallback); - -/** * Creates an instance of AChoreographer. * * The key differences between this method and AChoreographer_getInstance are: diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index e257704750..98605baf82 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -1003,7 +1003,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, setViewportAndProjection(display.physicalDisplay, display.clip); } else { setViewportAndProjection(display.physicalDisplay, display.clip); - auto status = mBlurFilter->setAsDrawTarget(display); + auto status = mBlurFilter->setAsDrawTarget(display, blurLayer->backgroundBlurRadius); if (status != NO_ERROR) { ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).", buffer->handle); @@ -1037,7 +1037,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, .build(); for (auto const layer : layers) { if (blurLayer == layer) { - auto status = mBlurFilter->prepare(layer->backgroundBlurRadius); + auto status = mBlurFilter->prepare(); if (status != NO_ERROR) { ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", buffer->handle); diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp index 091eac90b2..153935b678 100644 --- a/libs/renderengine/gl/GLFramebuffer.cpp +++ b/libs/renderengine/gl/GLFramebuffer.cpp @@ -122,6 +122,14 @@ void GLFramebuffer::bind() const { glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferName); } +void GLFramebuffer::bindAsReadBuffer() const { + glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebufferName); +} + +void GLFramebuffer::bindAsDrawBuffer() const { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebufferName); +} + void GLFramebuffer::unbind() const { glBindFramebuffer(GL_FRAMEBUFFER, 0); } diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h index 668685afd1..69102d6e78 100644 --- a/libs/renderengine/gl/GLFramebuffer.h +++ b/libs/renderengine/gl/GLFramebuffer.h @@ -48,6 +48,8 @@ public: int32_t getBufferWidth() const { return mBufferWidth; } GLenum getStatus() const { return mStatus; } void bind() const; + void bindAsReadBuffer() const; + void bindAsDrawBuffer() const; void unbind() const; private: diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp index a18a999b43..48c256065c 100644 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ b/libs/renderengine/gl/filters/BlurFilter.cpp @@ -31,29 +31,24 @@ namespace renderengine { namespace gl { BlurFilter::BlurFilter(GLESRenderEngine& engine) - : mEngine(engine), mCompositionFbo(engine), mBlurredFbo(engine), mSimpleProgram(engine) { - mSimpleProgram.compile(getVertexShader(), getSimpleFragShader()); - mSPosLoc = mSimpleProgram.getAttributeLocation("aPosition"); - mSUvLoc = mSimpleProgram.getAttributeLocation("aUV"); - mSTextureLoc = mSimpleProgram.getUniformLocation("uTexture"); + : mEngine(engine), mCompositionFbo(engine), mBlurredFbo(engine), mMixProgram(engine) { + mMixProgram.compile(getVertexShader(), getMixFragShader()); + mMPosLoc = mMixProgram.getAttributeLocation("aPosition"); + mMUvLoc = mMixProgram.getAttributeLocation("aUV"); + mMTextureLoc = mMixProgram.getUniformLocation("uTexture"); + mMCompositionTextureLoc = mMixProgram.getUniformLocation("uCompositionTexture"); + mMMixLoc = mMixProgram.getUniformLocation("uMix"); } -status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display) { +status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t radius) { ATRACE_NAME("BlurFilter::setAsDrawTarget"); + mRadius = radius; if (!mTexturesAllocated) { mDisplayWidth = display.physicalDisplay.width(); mDisplayHeight = display.physicalDisplay.height(); mCompositionFbo.allocateBuffers(mDisplayWidth, mDisplayHeight); - // Let's use mimap filtering on the offscreen composition texture, - // this will drastically improve overall shader quality. - glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName()); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 3); - glBindTexture(GL_TEXTURE_2D, 0); - const uint32_t fboWidth = floorf(mDisplayWidth * kFboScale); const uint32_t fboHeight = floorf(mDisplayHeight * kFboScale); mBlurredFbo.allocateBuffers(fboWidth, fboHeight); @@ -94,27 +89,41 @@ void BlurFilter::drawMesh(GLuint uv, GLuint position) { status_t BlurFilter::render() { ATRACE_NAME("BlurFilter::render"); - // Now let's scale our blur up - mSimpleProgram.useProgram(); + // Now let's scale our blur up. It will be interpolated with the larger composited + // texture for the first frames, to hide downscaling artifacts. + GLfloat mix = fmin(1.0, mRadius / kMaxCrossFadeRadius); + if (mix >= 1) { + mBlurredFbo.bindAsReadBuffer(); + glBlitFramebuffer(0, 0, mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight(), 0, 0, + mDisplayWidth, mDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + return NO_ERROR; + } + + mMixProgram.useProgram(); + glUniform1f(mMMixLoc, mix); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, mBlurredFbo.getTextureName()); - glUniform1i(mSTextureLoc, 0); + glUniform1i(mMTextureLoc, 0); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName()); + glUniform1i(mMCompositionTextureLoc, 1); mEngine.checkErrors("Setting final pass uniforms"); - drawMesh(mSUvLoc, mSPosLoc); + drawMesh(mMUvLoc, mMPosLoc); glUseProgram(0); + glActiveTexture(GL_TEXTURE0); return NO_ERROR; } string BlurFilter::getVertexShader() const { return R"SHADER( #version 310 es - precision lowp float; in vec2 aPosition; - in mediump vec2 aUV; - out mediump vec2 vUV; + in highp vec2 aUV; + out highp vec2 vUV; void main() { vUV = aUV; @@ -123,18 +132,22 @@ string BlurFilter::getVertexShader() const { )SHADER"; } -string BlurFilter::getSimpleFragShader() const { +string BlurFilter::getMixFragShader() const { string shader = R"SHADER( #version 310 es - precision lowp float; + precision mediump float; - in mediump vec2 vUV; + in highp vec2 vUV; out vec4 fragColor; + uniform sampler2D uCompositionTexture; uniform sampler2D uTexture; + uniform float uMix; void main() { - fragColor = texture(uTexture, vUV); + vec4 blurred = texture(uTexture, vUV); + vec4 composition = texture(uCompositionTexture, vUV); + fragColor = mix(composition, blurred, uMix); } )SHADER"; return shader; diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h index e265b5113a..6889939518 100644 --- a/libs/renderengine/gl/filters/BlurFilter.h +++ b/libs/renderengine/gl/filters/BlurFilter.h @@ -31,22 +31,25 @@ class BlurFilter { public: // Downsample FBO to improve performance static constexpr float kFboScale = 0.25f; + // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited + // image, up to this radius. + static constexpr float kMaxCrossFadeRadius = 15.0f; explicit BlurFilter(GLESRenderEngine& engine); virtual ~BlurFilter(){}; // Set up render targets, redirecting output to offscreen texture. - status_t setAsDrawTarget(const DisplaySettings&); + status_t setAsDrawTarget(const DisplaySettings&, uint32_t radius); // Allocate any textures needed for the filter. virtual void allocateTextures() = 0; // Execute blur passes, rendering to offscreen texture. - virtual status_t prepare(uint32_t radius) = 0; + virtual status_t prepare() = 0; // Render blur to the bound framebuffer (screen). status_t render(); protected: + uint32_t mRadius; void drawMesh(GLuint uv, GLuint position); - string getSimpleFragShader() const; string getVertexShader() const; GLESRenderEngine& mEngine; @@ -58,12 +61,15 @@ protected: uint32_t mDisplayHeight; private: + string getMixFragShader() const; bool mTexturesAllocated = false; - GenericProgram mSimpleProgram; - GLuint mSPosLoc; - GLuint mSUvLoc; - GLuint mSTextureLoc; + GenericProgram mMixProgram; + GLuint mMPosLoc; + GLuint mMUvLoc; + GLuint mMMixLoc; + GLuint mMTextureLoc; + GLuint mMCompositionTextureLoc; }; } // namespace gl diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp index f5ba02a5fc..4d7bf44540 100644 --- a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp +++ b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp @@ -26,6 +26,10 @@ #include <utils/Trace.h> +#define PI 3.14159265359 +#define THETA 0.352 +#define K 1.0 / (2.0 * THETA * THETA) + namespace android { namespace renderengine { namespace gl { @@ -39,22 +43,24 @@ GaussianBlurFilter::GaussianBlurFilter(GLESRenderEngine& engine) mVPosLoc = mVerticalProgram.getAttributeLocation("aPosition"); mVUvLoc = mVerticalProgram.getAttributeLocation("aUV"); mVTextureLoc = mVerticalProgram.getUniformLocation("uTexture"); - mVSizeLoc = mVerticalProgram.getUniformLocation("uSize"); - mVRadiusLoc = mVerticalProgram.getUniformLocation("uRadius"); + mVIncrementLoc = mVerticalProgram.getUniformLocation("uIncrement"); + mVNumSamplesLoc = mVerticalProgram.getUniformLocation("uSamples"); + mVGaussianWeightLoc = mVerticalProgram.getUniformLocation("uGaussianWeights"); mHorizontalProgram.compile(getVertexShader(), getFragmentShader(true)); mHPosLoc = mHorizontalProgram.getAttributeLocation("aPosition"); mHUvLoc = mHorizontalProgram.getAttributeLocation("aUV"); mHTextureLoc = mHorizontalProgram.getUniformLocation("uTexture"); - mHSizeLoc = mHorizontalProgram.getUniformLocation("uSize"); - mHRadiusLoc = mHorizontalProgram.getUniformLocation("uRadius"); + mHIncrementLoc = mHorizontalProgram.getUniformLocation("uIncrement"); + mHNumSamplesLoc = mHorizontalProgram.getUniformLocation("uSamples"); + mHGaussianWeightLoc = mHorizontalProgram.getUniformLocation("uGaussianWeights"); } void GaussianBlurFilter::allocateTextures() { mVerticalPassFbo.allocateBuffers(mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight()); } -status_t GaussianBlurFilter::prepare(uint32_t radius) { +status_t GaussianBlurFilter::prepare() { ATRACE_NAME("GaussianBlurFilter::prepare"); if (mVerticalPassFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { @@ -70,21 +76,38 @@ status_t GaussianBlurFilter::prepare(uint32_t radius) { return GL_INVALID_OPERATION; } + mCompositionFbo.bindAsReadBuffer(); + mBlurredFbo.bindAsDrawBuffer(); + glBlitFramebuffer(0, 0, mCompositionFbo.getBufferWidth(), mCompositionFbo.getBufferHeight(), 0, + 0, mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight(), + GL_COLOR_BUFFER_BIT, GL_LINEAR); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + // First, we'll apply the vertical pass, that receives the flattened background layers. mVerticalPassFbo.bind(); mVerticalProgram.useProgram(); + // Precompute gaussian bell curve, and send it to the shader to avoid + // unnecessary computations. + auto samples = min(mRadius, kNumSamples); + GLfloat gaussianWeights[kNumSamples] = {}; + for (size_t i = 0; i < samples; i++) { + float normalized = float(i) / samples; + gaussianWeights[i] = (float)exp(-K * normalized * normalized); + } + // set uniforms auto width = mVerticalPassFbo.getBufferWidth(); auto height = mVerticalPassFbo.getBufferHeight(); - auto radiusF = fmax(1.0f, radius * kFboScale); + auto radiusF = fmax(1.0f, mRadius * kFboScale); glViewport(0, 0, width, height); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName()); - glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, mBlurredFbo.getTextureName()); glUniform1i(mVTextureLoc, 0); - glUniform2f(mVSizeLoc, width, height); - glUniform1f(mVRadiusLoc, radiusF); + glUniform2f(mVIncrementLoc, radiusF / (width * 2.0f), radiusF / (height * 2.0f)); + glUniform1i(mVNumSamplesLoc, samples); + glUniform1fv(mVGaussianWeightLoc, kNumSamples, gaussianWeights); mEngine.checkErrors("Setting vertical-diagonal pass uniforms"); drawMesh(mVUvLoc, mVPosLoc); @@ -97,8 +120,9 @@ status_t GaussianBlurFilter::prepare(uint32_t radius) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, mVerticalPassFbo.getTextureName()); glUniform1i(mHTextureLoc, 0); - glUniform2f(mHSizeLoc, width, height); - glUniform1f(mHRadiusLoc, radiusF); + glUniform2f(mHIncrementLoc, radiusF / (width * 2.0f), radiusF / (height * 2.0f)); + glUniform1i(mHNumSamplesLoc, samples); + glUniform1fv(mHGaussianWeightLoc, kNumSamples, gaussianWeights); mEngine.checkErrors("Setting vertical pass uniforms"); drawMesh(mHUvLoc, mHPosLoc); @@ -115,42 +139,31 @@ status_t GaussianBlurFilter::prepare(uint32_t radius) { } string GaussianBlurFilter::getFragmentShader(bool horizontal) const { - string shader = "#version 310 es\n#define DIRECTION "; - shader += (horizontal ? "1" : "0"); - shader += R"SHADER( - precision lowp float; + stringstream shader; + shader << "#version 310 es\n" + << "#define DIRECTION " << (horizontal ? "1" : "0") << "\n" + << "#define NUM_SAMPLES " << kNumSamples << + R"SHADER( + precision mediump float; uniform sampler2D uTexture; - uniform vec2 uSize; - uniform float uRadius; + uniform vec2 uIncrement; + uniform float[NUM_SAMPLES] uGaussianWeights; + uniform int uSamples; - mediump in vec2 vUV; + highp in vec2 vUV; out vec4 fragColor; - #define PI 3.14159265359 - #define THETA 0.352 - #define MU 0.0 - #define A 1.0 / (THETA * sqrt(2.0 * PI)) - #define K 1.0 / (2.0 * THETA * THETA) - #define MAX_SAMPLES 10 - - float gaussianBellCurve(float x) { - float tmp = (x - MU); - return exp(-K * tmp * tmp); - } - - vec3 gaussianBlur(sampler2D texture, mediump vec2 uv, float size, - mediump vec2 direction, float radius) { + vec3 gaussianBlur(sampler2D texture, highp vec2 uv, float inc, vec2 direction) { float totalWeight = 0.0; - vec3 blurred = vec3(0.); - int samples = min(int(ceil(radius / 2.0)), MAX_SAMPLES); - float inc = radius / (size * 2.0); + vec3 blurred = vec3(0.0); + float fSamples = 1.0 / float(uSamples); - for (int i = -samples; i <= samples; i++) { - float normalized = float(i) / float(samples); - float weight = gaussianBellCurve(normalized); + for (int i = -uSamples; i <= uSamples; i++) { + float weight = uGaussianWeights[abs(i)]; + float normalized = float(i) * fSamples; float radInc = inc * normalized; - blurred += weight * (texture(texture, uv + radInc * direction)).rgb;; + blurred += weight * (texture(texture, radInc * direction + uv, 0.0)).rgb; totalWeight += weight; } @@ -159,15 +172,15 @@ string GaussianBlurFilter::getFragmentShader(bool horizontal) const { void main() { #if DIRECTION == 1 - vec3 color = gaussianBlur(uTexture, vUV, uSize.x, vec2(1.0, 0.0), uRadius); + vec3 color = gaussianBlur(uTexture, vUV, uIncrement.x, vec2(1.0, 0.0)); #else - vec3 color = gaussianBlur(uTexture, vUV, uSize.y, vec2(0.0, 1.0), uRadius); + vec3 color = gaussianBlur(uTexture, vUV, uIncrement.y, vec2(0.0, 1.0)); #endif fragColor = vec4(color, 1.0); } )SHADER"; - return shader; + return shader.str(); } } // namespace gl diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.h b/libs/renderengine/gl/filters/GaussianBlurFilter.h index acf0f07d36..8580522f40 100644 --- a/libs/renderengine/gl/filters/GaussianBlurFilter.h +++ b/libs/renderengine/gl/filters/GaussianBlurFilter.h @@ -30,8 +30,10 @@ namespace gl { class GaussianBlurFilter : public BlurFilter { public: + static constexpr uint32_t kNumSamples = 12; + explicit GaussianBlurFilter(GLESRenderEngine& engine); - status_t prepare(uint32_t radius) override; + status_t prepare() override; void allocateTextures() override; private: @@ -45,16 +47,18 @@ private: GLuint mVPosLoc; GLuint mVUvLoc; GLuint mVTextureLoc; - GLuint mVSizeLoc; - GLuint mVRadiusLoc; + GLuint mVIncrementLoc; + GLuint mVNumSamplesLoc; + GLuint mVGaussianWeightLoc; // Horizontal pass and its uniforms GenericProgram mHorizontalProgram; GLuint mHPosLoc; GLuint mHUvLoc; GLuint mHTextureLoc; - GLuint mHSizeLoc; - GLuint mHRadiusLoc; + GLuint mHIncrementLoc; + GLuint mHNumSamplesLoc; + GLuint mHGaussianWeightLoc; }; } // namespace gl diff --git a/libs/renderengine/gl/filters/LensBlurFilter.cpp b/libs/renderengine/gl/filters/LensBlurFilter.cpp index 799deac202..fb29fbb48b 100644 --- a/libs/renderengine/gl/filters/LensBlurFilter.cpp +++ b/libs/renderengine/gl/filters/LensBlurFilter.cpp @@ -62,7 +62,7 @@ void LensBlurFilter::allocateTextures() { mBlurredFbo.getBufferHeight()); } -status_t LensBlurFilter::prepare(uint32_t radius) { +status_t LensBlurFilter::prepare() { ATRACE_NAME("LensBlurFilter::prepare"); if (mVerticalDiagonalPassFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { @@ -86,11 +86,10 @@ status_t LensBlurFilter::prepare(uint32_t radius) { // set uniforms auto width = mVerticalDiagonalPassFbo.getBufferWidth(); auto height = mVerticalDiagonalPassFbo.getBufferHeight(); - auto radiusF = fmax(1.0f, radius * kFboScale); + auto radiusF = fmax(1.0f, mRadius * kFboScale); glViewport(0, 0, width, height); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName()); - glGenerateMipmap(GL_TEXTURE_2D); glUniform1i(mVDTexture0Loc, 0); glUniform2f(mVDSizeLoc, mDisplayWidth, mDisplayHeight); glUniform1f(mVDRadiusLoc, radiusF); @@ -134,8 +133,7 @@ string LensBlurFilter::getFragmentShader(bool forComposition) const { string shader = "#version 310 es\n#define DIRECTION "; shader += (forComposition ? "1" : "0"); shader += R"SHADER( - precision lowp float; - + precision mediump float; #define PI 3.14159265359 uniform sampler2D uTexture0; @@ -143,7 +141,7 @@ string LensBlurFilter::getFragmentShader(bool forComposition) const { uniform float uRadius; uniform int uNumSamples; - mediump in vec2 vUV; + highp in vec2 vUV; #if DIRECTION == 0 layout(location = 0) out vec4 fragColor0; diff --git a/libs/renderengine/gl/filters/LensBlurFilter.h b/libs/renderengine/gl/filters/LensBlurFilter.h index 8543f0db4f..1620c5a556 100644 --- a/libs/renderengine/gl/filters/LensBlurFilter.h +++ b/libs/renderengine/gl/filters/LensBlurFilter.h @@ -31,7 +31,7 @@ namespace gl { class LensBlurFilter : public BlurFilter { public: explicit LensBlurFilter(GLESRenderEngine& engine); - status_t prepare(uint32_t radius) override; + status_t prepare() override; void allocateTextures() override; private: diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index f6b5935bcf..308e93aa48 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -83,6 +83,7 @@ cc_library_shared { srcs: [ "InputListener.cpp", "InputReaderBase.cpp", + "InputThread.cpp", ], shared_libs: [ diff --git a/services/inputflinger/InputThread.cpp b/services/inputflinger/InputThread.cpp new file mode 100644 index 0000000000..b87f7a1243 --- /dev/null +++ b/services/inputflinger/InputThread.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 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 "InputThread.h" + +namespace android { + +namespace { + +// Implementation of Thread from libutils. +class InputThreadImpl : public Thread { +public: + explicit InputThreadImpl(std::function<void()> loop) + : Thread(/* canCallJava */ true), mThreadLoop(loop) {} + + ~InputThreadImpl() {} + +private: + std::function<void()> mThreadLoop; + + bool threadLoop() override { + mThreadLoop(); + return true; + } +}; + +} // namespace + +InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake) + : mName(name), mThreadWake(wake) { + mThread = new InputThreadImpl(loop); + mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY); +} + +InputThread::~InputThread() { + mThread->requestExit(); + if (mThreadWake) { + mThreadWake(); + } + mThread->requestExitAndWait(); +} + +bool InputThread::isCallingThread() { + return gettid() == mThread->getTid(); +} + +} // namespace android
\ No newline at end of file diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index 246e735330..9a6ef21724 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -203,9 +203,10 @@ static MotionEvent generateMotionEvent() { const nsecs_t currentTime = now(); MotionEvent event; - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, + 1 /* xScale */, 1 /* yScale */, /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, currentTime, diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 14bcbf70f7..b2b5145097 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -325,24 +325,6 @@ static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inp return dispatchEntry; } -// --- InputDispatcherThread --- - -class InputDispatcher::InputDispatcherThread : public Thread { -public: - explicit InputDispatcherThread(InputDispatcher* dispatcher) - : Thread(/* canCallJava */ true), mDispatcher(dispatcher) {} - - ~InputDispatcherThread() {} - -private: - InputDispatcher* mDispatcher; - - virtual bool threadLoop() override { - mDispatcher->dispatchOnce(); - return true; - } -}; - // --- InputDispatcher --- InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) @@ -367,8 +349,6 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mKeyRepeatState.lastKeyEntry = nullptr; policy->getDispatcherConfiguration(&mConfig); - - mThread = new InputDispatcherThread(this); } InputDispatcher::~InputDispatcher() { @@ -387,25 +367,21 @@ InputDispatcher::~InputDispatcher() { } status_t InputDispatcher::start() { - if (mThread->isRunning()) { + if (mThread) { return ALREADY_EXISTS; } - return mThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY); + mThread = std::make_unique<InputThread>( + "InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); }); + return OK; } status_t InputDispatcher::stop() { - if (!mThread->isRunning()) { - return OK; - } - if (gettid() == mThread->getTid()) { - ALOGE("InputDispatcher can only be stopped from outside of the InputDispatcherThread!"); + if (mThread && mThread->isCallingThread()) { + ALOGE("InputDispatcher cannot be stopped from its own thread!"); return INVALID_OPERATION; } - // Directly calling requestExitAndWait() causes the thread to not exit - // if mLooper is waiting for a long timeout. - mThread->requestExit(); - mLooper->wake(); - return mThread->requestExitAndWait(); + mThread.reset(); + return OK; } void InputDispatcher::dispatchOnce() { @@ -2410,7 +2386,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, status = connection->inputPublisher .publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId, keyEntry->source, keyEntry->displayId, - dispatchEntry->resolvedAction, + INVALID_HMAC, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, keyEntry->keyCode, keyEntry->scanCode, keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime, @@ -2424,26 +2400,28 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, PointerCoords scaledCoords[MAX_POINTERS]; const PointerCoords* usingCoords = motionEntry->pointerCoords; - // Set the X and Y offset depending on the input source. - float xOffset, yOffset; + // Set the X and Y offset and X and Y scale depending on the input source. + float xOffset = 0.0f, yOffset = 0.0f; + float xScale = 1.0f, yScale = 1.0f; if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { float globalScaleFactor = dispatchEntry->globalScaleFactor; - float wxs = dispatchEntry->windowXScale; - float wys = dispatchEntry->windowYScale; - xOffset = dispatchEntry->xOffset * wxs; - yOffset = dispatchEntry->yOffset * wys; - if (wxs != 1.0f || wys != 1.0f || globalScaleFactor != 1.0f) { + xScale = dispatchEntry->windowXScale; + yScale = dispatchEntry->windowYScale; + xOffset = dispatchEntry->xOffset * xScale; + yOffset = dispatchEntry->yOffset * yScale; + if (globalScaleFactor != 1.0f) { for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { scaledCoords[i] = motionEntry->pointerCoords[i]; - scaledCoords[i].scale(globalScaleFactor, wxs, wys); + // Don't apply window scale here since we don't want scale to affect raw + // coordinates. The scale will be sent back to the client and applied + // later when requesting relative coordinates. + scaledCoords[i].scale(globalScaleFactor, 1 /* windowXScale */, + 1 /* windowYScale */); } usingCoords = scaledCoords; } } else { - xOffset = 0.0f; - yOffset = 0.0f; - // We don't want the dispatch target to know. if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { @@ -2457,13 +2435,13 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, status = connection->inputPublisher .publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId, motionEntry->source, motionEntry->displayId, - dispatchEntry->resolvedAction, + INVALID_HMAC, dispatchEntry->resolvedAction, motionEntry->actionButton, dispatchEntry->resolvedFlags, motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState, - motionEntry->classification, xOffset, yOffset, - motionEntry->xPrecision, + motionEntry->classification, xScale, yScale, + xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision, motionEntry->xCursorPosition, motionEntry->yCursorPosition, @@ -2930,8 +2908,9 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState); KeyEvent event; - event.initialize(args->deviceId, args->source, args->displayId, args->action, flags, keyCode, - args->scanCode, metaState, repeatCount, args->downTime, args->eventTime); + event.initialize(args->deviceId, args->source, args->displayId, INVALID_HMAC, args->action, + flags, keyCode, args->scanCode, metaState, repeatCount, args->downTime, + args->eventTime); android::base::Timer t; mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); @@ -3024,9 +3003,10 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { mLock.unlock(); MotionEvent event; - event.initialize(args->deviceId, args->source, args->displayId, args->action, - args->actionButton, args->flags, args->edgeFlags, args->metaState, - args->buttonState, args->classification, 0, 0, args->xPrecision, + event.initialize(args->deviceId, args->source, args->displayId, INVALID_HMAC, + args->action, args->actionButton, args->flags, args->edgeFlags, + args->metaState, args->buttonState, args->classification, 1 /*xScale*/, + 1 /*yScale*/, 0 /* xOffset */, 0 /* yOffset */, args->xPrecision, args->yPrecision, args->xCursorPosition, args->yCursorPosition, args->downTime, args->eventTime, args->pointerCount, args->pointerProperties, args->pointerCoords); @@ -3126,7 +3106,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec accelerateMetaShortcuts(keyEvent.getDeviceId(), action, /*byref*/ keyCode, /*byref*/ metaState); keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(), - keyEvent.getDisplayId(), action, flags, keyCode, + keyEvent.getDisplayId(), INVALID_HMAC, action, flags, keyCode, keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(), keyEvent.getDownTime(), keyEvent.getEventTime()); @@ -4682,8 +4662,8 @@ void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* comman KeyEvent InputDispatcher::createKeyEvent(const KeyEntry& entry) { KeyEvent event; - event.initialize(entry.deviceId, entry.source, entry.displayId, entry.action, entry.flags, - entry.keyCode, entry.scanCode, entry.metaState, entry.repeatCount, + event.initialize(entry.deviceId, entry.source, entry.displayId, INVALID_HMAC, entry.action, + entry.flags, entry.keyCode, entry.scanCode, entry.metaState, entry.repeatCount, entry.downTime, entry.eventTime); return event; } diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index a4ba0dec6a..93de18d02f 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -25,6 +25,7 @@ #include "InputDispatcherPolicyInterface.h" #include "InputState.h" #include "InputTarget.h" +#include "InputThread.h" #include "Monitor.h" #include "TouchState.h" #include "TouchedWindow.h" @@ -124,8 +125,7 @@ private: STALE, }; - class InputDispatcherThread; - sp<InputDispatcherThread> mThread; + std::unique_ptr<InputThread> mThread; sp<InputDispatcherPolicyInterface> mPolicy; android::InputDispatcherConfiguration mConfig; diff --git a/services/inputflinger/include/InputThread.h b/services/inputflinger/include/InputThread.h new file mode 100644 index 0000000000..407365a269 --- /dev/null +++ b/services/inputflinger/include/InputThread.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2020 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. + */ + +#ifndef _UI_INPUT_THREAD_H +#define _UI_INPUT_THREAD_H + +#include <utils/Thread.h> + +namespace android { + +/* A thread that loops continuously until destructed to process input events. + * + * Creating the InputThread starts it immediately. The thread begins looping the loop + * function until the InputThread is destroyed. The wake function is used to wake anything + * that sleeps in the loop when it is time for the thread to be destroyed. + */ +class InputThread { +public: + explicit InputThread(std::string name, std::function<void()> loop, + std::function<void()> wake = nullptr); + virtual ~InputThread(); + + bool isCallingThread(); + +private: + std::string mName; + std::function<void()> mThreadWake; + sp<Thread> mThread; +}; + +} // namespace android + +#endif // _UI_INPUT_THREAD_H
\ No newline at end of file diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 05f0db1329..2023c6e8da 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -49,25 +49,6 @@ using android::base::StringPrintf; namespace android { -// --- InputReader::InputReaderThread --- - -/* Thread that reads raw events from the event hub and processes them, endlessly. */ -class InputReader::InputReaderThread : public Thread { -public: - explicit InputReaderThread(InputReader* reader) - : Thread(/* canCallJava */ true), mReader(reader) {} - - ~InputReaderThread() {} - -private: - InputReader* mReader; - - bool threadLoop() override { - mReader->loopOnce(); - return true; - } -}; - // --- InputReader --- InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub, @@ -83,7 +64,6 @@ InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub, mNextTimeout(LLONG_MAX), mConfigurationChangesToRefresh(0) { mQueuedListener = new QueuedInputListener(listener); - mThread = new InputReaderThread(this); { // acquire lock AutoMutex _l(mLock); @@ -100,25 +80,21 @@ InputReader::~InputReader() { } status_t InputReader::start() { - if (mThread->isRunning()) { + if (mThread) { return ALREADY_EXISTS; } - return mThread->run("InputReader", PRIORITY_URGENT_DISPLAY); + mThread = std::make_unique<InputThread>( + "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); }); + return OK; } status_t InputReader::stop() { - if (!mThread->isRunning()) { - return OK; - } - if (gettid() == mThread->getTid()) { - ALOGE("InputReader can only be stopped from outside of the InputReaderThread!"); + if (mThread && mThread->isCallingThread()) { + ALOGE("InputReader cannot be stopped from its own thread!"); return INVALID_OPERATION; } - // Directly calling requestExitAndWait() causes the thread to not exit - // if mEventHub is waiting for a long timeout. - mThread->requestExit(); - mEventHub->wake(); - return mThread->requestExitAndWait(); + mThread.reset(); + return OK; } void InputReader::loopOnce() { diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index 502490601e..02957cd6ee 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -21,6 +21,7 @@ #include "InputListener.h" #include "InputReaderBase.h" #include "InputReaderContext.h" +#include "InputThread.h" #include <utils/Condition.h> #include <utils/Mutex.h> @@ -116,8 +117,7 @@ protected: friend class ContextImpl; private: - class InputReaderThread; - sp<InputReaderThread> mThread; + std::unique_ptr<InputThread> mThread; Mutex mLock; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 98ebf50819..094452a0c0 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -225,18 +225,18 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { KeyEvent event; // Rejects undefined key actions. - event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, - /*action*/ -1, 0, - AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); + event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC, + /*action*/ -1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, + ARBITRARY_TIME); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject key events with undefined action."; // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API. - event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, - AKEY_EVENT_ACTION_MULTIPLE, 0, - AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); + event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC, + AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, + ARBITRARY_TIME, ARBITRARY_TIME); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) @@ -260,10 +260,10 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { constexpr MotionClassification classification = MotionClassification::NONE; // Rejects undefined motion actions. - event.initialize(DEVICE_ID, source, DISPLAY_ID, - /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ARBITRARY_TIME, ARBITRARY_TIME, + event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, + /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 1 /* xScale */, + 1 /* yScale */, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, @@ -271,24 +271,24 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { << "Should reject motion events with undefined action."; // Rejects pointer down with invalid index. - event.initialize(DEVICE_ID, source, DISPLAY_ID, + event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ARBITRARY_TIME, ARBITRARY_TIME, + 0, 0, edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, + 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer down index too large."; - event.initialize(DEVICE_ID, source, DISPLAY_ID, + event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_POINTER_DOWN | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ARBITRARY_TIME, ARBITRARY_TIME, + 0, 0, edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, + 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, @@ -296,24 +296,24 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { << "Should reject motion events with pointer down index too small."; // Rejects pointer up with invalid index. - event.initialize(DEVICE_ID, source, DISPLAY_ID, + event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ARBITRARY_TIME, ARBITRARY_TIME, + 0, 0, edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, + 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer up index too large."; - event.initialize(DEVICE_ID, source, DISPLAY_ID, + event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_POINTER_UP | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ARBITRARY_TIME, ARBITRARY_TIME, + 0, 0, edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, + 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, @@ -321,20 +321,20 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { << "Should reject motion events with pointer up index too small."; // Rejects motion events with invalid number of pointers. - event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, - metaState, 0, classification, 0, 0, 0, 0, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ARBITRARY_TIME, ARBITRARY_TIME, + event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, + edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0, + 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with 0 pointers."; - event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, - metaState, 0, classification, 0, 0, 0, 0, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ARBITRARY_TIME, ARBITRARY_TIME, + event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, + edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0, + 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, @@ -343,10 +343,10 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects motion events with invalid pointer ids. pointerProperties[0].id = -1; - event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, - metaState, 0, classification, 0, 0, 0, 0, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ARBITRARY_TIME, ARBITRARY_TIME, + event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, + edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0, + 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, @@ -354,10 +354,10 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { << "Should reject motion events with pointer ids less than 0."; pointerProperties[0].id = MAX_POINTER_ID + 1; - event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, - metaState, 0, classification, 0, 0, 0, 0, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ARBITRARY_TIME, ARBITRARY_TIME, + event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, + edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0, + 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, @@ -367,10 +367,10 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects motion events with duplicate pointer ids. pointerProperties[0].id = 1; pointerProperties[1].id = 1; - event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, - metaState, 0, classification, 0, 0, 0, 0, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ARBITRARY_TIME, ARBITRARY_TIME, + event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, + edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0, + 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, @@ -645,9 +645,9 @@ static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher, nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid key down event. - event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId, - AKEY_EVENT_ACTION_DOWN, /* flags */ 0, - AKEYCODE_A, KEY_A, AMETA_NONE, /* repeatCount */ 0, currentTime, currentTime); + event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId, INVALID_HMAC, + AKEY_EVENT_ACTION_DOWN, /* flags */ 0, AKEYCODE_A, KEY_A, AMETA_NONE, + /* repeatCount */ 0, currentTime, currentTime); // Inject event until dispatch out. return dispatcher->injectInputEvent( @@ -674,10 +674,12 @@ static int32_t injectMotionEvent(const sp<InputDispatcher>& dispatcher, int32_t nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid motion down event. - event.initialize(DEVICE_ID, source, displayId, action, /* actionButton */ 0, /* flags */ 0, + event.initialize(DEVICE_ID, source, displayId, INVALID_HMAC, action, /* actionButton */ 0, + /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, - /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0, - /* yPrecision */ 0, xCursorPosition, yCursorPosition, currentTime, currentTime, + /* xScale */ 1, /* yScale */ 1, /* xOffset */ 0, /* yOffset */ 0, + /* xPrecision */ 0, /* yPrecision */ 0, xCursorPosition, yCursorPosition, + currentTime, currentTime, /*pointerCount*/ 1, pointerProperties, pointerCoords); // Inject event until dispatch out. diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index e85281d8a9..46bbbe1200 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -130,8 +130,10 @@ bool BufferQueueLayer::setFrameRate(float frameRate) { } std::optional<float> BufferQueueLayer::getFrameRate() const { - if (mLatchedFrameRate > 0.f || mLatchedFrameRate == FRAME_RATE_NO_VOTE) - return mLatchedFrameRate; + const auto frameRate = mLatchedFrameRate.load(); + if (frameRate > 0.f || frameRate == FRAME_RATE_NO_VOTE) { + return frameRate; + } return {}; } diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index cd4227ccc0..c86c53871a 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -239,7 +239,7 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTi mReleasePreviousBuffer = true; } - mFrameCounter++; + mCurrentState.frameNumber++; mCurrentState.buffer = buffer; mCurrentState.clientCacheId = clientCacheId; @@ -247,10 +247,11 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTi setTransactionFlags(eTransactionNeeded); const int32_t layerId = getSequence(); - mFlinger->mTimeStats->setPostTime(layerId, mFrameNumber, getName().c_str(), postTime); + mFlinger->mTimeStats->setPostTime(layerId, mCurrentState.frameNumber, getName().c_str(), + postTime); mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str()); - mFlinger->mFrameTracer->traceTimestamp(layerId, buffer->getId(), mFrameNumber, postTime, - FrameTracer::FrameEvent::POST); + mFlinger->mFrameTracer->traceTimestamp(layerId, buffer->getId(), mCurrentState.frameNumber, + postTime, FrameTracer::FrameEvent::POST); mCurrentState.desiredPresentTime = desiredPresentTime; mFlinger->mScheduler->recordLayerHistory(this, @@ -414,7 +415,7 @@ bool BufferStateLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) co } uint64_t BufferStateLayer::getFrameNumber(nsecs_t /*expectedPresentTime*/) const { - return mFrameNumber; + return mDrawingState.frameNumber; } bool BufferStateLayer::getAutoRefresh() const { @@ -491,7 +492,7 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse ALOGE("[%s] rejecting buffer: " "bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}", getDebugName(), bufferWidth, bufferHeight, s.active.w, s.active.h); - mFlinger->mTimeStats->removeTimeRecord(layerId, mFrameNumber); + mFlinger->mTimeStats->removeTimeRecord(layerId, mDrawingState.frameNumber); return BAD_VALUE; } @@ -499,8 +500,6 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse handle->latchTime = latchTime; } - mFrameNumber = mFrameCounter; - if (!SyncFeatures::getInstance().useNativeFenceSync()) { // Bind the new buffer to the GL texture. // @@ -517,11 +516,13 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse } const uint64_t bufferID = getCurrentBufferId(); - mFlinger->mTimeStats->setAcquireFence(layerId, mFrameNumber, mBufferInfo.mFenceTime); - mFlinger->mFrameTracer->traceFence(layerId, bufferID, mFrameNumber, mBufferInfo.mFenceTime, + mFlinger->mTimeStats->setAcquireFence(layerId, mDrawingState.frameNumber, + mBufferInfo.mFenceTime); + mFlinger->mFrameTracer->traceFence(layerId, bufferID, mDrawingState.frameNumber, + mBufferInfo.mFenceTime, FrameTracer::FrameEvent::ACQUIRE_FENCE); - mFlinger->mTimeStats->setLatchTime(layerId, mFrameNumber, latchTime); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferID, mFrameNumber, latchTime, + mFlinger->mTimeStats->setLatchTime(layerId, mDrawingState.frameNumber, latchTime); + mFlinger->mFrameTracer->traceTimestamp(layerId, bufferID, mDrawingState.frameNumber, latchTime, FrameTracer::FrameEvent::LATCH); mCurrentStateModified = false; @@ -548,7 +549,7 @@ status_t BufferStateLayer::updateActiveBuffer() { status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) { // TODO(marissaw): support frame history events mPreviousFrameNumber = mCurrentFrameNumber; - mCurrentFrameNumber = mFrameNumber; + mCurrentFrameNumber = mDrawingState.frameNumber; return NO_ERROR; } diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp index 04854d0803..dbdfd5b9ad 100644 --- a/services/surfaceflinger/ColorLayer.cpp +++ b/services/surfaceflinger/ColorLayer.cpp @@ -61,7 +61,7 @@ std::optional<compositionengine::LayerFE::LayerSettings> ColorLayer::prepareClie } bool ColorLayer::isVisible() const { - return !isHiddenByPolicy() && getAlpha() > 0.0f; + return !isHiddenByPolicy() && getAlpha() > 0.0_hf; } bool ColorLayer::setColor(const half3& color) { @@ -104,7 +104,9 @@ std::shared_ptr<compositionengine::Layer> ColorLayer::getCompositionLayer() cons } bool ColorLayer::isOpaque(const Layer::State& s) const { - return (s.flags & layer_state_t::eLayerOpaque) != 0; + // Consider the layer to be opaque if its opaque flag is set or its effective + // alpha (considering the alpha of its parents as well) is 1.0; + return (s.flags & layer_state_t::eLayerOpaque) != 0 || getAlpha() == 1.0_hf; } ui::Dataspace ColorLayer::getDataSpace() const { diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index a5da0b1535..4ab7082522 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -163,7 +163,8 @@ public: // Sets the projection state to use virtual void setProjection(const ui::Transform&, uint32_t orientation, const Rect& frame, - const Rect& viewport, const Rect& scissor, bool needsFiltering) = 0; + const Rect& viewport, const Rect& sourceClip, + const Rect& destinationClip, bool needsFiltering) = 0; // Sets the bounds to use virtual void setBounds(const ui::Size&) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index f469e62430..8dc440c27d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -39,7 +39,8 @@ public: std::optional<DisplayId> getDisplayId() const override; void setCompositionEnabled(bool) override; void setProjection(const ui::Transform&, uint32_t orientation, const Rect& frame, - const Rect& viewport, const Rect& scissor, bool needsFiltering) override; + const Rect& viewport, const Rect& sourceClip, const Rect& destinationClip, + bool needsFiltering) override; void setBounds(const ui::Size&) override; void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index e700b76156..66ed2b6d25 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -79,8 +79,11 @@ struct OutputCompositionState { // The logical space user viewport rectangle Rect viewport; - // The physical space scissor rectangle - Rect scissor; + // The physical space source clip rectangle + Rect sourceClip; + + // The physical space destination clip rectangle + Rect destinationClip; // If true, RenderEngine filtering should be enabled bool needsFiltering{false}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index c41302d1a2..59906b9a9a 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -37,8 +37,9 @@ public: MOCK_CONST_METHOD0(getDisplayId, std::optional<DisplayId>()); MOCK_METHOD1(setCompositionEnabled, void(bool)); - MOCK_METHOD6(setProjection, - void(const ui::Transform&, uint32_t, const Rect&, const Rect&, const Rect&, bool)); + MOCK_METHOD7(setProjection, + void(const ui::Transform&, uint32_t, const Rect&, const Rect&, const Rect&, + const Rect&, bool)); MOCK_METHOD1(setBounds, void(const ui::Size&)); MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool)); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 55371dfef0..ce4b84a454 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -107,11 +107,13 @@ void Output::setCompositionEnabled(bool enabled) { } void Output::setProjection(const ui::Transform& transform, uint32_t orientation, const Rect& frame, - const Rect& viewport, const Rect& scissor, bool needsFiltering) { + const Rect& viewport, const Rect& sourceClip, + const Rect& destinationClip, bool needsFiltering) { auto& outputState = editState(); outputState.transform = transform; outputState.orientation = orientation; - outputState.scissor = scissor; + outputState.sourceClip = sourceClip; + outputState.destinationClip = destinationClip; outputState.frame = frame; outputState.viewport = viewport; outputState.needsFiltering = needsFiltering; @@ -834,8 +836,8 @@ std::optional<base::unique_fd> Output::composeSurfaces(const Region& debugRegion const bool supportsProtectedContent = renderEngine.supportsProtectedContent(); renderengine::DisplaySettings clientCompositionDisplay; - clientCompositionDisplay.physicalDisplay = outputState.scissor; - clientCompositionDisplay.clip = outputState.scissor; + clientCompositionDisplay.physicalDisplay = outputState.destinationClip; + clientCompositionDisplay.clip = outputState.sourceClip; clientCompositionDisplay.globalTransform = outputState.transform.asMatrix4(); clientCompositionDisplay.orientation = outputState.orientation; clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut() @@ -903,8 +905,7 @@ std::optional<base::unique_fd> Output::composeSurfaces(const Region& debugRegion // GPU composition can finish in time. We must reset GPU frequency afterwards, // because high frequency consumes extra battery. const bool expensiveRenderingExpected = - clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3 || - mLayerRequestingBackgroundBlur != nullptr; + clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3; if (expensiveRenderingExpected) { setExpensiveRenderingExpected(true); } diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index 84d79f7924..ca5be4821c 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -40,7 +40,8 @@ void OutputCompositionState::dump(std::string& out) const { dumpVal(out, "frame", frame); dumpVal(out, "viewport", viewport); - dumpVal(out, "scissor", scissor); + dumpVal(out, "sourceClip", sourceClip); + dumpVal(out, "destinationClip", destinationClip); dumpVal(out, "needsFiltering", needsFiltering); out.append("\n "); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 6e8d3dfa7f..463d095b8c 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -249,16 +249,19 @@ TEST_F(OutputTest, setProjectionTriviallyWorks) { const int32_t orientation = 123; const Rect frame{1, 2, 3, 4}; const Rect viewport{5, 6, 7, 8}; - const Rect scissor{9, 10, 11, 12}; + const Rect sourceClip{9, 10, 11, 12}; + const Rect destinationClip{13, 14, 15, 16}; const bool needsFiltering = true; - mOutput->setProjection(transform, orientation, frame, viewport, scissor, needsFiltering); + mOutput->setProjection(transform, orientation, frame, viewport, sourceClip, destinationClip, + needsFiltering); EXPECT_THAT(mOutput->getState().transform, transform); EXPECT_EQ(orientation, mOutput->getState().orientation); EXPECT_EQ(frame, mOutput->getState().frame); EXPECT_EQ(viewport, mOutput->getState().viewport); - EXPECT_EQ(scissor, mOutput->getState().scissor); + EXPECT_EQ(sourceClip, mOutput->getState().sourceClip); + EXPECT_EQ(destinationClip, mOutput->getState().destinationClip); EXPECT_EQ(needsFiltering, mOutput->getState().needsFiltering); } @@ -2778,7 +2781,8 @@ struct OutputComposeSurfacesTest : public testing::Test { mOutput.mState.frame = kDefaultOutputFrame; mOutput.mState.viewport = kDefaultOutputViewport; - mOutput.mState.scissor = kDefaultOutputScissor; + mOutput.mState.sourceClip = kDefaultOutputSourceClip; + mOutput.mState.destinationClip = kDefaultOutputDestinationClip; mOutput.mState.transform = ui::Transform{kDefaultOutputOrientation}; mOutput.mState.orientation = kDefaultOutputOrientation; mOutput.mState.dataspace = kDefaultOutputDataspace; @@ -2822,7 +2826,8 @@ struct OutputComposeSurfacesTest : public testing::Test { static const Rect kDefaultOutputFrame; static const Rect kDefaultOutputViewport; - static const Rect kDefaultOutputScissor; + static const Rect kDefaultOutputSourceClip; + static const Rect kDefaultOutputDestinationClip; static const mat4 kDefaultColorTransformMat; static const Region kDebugRegion; @@ -2842,7 +2847,8 @@ struct OutputComposeSurfacesTest : public testing::Test { const Rect OutputComposeSurfacesTest::kDefaultOutputFrame{1001, 1002, 1003, 1004}; const Rect OutputComposeSurfacesTest::kDefaultOutputViewport{1005, 1006, 1007, 1008}; -const Rect OutputComposeSurfacesTest::kDefaultOutputScissor{1009, 1010, 1011, 1012}; +const Rect OutputComposeSurfacesTest::kDefaultOutputSourceClip{1009, 1010, 1011, 1012}; +const Rect OutputComposeSurfacesTest::kDefaultOutputDestinationClip{1013, 1014, 1015, 1016}; const mat4 OutputComposeSurfacesTest::kDefaultColorTransformMat{mat4() * 0.5f}; const Region OutputComposeSurfacesTest::kDebugRegion{Rect{100, 101, 102, 103}}; const HdrCapabilities OutputComposeSurfacesTest:: @@ -3085,9 +3091,10 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrMixedComposi verify().ifMixedCompositionIs(true) .andIfUsesHdr(true) .andIfSkipColorTransform(false) - .thenExpectDisplaySettingsUsed({kDefaultOutputScissor, kDefaultOutputScissor, mat4(), - kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(), - Region::INVALID_REGION, kDefaultOutputOrientation}) + .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip, + mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace, + mat4(), Region::INVALID_REGION, + kDefaultOutputOrientation}) .execute() .expectAFenceWasReturned(); } @@ -3096,9 +3103,10 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrMixedComp verify().ifMixedCompositionIs(true) .andIfUsesHdr(false) .andIfSkipColorTransform(false) - .thenExpectDisplaySettingsUsed({kDefaultOutputScissor, kDefaultOutputScissor, mat4(), - kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(), - Region::INVALID_REGION, kDefaultOutputOrientation}) + .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip, + mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace, + mat4(), Region::INVALID_REGION, + kDefaultOutputOrientation}) .execute() .expectAFenceWasReturned(); } @@ -3107,8 +3115,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrOnlyClientCo verify().ifMixedCompositionIs(false) .andIfUsesHdr(true) .andIfSkipColorTransform(false) - .thenExpectDisplaySettingsUsed({kDefaultOutputScissor, kDefaultOutputScissor, mat4(), - kDefaultMaxLuminance, kDefaultOutputDataspace, + .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip, + mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace, kDefaultColorTransformMat, Region::INVALID_REGION, kDefaultOutputOrientation}) .execute() @@ -3119,8 +3127,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrOnlyClien verify().ifMixedCompositionIs(false) .andIfUsesHdr(false) .andIfSkipColorTransform(false) - .thenExpectDisplaySettingsUsed({kDefaultOutputScissor, kDefaultOutputScissor, mat4(), - kDefaultMaxLuminance, kDefaultOutputDataspace, + .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip, + mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace, kDefaultColorTransformMat, Region::INVALID_REGION, kDefaultOutputOrientation}) .execute() @@ -3132,9 +3140,10 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, verify().ifMixedCompositionIs(false) .andIfUsesHdr(true) .andIfSkipColorTransform(true) - .thenExpectDisplaySettingsUsed({kDefaultOutputScissor, kDefaultOutputScissor, mat4(), - kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(), - Region::INVALID_REGION, kDefaultOutputOrientation}) + .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip, + mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace, + mat4(), Region::INVALID_REGION, + kDefaultOutputOrientation}) .execute() .expectAFenceWasReturned(); } @@ -3345,7 +3354,8 @@ struct GenerateClientCompositionRequestsTest_ThreeLayers GenerateClientCompositionRequestsTest_ThreeLayers() { mOutput.mState.frame = kDisplayFrame; mOutput.mState.viewport = kDisplayViewport; - mOutput.mState.scissor = kDisplayScissor; + mOutput.mState.sourceClip = kDisplaySourceClip; + mOutput.mState.destinationClip = kDisplayDestinationClip; mOutput.mState.transform = ui::Transform{kDisplayOrientation}; mOutput.mState.orientation = kDisplayOrientation; mOutput.mState.needsFiltering = false; @@ -3376,14 +3386,17 @@ struct GenerateClientCompositionRequestsTest_ThreeLayers static const Rect kDisplayFrame; static const Rect kDisplayViewport; - static const Rect kDisplayScissor; + static const Rect kDisplaySourceClip; + static const Rect kDisplayDestinationClip; std::array<Layer, 3> mLayers; }; const Rect GenerateClientCompositionRequestsTest_ThreeLayers::kDisplayFrame(0, 0, 100, 200); const Rect GenerateClientCompositionRequestsTest_ThreeLayers::kDisplayViewport(0, 0, 101, 201); -const Rect GenerateClientCompositionRequestsTest_ThreeLayers::kDisplayScissor(0, 0, 102, 202); +const Rect GenerateClientCompositionRequestsTest_ThreeLayers::kDisplaySourceClip(0, 0, 102, 202); +const Rect GenerateClientCompositionRequestsTest_ThreeLayers::kDisplayDestinationClip(0, 0, 103, + 203); TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, handlesNoClientCompostionLayers) { EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); @@ -3789,13 +3802,15 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq const Rect kPortraitFrame(0, 0, 1000, 2000); const Rect kPortraitViewport(0, 0, 2000, 1000); - const Rect kPortraitScissor(0, 0, 1000, 2000); + const Rect kPortraitSourceClip(0, 0, 1000, 2000); + const Rect kPortraitDestinationClip(0, 0, 1000, 2000); const uint32_t kPortraitOrientation = TR_ROT_90; constexpr ui::Dataspace kOutputDataspace = ui::Dataspace::DISPLAY_P3; mOutput.mState.frame = kPortraitFrame; mOutput.mState.viewport = kPortraitViewport; - mOutput.mState.scissor = kPortraitScissor; + mOutput.mState.sourceClip = kPortraitSourceClip; + mOutput.mState.destinationClip = kPortraitDestinationClip; mOutput.mState.transform = ui::Transform{kPortraitOrientation}; mOutput.mState.orientation = kPortraitOrientation; mOutput.mState.needsFiltering = false; diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 4ae6dadfe8..f3fe1592c2 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -222,10 +222,13 @@ void DisplayDevice::setProjection(ui::Rotation orientation, Rect viewport, Rect const bool needsFiltering = (!globalTransform.preserveRects() || (type >= ui::Transform::SCALE)); - Rect scissor = globalTransform.transform(viewport); - if (scissor.isEmpty()) { - scissor = displayBounds; + Rect sourceClip = globalTransform.transform(viewport); + if (sourceClip.isEmpty()) { + sourceClip = displayBounds; } + // For normal display use we always set the source and destination clip + // rectangles to the same values. + const Rect& destinationClip = sourceClip; uint32_t transformOrientation; @@ -236,8 +239,8 @@ void DisplayDevice::setProjection(ui::Rotation orientation, Rect viewport, Rect transformOrientation = ui::Transform::toRotationFlags(orientation); } - getCompositionDisplay()->setProjection(globalTransform, transformOrientation, - frame, viewport, scissor, needsFiltering); + getCompositionDisplay()->setProjection(globalTransform, transformOrientation, frame, viewport, + sourceClip, destinationClip, needsFiltering); } ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() { @@ -302,8 +305,8 @@ const Rect& DisplayDevice::getFrame() const { return mCompositionDisplay->getState().frame; } -const Rect& DisplayDevice::getScissor() const { - return mCompositionDisplay->getState().scissor; +const Rect& DisplayDevice::getSourceClip() const { + return mCompositionDisplay->getState().sourceClip; } bool DisplayDevice::hasWideColorGamut() const { diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index ff48ecdedc..75c709e8da 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -96,7 +96,7 @@ public: const ui::Transform& getTransform() const; const Rect& getViewport() const; const Rect& getFrame() const; - const Rect& getScissor() const; + const Rect& getSourceClip() const; bool needsFiltering() const; uint32_t getLayerStack() const; @@ -271,7 +271,7 @@ public: Rect getSourceCrop() const override { // use the projected display viewport by default. if (mSourceCrop.isEmpty()) { - return mDisplay->getScissor(); + return mDisplay->getSourceClip(); } // Recompute the device transformation for the source crop. @@ -280,14 +280,14 @@ public: ui::Transform translateLogical; ui::Transform scale; const Rect& viewport = mDisplay->getViewport(); - const Rect& scissor = mDisplay->getScissor(); + const Rect& sourceClip = mDisplay->getSourceClip(); const Rect& frame = mDisplay->getFrame(); const auto flags = ui::Transform::toRotationFlags(mDisplay->getPhysicalOrientation()); rotation.set(flags, getWidth(), getHeight()); translateLogical.set(-viewport.left, -viewport.top); - translatePhysical.set(scissor.left, scissor.top); + translatePhysical.set(sourceClip.left, sourceClip.top); scale.set(frame.getWidth() / float(viewport.getWidth()), 0, 0, frame.getHeight() / float(viewport.getHeight())); const ui::Transform finalTransform = diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 6f8df9585a..cedab59b23 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -101,6 +101,7 @@ Layer::Layer(const LayerCreationArgs& args) mCurrentState.active.w = UINT32_MAX; mCurrentState.active.h = UINT32_MAX; mCurrentState.active.transform.set(0, 0); + mCurrentState.frameNumber = 0; mCurrentState.transform = 0; mCurrentState.transformToDisplayInverse = false; mCurrentState.crop.makeInvalid(); @@ -1803,6 +1804,15 @@ void Layer::traverseInReverseZOrder(LayerVector::StateSet stateSet, } } +void Layer::traverse(LayerVector::StateSet state, const LayerVector::Visitor& visitor) { + visitor(this); + const LayerVector& children = + state == LayerVector::StateSet::Drawing ? mDrawingChildren : mCurrentChildren; + for (const sp<Layer>& child : children) { + child->traverse(state, visitor); + } +} + LayerVector Layer::makeChildrenTraversalList(LayerVector::StateSet stateSet, const std::vector<Layer*>& layersInTree) { LOG_ALWAYS_FATAL_IF(stateSet == LayerVector::StateSet::Invalid, diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index c75a570985..da3df8fd8d 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -189,6 +189,7 @@ public: ui::Dataspace dataspace; // The fields below this point are only used by BufferStateLayer + uint64_t frameNumber; Geometry active; uint32_t transform; @@ -678,6 +679,15 @@ public: renderengine::ShadowSettings getShadowSettings(const Rect& viewport) const; + /** + * Traverse this layer and it's hierarchy of children directly. Unlike traverseInZOrder + * which will not emit children who have relativeZOrder to another layer, this method + * just directly emits all children. It also emits them in no particular order. + * So this method is not suitable for graphical operations, as it doesn't represent + * the scene state, but it's also more efficient than traverseInZOrder and so useful for + * book-keeping. + */ + void traverse(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor); void traverseInReverseZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor); void traverseInZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor); diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp index 7c959b9e56..9b94920408 100644 --- a/services/surfaceflinger/LayerVector.cpp +++ b/services/surfaceflinger/LayerVector.cpp @@ -86,6 +86,14 @@ void LayerVector::traverseInReverseZOrder(StateSet stateSet, const Visitor& visi layer->traverseInReverseZOrder(stateSet, visitor); } } + +void LayerVector::traverse(const Visitor& visitor) const { + for (auto i = static_cast<int64_t>(size()) - 1; i >= 0; i--) { + const auto& layer = (*this)[i]; + layer->traverse(mStateSet, visitor); + } +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/LayerVector.h b/services/surfaceflinger/LayerVector.h index 88d7711bb8..a531f4fd95 100644 --- a/services/surfaceflinger/LayerVector.h +++ b/services/surfaceflinger/LayerVector.h @@ -50,7 +50,7 @@ public: using Visitor = std::function<void(Layer*)>; void traverseInReverseZOrder(StateSet stateSet, const Visitor& visitor) const; void traverseInZOrder(StateSet stateSet, const Visitor& visitor) const; - + void traverse(const Visitor& visitor) const; private: const StateSet mStateSet; }; diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp index d94d758ec5..f309d4d889 100644 --- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp @@ -57,7 +57,7 @@ bool LayerInfoV2::isRecentlyActive(nsecs_t now) const { bool LayerInfoV2::isFrequent(nsecs_t now) const { // Assume layer is infrequent if too few present times have been recorded. if (mFrameTimes.size() < FREQUENT_LAYER_WINDOW_SIZE) { - return true; + return false; } // Layer is frequent if the earliest value in the window of most recent present times is @@ -100,8 +100,7 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { static_cast<float>(totalPresentTimeDeltas) / (mFrameTimes.size() - 1); // Now once we calculated the refresh rate we need to make sure that all the frames we captured - // are evenly distrubuted and we don't calculate the average across some burst of frames. - + // are evenly distributed and we don't calculate the average across some burst of frames. for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) { const nsecs_t presentTimeDeltas = std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod); diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index c187049eb1..e4b0287148 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -125,12 +125,13 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( } for (const auto& layer : layers) { + ALOGV("Calculating score for %s (type: %d)", layer.name.c_str(), layer.vote); if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min || layer.vote == LayerVoteType::Max) { continue; } - // If we have Explicit layers, ignore the Huristic ones + // If we have Explicit layers, ignore the Hueristic ones if (explicitVoteLayers > 0 && layer.vote == LayerVoteType::Heuristic) { continue; } @@ -148,24 +149,26 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( } float layerScore; + static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1 if (displayFramesRem == 0) { // Layer desired refresh rate matches the display rate. layerScore = layer.weight * 1.0f; } else if (displayFramesQuot == 0) { // Layer desired refresh rate is higher the display rate. - layerScore = layer.weight * layerPeriod / displayPeriod; + layerScore = layer.weight * + (static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) * + (1.0f / (MAX_FRAMES_TO_FIT + 1)); } else { // Layer desired refresh rate is lower the display rate. Check how well it fits the // cadence auto diff = std::abs(displayFramesRem - (displayPeriod - displayFramesRem)); int iter = 2; - static constexpr size_t MAX_ITERATOR = 10; // Stop calculating when score < 0.1 - while (diff > MARGIN && iter < MAX_ITERATOR) { + while (diff > MARGIN && iter < MAX_FRAMES_TO_FIT) { diff = diff - (displayPeriod - diff); iter++; } - layerScore = layer.weight * 1.0f / iter; + layerScore = layer.weight * (1.0f / iter); } ALOGV("%s (weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(), diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index ac326334f4..e6884159c3 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -71,12 +71,12 @@ nsecs_t VSyncPredictor::currentPeriod() const { return std::get<0>(mRateMap.find(mIdealPeriod)->second); } -void VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { +bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { std::lock_guard<std::mutex> lk(mMutex); if (!validate(timestamp)) { ALOGV("timestamp was too far off the last known timestamp"); - return; + return false; } if (timestamps.size() != kHistorySize) { @@ -89,7 +89,7 @@ void VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { if (timestamps.size() < kMinimumSamplesForPrediction) { mRateMap[mIdealPeriod] = {mIdealPeriod, 0}; - return; + return true; } // This is a 'simple linear regression' calculation of Y over X, with Y being the @@ -143,7 +143,7 @@ void VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { if (CC_UNLIKELY(bottom == 0)) { it->second = {mIdealPeriod, 0}; - return; + return false; } nsecs_t const anticipatedPeriod = top / bottom * kScalingFactor; @@ -156,6 +156,7 @@ void VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { ALOGV("model update ts: %" PRId64 " slope: %" PRId64 " intercept: %" PRId64, timestamp, anticipatedPeriod, intercept); + return true; } nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h index e3665553c7..532fe9e928 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.h +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h @@ -38,7 +38,7 @@ public: uint32_t outlierTolerancePercent); ~VSyncPredictor(); - void addVsyncTimestamp(nsecs_t timestamp) final; + bool addVsyncTimestamp(nsecs_t timestamp) final; nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final; nsecs_t currentPeriod() const final; void resetModel() final; diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index 53fa212465..70e4760676 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -130,10 +130,11 @@ bool VSyncReactor::addPresentFence(const std::shared_ptr<FenceTime>& fence) { } std::lock_guard<std::mutex> lk(mMutex); - if (mIgnorePresentFences) { + if (mExternalIgnoreFences || mInternalIgnoreFences) { return true; } + bool timestampAccepted = true; for (auto it = mUnfiredFences.begin(); it != mUnfiredFences.end();) { auto const time = (*it)->getCachedSignalTime(); if (time == Fence::SIGNAL_TIME_PENDING) { @@ -141,7 +142,8 @@ bool VSyncReactor::addPresentFence(const std::shared_ptr<FenceTime>& fence) { } else if (time == Fence::SIGNAL_TIME_INVALID) { it = mUnfiredFences.erase(it); } else { - mTracker->addVsyncTimestamp(time); + timestampAccepted &= mTracker->addVsyncTimestamp(time); + it = mUnfiredFences.erase(it); } } @@ -152,7 +154,13 @@ bool VSyncReactor::addPresentFence(const std::shared_ptr<FenceTime>& fence) { } mUnfiredFences.push_back(fence); } else { - mTracker->addVsyncTimestamp(signalTime); + timestampAccepted &= mTracker->addVsyncTimestamp(signalTime); + } + + if (!timestampAccepted) { + mMoreSamplesNeeded = true; + setIgnorePresentFencesInternal(true); + mPeriodConfirmationInProgress = true; } return mMoreSamplesNeeded; @@ -160,8 +168,17 @@ bool VSyncReactor::addPresentFence(const std::shared_ptr<FenceTime>& fence) { void VSyncReactor::setIgnorePresentFences(bool ignoration) { std::lock_guard<std::mutex> lk(mMutex); - mIgnorePresentFences = ignoration; - if (mIgnorePresentFences == true) { + mExternalIgnoreFences = ignoration; + updateIgnorePresentFencesInternal(); +} + +void VSyncReactor::setIgnorePresentFencesInternal(bool ignoration) { + mInternalIgnoreFences = ignoration; + updateIgnorePresentFencesInternal(); +} + +void VSyncReactor::updateIgnorePresentFencesInternal() { + if (mExternalIgnoreFences || mInternalIgnoreFences) { mUnfiredFences.clear(); } } @@ -177,14 +194,18 @@ nsecs_t VSyncReactor::expectedPresentTime() { } void VSyncReactor::startPeriodTransition(nsecs_t newPeriod) { + mPeriodConfirmationInProgress = true; mPeriodTransitioningTo = newPeriod; mMoreSamplesNeeded = true; + setIgnorePresentFencesInternal(true); } void VSyncReactor::endPeriodTransition() { + setIgnorePresentFencesInternal(false); + mMoreSamplesNeeded = false; mPeriodTransitioningTo.reset(); + mPeriodConfirmationInProgress = false; mLastHwVsync.reset(); - mMoreSamplesNeeded = false; } void VSyncReactor::setPeriod(nsecs_t period) { @@ -208,27 +229,33 @@ void VSyncReactor::beginResync() { void VSyncReactor::endResync() {} -bool VSyncReactor::periodChangeDetected(nsecs_t vsync_timestamp) { - if (!mLastHwVsync || !mPeriodTransitioningTo) { +bool VSyncReactor::periodConfirmed(nsecs_t vsync_timestamp) { + if (!mLastHwVsync || !mPeriodConfirmationInProgress) { return false; } + auto const period = mPeriodTransitioningTo ? *mPeriodTransitioningTo : getPeriod(); + + static constexpr int allowancePercent = 10; + static constexpr std::ratio<allowancePercent, 100> allowancePercentRatio; + auto const allowance = period * allowancePercentRatio.num / allowancePercentRatio.den; auto const distance = vsync_timestamp - *mLastHwVsync; - return std::abs(distance - *mPeriodTransitioningTo) < std::abs(distance - getPeriod()); + return std::abs(distance - period) < allowance; } bool VSyncReactor::addResyncSample(nsecs_t timestamp, bool* periodFlushed) { assert(periodFlushed); std::lock_guard<std::mutex> lk(mMutex); - if (periodChangeDetected(timestamp)) { - mTracker->setPeriod(*mPeriodTransitioningTo); - for (auto& entry : mCallbacks) { - entry.second->setPeriod(*mPeriodTransitioningTo); + if (periodConfirmed(timestamp)) { + if (mPeriodTransitioningTo) { + mTracker->setPeriod(*mPeriodTransitioningTo); + for (auto& entry : mCallbacks) { + entry.second->setPeriod(*mPeriodTransitioningTo); + } + *periodFlushed = true; } - endPeriodTransition(); - *periodFlushed = true; - } else if (mPeriodTransitioningTo) { + } else if (mPeriodConfirmationInProgress) { mLastHwVsync = timestamp; mMoreSamplesNeeded = true; *periodFlushed = false; diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h index f318dcb720..5b79f35c23 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.h +++ b/services/surfaceflinger/Scheduler/VSyncReactor.h @@ -61,9 +61,11 @@ public: void reset() final; private: + void setIgnorePresentFencesInternal(bool ignoration) REQUIRES(mMutex); + void updateIgnorePresentFencesInternal() REQUIRES(mMutex); void startPeriodTransition(nsecs_t newPeriod) REQUIRES(mMutex); void endPeriodTransition() REQUIRES(mMutex); - bool periodChangeDetected(nsecs_t vsync_timestamp) REQUIRES(mMutex); + bool periodConfirmed(nsecs_t vsync_timestamp) REQUIRES(mMutex); std::unique_ptr<Clock> const mClock; std::unique_ptr<VSyncTracker> const mTracker; @@ -71,10 +73,12 @@ private: size_t const mPendingLimit; std::mutex mMutex; - bool mIgnorePresentFences GUARDED_BY(mMutex) = false; + bool mInternalIgnoreFences GUARDED_BY(mMutex) = false; + bool mExternalIgnoreFences GUARDED_BY(mMutex) = false; std::vector<std::shared_ptr<FenceTime>> mUnfiredFences GUARDED_BY(mMutex); bool mMoreSamplesNeeded GUARDED_BY(mMutex) = false; + bool mPeriodConfirmationInProgress GUARDED_BY(mMutex) = false; std::optional<nsecs_t> mPeriodTransitioningTo GUARDED_BY(mMutex); std::optional<nsecs_t> mLastHwVsync GUARDED_BY(mMutex); diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h index 2b278848b3..a25b8a98de 100644 --- a/services/surfaceflinger/Scheduler/VSyncTracker.h +++ b/services/surfaceflinger/Scheduler/VSyncTracker.h @@ -33,8 +33,10 @@ public: * to the model. * * \param [in] timestamp The timestamp when the vsync signal was. + * \return True if the timestamp was consistent with the internal model, + * False otherwise */ - virtual void addVsyncTimestamp(nsecs_t timestamp) = 0; + virtual bool addVsyncTimestamp(nsecs_t timestamp) = 0; /* * Access the next anticipated vsync time such that the anticipated time >= timePoint. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 62d47e1d6e..61d197ca68 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2059,7 +2059,7 @@ void SurfaceFlinger::postComposition() compositorTiming = getBE().mCompositorTiming; } - mDrawingState.traverseInZOrder([&](Layer* layer) { + mDrawingState.traverse([&](Layer* layer) { bool frameLatched = layer->onPostComposition(displayDevice, glCompositionDoneFenceTime, presentFenceTime, compositorTiming); if (frameLatched) { @@ -2496,7 +2496,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); // Notify all layers of available frames - mCurrentState.traverseInZOrder([expectedPresentTime](Layer* layer) { + mCurrentState.traverse([expectedPresentTime](Layer* layer) { layer->notifyAvailableFrames(expectedPresentTime); }); @@ -2506,7 +2506,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) */ if ((transactionFlags & eTraversalNeeded) || mTraversalNeededMainThread) { - mCurrentState.traverseInZOrder([&](Layer* layer) { + mCurrentState.traverse([&](Layer* layer) { uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); if (!trFlags) return; @@ -2553,7 +2553,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) sp<const DisplayDevice> hintDisplay; uint32_t currentlayerStack = 0; bool first = true; - mCurrentState.traverseInZOrder([&](Layer* layer) { + mCurrentState.traverse([&](Layer* layer) { // NOTE: we rely on the fact that layers are sorted by // layerStack first (so we don't have to traverse the list // of displays for every layer). @@ -2781,7 +2781,7 @@ void SurfaceFlinger::commitTransactionLocked() { // clear the "changed" flags in current state mCurrentState.colorMatrixChanged = false; - mDrawingState.traverseInZOrder([&](Layer* layer) { + mDrawingState.traverse([&](Layer* layer) { layer->commitChildList(); // If the layer can be reached when traversing mDrawingState, then the layer is no @@ -2792,7 +2792,7 @@ void SurfaceFlinger::commitTransactionLocked() { }); commitOffscreenLayers(); - mDrawingState.traverseInZOrder([&](Layer* layer) { layer->updateMirrorInfo(); }); + mDrawingState.traverse([&](Layer* layer) { layer->updateMirrorInfo(); }); } void SurfaceFlinger::withTracingLock(std::function<void()> lockedOperation) { @@ -2817,7 +2817,7 @@ void SurfaceFlinger::withTracingLock(std::function<void()> lockedOperation) { void SurfaceFlinger::commitOffscreenLayers() { for (Layer* offscreenLayer : mOffscreenLayers) { - offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [](Layer* layer) { + offscreenLayer->traverse(LayerVector::StateSet::Drawing, [](Layer* layer) { uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); if (!trFlags) return; @@ -2858,7 +2858,7 @@ bool SurfaceFlinger::handlePageFlip() // 3.) Layer 1 is latched. // Display is now waiting on Layer 1's frame, which is behind layer 0's // second frame. But layer 0's second frame could be waiting on display. - mDrawingState.traverseInZOrder([&](Layer* layer) { + mDrawingState.traverse([&](Layer* layer) { if (layer->hasReadyFrame()) { frameQueued = true; if (layer->shouldPresentNow(expectedPresentTime)) { @@ -2876,7 +2876,7 @@ bool SurfaceFlinger::handlePageFlip() // be shown on screen. Therefore, we need to latch and release buffers of offscreen // layers to ensure dequeueBuffer doesn't block indefinitely. for (Layer* offscreenLayer : mOffscreenLayers) { - offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, + offscreenLayer->traverse(LayerVector::StateSet::Drawing, [&](Layer* l) { l->latchAndReleaseBuffer(); }); } @@ -2911,7 +2911,7 @@ bool SurfaceFlinger::handlePageFlip() mBootStage = BootStage::BOOTANIMATION; } - mDrawingState.traverseInZOrder([&](Layer* layer) { layer->updateCloneBufferInfo(); }); + mDrawingState.traverse([&](Layer* layer) { layer->updateCloneBufferInfo(); }); // Only continue with the refresh if there is actually new work to do return !mLayersWithQueuedFrames.empty() && newDataLatched; @@ -3733,7 +3733,7 @@ std::string SurfaceFlinger::getUniqueLayerName(const char* name) { bool matchFound = true; while (matchFound) { matchFound = false; - mCurrentState.traverseInZOrder([&](Layer* layer) { + mCurrentState.traverse([&](Layer* layer) { if (layer->getName() == uniqueName) { matchFound = true; uniqueName = base::StringPrintf("%s#%u", name, ++dupeCounter); @@ -4104,7 +4104,7 @@ void SurfaceFlinger::clearStatsLocked(const DumpArgs& args, std::string&) { const bool clearAll = args.size() < 2; const auto name = clearAll ? String8() : String8(args[1]); - mCurrentState.traverseInZOrder([&](Layer* layer) { + mCurrentState.traverse([&](Layer* layer) { if (clearAll || layer->getName() == name.string()) { layer->clearFrameStats(); } @@ -4120,7 +4120,7 @@ void SurfaceFlinger::dumpTimeStats(const DumpArgs& args, bool asProto, std::stri // This should only be called from the main thread. Otherwise it would need // the lock and should use mCurrentState rather than mDrawingState. void SurfaceFlinger::logFrameStats() { - mDrawingState.traverseInZOrder([&](Layer* layer) { + mDrawingState.traverse([&](Layer* layer) { layer->logFrameStats(); }); @@ -4355,7 +4355,7 @@ void SurfaceFlinger::dumpOffscreenLayers(std::string& result) { result.append("Offscreen Layers:\n"); postMessageSync(new LambdaMessage([&]() { for (Layer* offscreenLayer : mOffscreenLayers) { - offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { + offscreenLayer->traverse(LayerVector::StateSet::Drawing, [&](Layer* layer) { layer->dumpCallingUidPid(result); }); } @@ -5588,6 +5588,10 @@ void SurfaceFlinger::setInputWindowsFinished() { // --------------------------------------------------------------------------- +void SurfaceFlinger::State::traverse(const LayerVector::Visitor& visitor) const { + layersSortedByZ.traverse(visitor); +} + void SurfaceFlinger::State::traverseInZOrder(const LayerVector::Visitor& visitor) const { layersSortedByZ.traverseInZOrder(stateSet, visitor); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f8980a513f..4c8775da98 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -384,6 +384,7 @@ private: renderengine::ShadowSettings globalShadowSettings; + void traverse(const LayerVector::Visitor& visitor) const; void traverseInZOrder(const LayerVector::Visitor& visitor) const; void traverseInReverseZOrder(const LayerVector::Visitor& visitor) const; }; diff --git a/services/surfaceflinger/TEST_MAPPING b/services/surfaceflinger/TEST_MAPPING index cab33ae379..eed975e9bf 100644 --- a/services/surfaceflinger/TEST_MAPPING +++ b/services/surfaceflinger/TEST_MAPPING @@ -1,7 +1,13 @@ { "presubmit": [ { - "name": "libsurfaceflinger_unittest" + "name": "libsurfaceflinger_unittest", + // TODO(b/148517641): re-enable once this test is fixed + "options": [ + { + "exclude-filter": "FrameTracerTest.*" + } + ] }, { "name": "libcompositionengine_test" diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index 12c98da663..130e99a514 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -40,13 +40,18 @@ namespace impl { status_pull_atom_return_t TimeStats::pullAtomCallback(int32_t atom_tag, pulled_stats_event_list* data, void* cookie) { impl::TimeStats* timeStats = reinterpret_cast<impl::TimeStats*>(cookie); + status_pull_atom_return_t result = STATS_PULL_SKIP; if (atom_tag == android::util::SURFACEFLINGER_STATS_GLOBAL_INFO) { - return timeStats->populateGlobalAtom(data); + result = timeStats->populateGlobalAtom(data); } else if (atom_tag == android::util::SURFACEFLINGER_STATS_LAYER_INFO) { - return timeStats->populateLayerAtom(data); + result = timeStats->populateLayerAtom(data); } - return STATS_PULL_SKIP; + // Enable timestats now. The first full pull for a given build is expected to + // have empty or very little stats, as stats are first enabled after the + // first pull is completed for either the global or layer stats. + timeStats->enable(); + return result; } status_pull_atom_return_t TimeStats::populateGlobalAtom(pulled_stats_event_list* data) { @@ -167,13 +172,19 @@ TimeStats::TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate, } } +TimeStats::~TimeStats() { + std::lock_guard<std::mutex> lock(mMutex); + mStatsDelegate->unregisterStatsPullAtomCallback( + android::util::SURFACEFLINGER_STATS_GLOBAL_INFO); + mStatsDelegate->unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO); +} + void TimeStats::onBootFinished() { - // Temporarily enable TimeStats by default. Telemetry is disabled while - // we move onto statsd, so TimeStats is currently not exercised at all - // during testing without enabling by default. - // TODO: remove this, as we should only be paying this overhead on devices - // where statsd exists. - enable(); + std::lock_guard<std::mutex> lock(mMutex); + mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, + TimeStats::pullAtomCallback, nullptr, this); + mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO, + TimeStats::pullAtomCallback, nullptr, this); } void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) { @@ -735,10 +746,6 @@ void TimeStats::enable() { mEnabled.store(true); mTimeStats.statsStart = static_cast<int64_t>(std::time(0)); mPowerTime.prevTime = systemTime(); - mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, - TimeStats::pullAtomCallback, nullptr, this); - mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO, - TimeStats::pullAtomCallback, nullptr, this); ALOGD("Enabled"); } @@ -751,9 +758,6 @@ void TimeStats::disable() { flushPowerTimeLocked(); mEnabled.store(false); mTimeStats.statsEnd = static_cast<int64_t>(std::time(0)); - mStatsDelegate->unregisterStatsPullAtomCallback( - android::util::SURFACEFLINGER_STATS_GLOBAL_INFO); - mStatsDelegate->unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO); ALOGD("Disabled"); } diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index 71f06af794..67b9d1055c 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -182,6 +182,8 @@ public: std::optional<size_t> maxPulledLayers, std::optional<size_t> maxPulledHistogramBuckets); + ~TimeStats() override; + void onBootFinished() override; void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override; bool isEnabled() override; diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index d046f765e8..7681283f33 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -32,6 +32,7 @@ cc_test { // option to false temporarily. address: true, }, + data: ["libsurfaceflinger_unittest.filter"], srcs: [ ":libsurfaceflinger_sources", "libsurfaceflinger_unittest_main.cpp", diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 9680a17655..dddad92f79 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -1357,7 +1357,8 @@ public: mHardwareDisplaySize.height), compositionState.transform); EXPECT_EQ(TRANSFORM_FLAGS_ROT_0, compositionState.orientation); - EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor); + EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.sourceClip); + EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip); EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.frame); EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.viewport); EXPECT_EQ(false, compositionState.needsFiltering); @@ -1369,7 +1370,8 @@ public: mHardwareDisplaySize.height), compositionState.transform); EXPECT_EQ(TRANSFORM_FLAGS_ROT_90, compositionState.orientation); - EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor); + EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.sourceClip); + EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip); // For 90, the frame and viewport have the hardware display size width and height swapped EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame); EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.viewport); @@ -1382,7 +1384,8 @@ public: mHardwareDisplaySize.height), compositionState.transform); EXPECT_EQ(TRANSFORM_FLAGS_ROT_180, compositionState.orientation); - EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor); + EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.sourceClip); + EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip); EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.frame); EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.viewport); EXPECT_EQ(false, compositionState.needsFiltering); @@ -1394,7 +1397,8 @@ public: mHardwareDisplaySize.height), compositionState.transform); EXPECT_EQ(TRANSFORM_FLAGS_ROT_270, compositionState.orientation); - EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor); + EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.sourceClip); + EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip); // For 270, the frame and viewport have the hardware display size width and height swapped EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame); EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.viewport); diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp index 11ace0576d..922966a70d 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp @@ -34,6 +34,7 @@ namespace android::scheduler { class LayerHistoryTestV2 : public testing::Test { protected: + static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfoV2::FREQUENT_LAYER_WINDOW_SIZE; static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfoV2::HISTORY_SIZE; static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfoV2::MAX_FREQUENT_LAYER_PERIOD_NS; @@ -105,7 +106,10 @@ TEST_F(LayerHistoryTestV2, oneLayer) { for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) { history().record(layer.get(), 0, mTime); ASSERT_EQ(1, history().summarize(mTime).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(mTime)[0].vote); + const auto expectedType = (i + 1 < FREQUENT_LAYER_WINDOW_SIZE) + ? LayerHistory::LayerVoteType::Min + : LayerHistory::LayerVoteType::Max; + EXPECT_EQ(expectedType, history().summarize(mTime)[0].vote); EXPECT_EQ(1, activeLayerCount()); } @@ -129,7 +133,8 @@ TEST_F(LayerHistoryTestV2, oneInvisibleLayer) { history().record(layer.get(), 0, mTime); auto summary = history().summarize(mTime); ASSERT_EQ(1, history().summarize(mTime).size()); - EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(mTime)[0].vote); + // Layer is still considered inactive so we expect to get Min + EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(mTime)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false)); diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 78009b8122..19a58dc6b2 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -495,7 +495,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60 EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); lr.desiredRefreshRate = 45.0f; - EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); lr.desiredRefreshRate = 30.0f; EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); @@ -702,6 +702,32 @@ TEST_F(RefreshRateConfigsTest, testInPolicy) { ASSERT_FALSE(expectedDefaultConfig.inPolicy(50.0f, 59.998f)); } +TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_75HzContent) { + std::vector<RefreshRateConfigs::InputConfig> configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs, + /*currentConfigId=*/HWC_CONFIG_ID_60); + + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + + RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30}; + RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60}; + RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90}; + + auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}}; + auto& lr = layers[0]; + + lr.vote = LayerVoteType::Explicit; + for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) { + lr.desiredRefreshRate = fps; + const auto& refreshRate = refreshRateConfigs->getRefreshRateForContentV2(layers); + printf("%.2fHz chooses %s\n", fps, refreshRate.name.c_str()); + EXPECT_EQ(expected90Config, refreshRate); + } +} + } // namespace } // namespace scheduler } // namespace android diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index 68e6697ce0..f65af77748 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -258,22 +258,25 @@ TEST_F(TimeStatsTest, disabledByDefault) { ASSERT_FALSE(mTimeStats->isEnabled()); } -TEST_F(TimeStatsTest, enabledAfterBoot) { +TEST_F(TimeStatsTest, registersCallbacksAfterBoot) { mTimeStats->onBootFinished(); - ASSERT_TRUE(mTimeStats->isEnabled()); -} - -TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) { - EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); - ASSERT_TRUE(mTimeStats->isEnabled()); EXPECT_THAT(mDelegate->mAtomTags, UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, android::util::SURFACEFLINGER_STATS_LAYER_INFO)); +} +TEST_F(TimeStatsTest, unregistersCallbacksOnDestruction) { EXPECT_CALL(*mDelegate, unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO)); EXPECT_CALL(*mDelegate, unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO)); + mTimeStats.reset(); +} + +TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) { + EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); + ASSERT_TRUE(mTimeStats->isEnabled()); + EXPECT_TRUE(inputCommand(InputCommand::DISABLE, FMT_STRING).empty()); ASSERT_FALSE(mTimeStats->isEnabled()); } diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp index acf852daa1..caac61da29 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp @@ -37,7 +37,7 @@ class FixedRateIdealStubTracker : public VSyncTracker { public: FixedRateIdealStubTracker() : mPeriod{toNs(3ms)} {} - void addVsyncTimestamp(nsecs_t) final {} + bool addVsyncTimestamp(nsecs_t) final { return true; } nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final { auto const floor = timePoint % mPeriod; @@ -60,7 +60,7 @@ class VRRStubTracker : public VSyncTracker { public: VRRStubTracker(nsecs_t period) : mPeriod{period} {} - void addVsyncTimestamp(nsecs_t) final {} + bool addVsyncTimestamp(nsecs_t) final { return true; } nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t time_point) const final { std::lock_guard<decltype(mMutex)> lk(mMutex); diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index 70c92254b2..3ab38e40ef 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -39,9 +39,10 @@ public: MockVSyncTracker(nsecs_t period) : mPeriod{period} { ON_CALL(*this, nextAnticipatedVSyncTimeFrom(_)) .WillByDefault(Invoke(this, &MockVSyncTracker::nextVSyncTime)); + ON_CALL(*this, addVsyncTimestamp(_)).WillByDefault(Return(true)); } - MOCK_METHOD1(addVsyncTimestamp, void(nsecs_t)); + MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t)); MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t)); MOCK_CONST_METHOD0(currentPeriod, nsecs_t()); MOCK_METHOD1(setPeriod, void(nsecs_t)); diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp index ce1fafedc9..1de72b9599 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -35,7 +35,8 @@ namespace android::scheduler { class MockVSyncTracker : public VSyncTracker { public: - MOCK_METHOD1(addVsyncTimestamp, void(nsecs_t)); + MockVSyncTracker() { ON_CALL(*this, addVsyncTimestamp(_)).WillByDefault(Return(true)); } + MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t)); MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t)); MOCK_CONST_METHOD0(currentPeriod, nsecs_t()); MOCK_METHOD1(setPeriod, void(nsecs_t)); @@ -46,7 +47,9 @@ class VSyncTrackerWrapper : public VSyncTracker { public: VSyncTrackerWrapper(std::shared_ptr<VSyncTracker> const& tracker) : mTracker(tracker) {} - void addVsyncTimestamp(nsecs_t timestamp) final { mTracker->addVsyncTimestamp(timestamp); } + bool addVsyncTimestamp(nsecs_t timestamp) final { + return mTracker->addVsyncTimestamp(timestamp); + } nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final { return mTracker->nextAnticipatedVSyncTimeFrom(timePoint); } @@ -239,6 +242,22 @@ TEST_F(VSyncReactorTest, ignoresPresentFencesWhenToldTo) { EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(mDummyTime))); } +TEST_F(VSyncReactorTest, ignoresProperlyAfterAPeriodConfirmation) { + bool periodFlushed = true; + EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(2); + mReactor.setIgnorePresentFences(true); + + nsecs_t const newPeriod = 5000; + mReactor.setPeriod(newPeriod); + + EXPECT_TRUE(mReactor.addResyncSample(0, &periodFlushed)); + EXPECT_FALSE(periodFlushed); + EXPECT_FALSE(mReactor.addResyncSample(newPeriod, &periodFlushed)); + EXPECT_TRUE(periodFlushed); + + EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0))); +} + TEST_F(VSyncReactorTest, queriesTrackerForNextRefreshNow) { nsecs_t const fakeTimestamp = 4839; EXPECT_CALL(*mMockTracker, currentPeriod()).Times(0); @@ -330,6 +349,35 @@ TEST_F(VSyncReactorTest, changingToAThirdPeriodWillWaitForLastPeriod) { EXPECT_TRUE(periodFlushed); } +TEST_F(VSyncReactorTest, reportedBadTimestampFromPredictorWillReactivateHwVSync) { + EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)) + .WillOnce(Return(false)) + .WillOnce(Return(true)) + .WillOnce(Return(true)); + EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0))); + EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0))); + + nsecs_t skewyPeriod = period >> 1; + bool periodFlushed = false; + nsecs_t sampleTime = 0; + EXPECT_TRUE(mReactor.addResyncSample(sampleTime += skewyPeriod, &periodFlushed)); + EXPECT_FALSE(periodFlushed); + EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, &periodFlushed)); + EXPECT_FALSE(periodFlushed); +} + +TEST_F(VSyncReactorTest, reportedBadTimestampFromPredictorWillReactivateHwVSyncPendingFence) { + EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)) + .Times(2) + .WillOnce(Return(false)) + .WillOnce(Return(true)); + + auto fence = generatePendingFence(); + EXPECT_FALSE(mReactor.addPresentFence(fence)); + signalFenceWithTime(fence, period >> 1); + EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0))); +} + TEST_F(VSyncReactorTest, presentFenceAdditionDoesNotInterruptConfirmationProcess) { nsecs_t const newPeriod = 5000; mReactor.setPeriod(newPeriod); diff --git a/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest.filter b/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest.filter new file mode 100644 index 0000000000..8e9c3cf705 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest.filter @@ -0,0 +1,6 @@ +{ + // TODO(b/148517641): re-enable once this test is fixed + "presubmit": { + "filter": "*:-FrameTracerTest.*" + } +} diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 90a73e2d32..a7ec4aed1d 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -164,6 +164,11 @@ const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{ "ro.board.platform", }}; +// LoadDriver returns: +// * 0 when succeed, or +// * -ENOENT when fail to open binary libraries, or +// * -EINVAL when fail to find HAL_MODULE_INFO_SYM_AS_STR or +// HWVULKAN_HARDWARE_MODULE_ID in the library. int LoadDriver(android_namespace_t* library_namespace, const hwvulkan_module_t** module) { ATRACE_CALL(); @@ -221,7 +226,13 @@ int LoadUpdatedDriver(const hwvulkan_module_t** module) { return -ENOENT; android::GraphicsEnv::getInstance().setDriverToLoad( android::GpuStatsInfo::Driver::VULKAN_UPDATED); - return LoadDriver(ns, module); + int result = LoadDriver(ns, module); + if (result != 0) { + LOG_ALWAYS_FATAL( + "couldn't find an updated Vulkan implementation from %s", + android::GraphicsEnv::getInstance().getDriverPath().c_str()); + } + return result; } bool Hal::Open() { |