diff options
127 files changed, 3880 insertions, 9517 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 33dceffa9f..69a1df27b2 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -194,6 +194,8 @@ static const std::string TOMBSTONE_DIR = "/data/tombstones/"; static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_"; static const std::string ANR_DIR = "/data/anr/"; static const std::string ANR_FILE_PREFIX = "anr_"; +static const std::string SHUTDOWN_CHECKPOINTS_DIR = "/data/system/shutdown-checkpoints/"; +static const std::string SHUTDOWN_CHECKPOINTS_FILE_PREFIX = "checkpoints-"; // TODO: temporary variables and functions used during C++ refactoring @@ -1110,6 +1112,16 @@ static void DumpIpTablesAsRoot() { RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"}); } +static void DumpShutdownCheckpoints() { + const bool shutdown_checkpoints_dumped = AddDumps( + ds.shutdown_checkpoints_.begin(), ds.shutdown_checkpoints_.end(), + "SHUTDOWN CHECKPOINTS", false /* add_to_zip */); + if (!shutdown_checkpoints_dumped) { + printf("*** NO SHUTDOWN CHECKPOINTS to dump in %s\n\n", + SHUTDOWN_CHECKPOINTS_DIR.c_str()); + } +} + static void DumpDynamicPartitionInfo() { if (!::android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) { return; @@ -1704,6 +1716,8 @@ Dumpstate::RunStatus Dumpstate::dumpstate() { DoKmsg(); + DumpShutdownCheckpoints(); + DumpIpAddrAndRules(); dump_route_tables(); @@ -1861,6 +1875,8 @@ Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() { if (!PropertiesHelper::IsDryRun()) { ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX); ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX); + ds.shutdown_checkpoints_ = GetDumpFds( + SHUTDOWN_CHECKPOINTS_DIR, SHUTDOWN_CHECKPOINTS_FILE_PREFIX); } ds.AddDir(RECOVERY_DIR, true); @@ -2915,6 +2931,7 @@ void Dumpstate::Cancel() { } tombstone_data_.clear(); anr_data_.clear(); + shutdown_checkpoints_.clear(); // Instead of shutdown the pool, we delete temporary files directly since // shutdown blocking the call. @@ -3202,6 +3219,7 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, tombstone_data_.clear(); anr_data_.clear(); + shutdown_checkpoints_.clear(); return (consent_callback_ != nullptr && consent_callback_->getResult() == UserConsentResult::UNAVAILABLE) diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 5f3acfdc5b..9f894b5079 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -514,6 +514,9 @@ class Dumpstate { // List of open ANR dump files. std::vector<DumpData> anr_data_; + // List of open shutdown checkpoint files. + std::vector<DumpData> shutdown_checkpoints_; + // A thread pool to execute dump tasks simultaneously if the parallel run is enabled. std::unique_ptr<android::os::dumpstate::DumpPool> dump_pool_; diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index b1283eb4a7..bb6639e1a8 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -501,10 +501,6 @@ static int prepare_app_cache_dir(const std::string& parent, const char* name, mo } static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) { - if (!property_get_bool("dalvik.vm.usejitprofiles", false)) { - return true; - } - int32_t uid = multiuser_get_uid(userId, appId); int shared_app_gid = multiuser_get_shared_gid(userId, appId); if (shared_app_gid == -1) { diff --git a/include/android/sensor.h b/include/android/sensor.h index 105f9524c7..085fc270c1 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -601,12 +601,15 @@ typedef struct AHeadingEvent { float accuracy; } AHeadingEvent; +// LINT.IfChange /** * Information that describes a sensor event, refer to * <a href="/reference/android/hardware/SensorEvent">SensorEvent</a> for additional * documentation. + * + * NOTE: changes to this struct has to be backward compatible and reflected in + * sensors_event_t */ -/* NOTE: changes to this struct has to be backward compatible */ typedef struct ASensorEvent { int32_t version; /* sizeof(struct ASensorEvent) */ int32_t sensor; /** The sensor that generates this event */ @@ -651,6 +654,7 @@ typedef struct ASensorEvent { uint32_t flags; int32_t reserved1[3]; } ASensorEvent; +// LINT.ThenChange (hardware/libhardware/include/hardware/sensors.h) struct ASensorManager; /** diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h index 98a18c9560..7457496784 100644 --- a/include/input/DisplayViewport.h +++ b/include/input/DisplayViewport.h @@ -21,6 +21,7 @@ #include <ftl/string.h> #include <gui/constants.h> #include <input/Input.h> +#include <ui/Rotation.h> #include <cinttypes> #include <optional> @@ -29,13 +30,6 @@ using android::base::StringPrintf; namespace android { -enum { - DISPLAY_ORIENTATION_0 = 0, - DISPLAY_ORIENTATION_90 = 1, - DISPLAY_ORIENTATION_180 = 2, - DISPLAY_ORIENTATION_270 = 3 -}; - /** * Describes the different type of viewports supported by input flinger. * Keep in sync with values in InputManagerService.java. @@ -54,7 +48,7 @@ enum class ViewportType : int32_t { */ struct DisplayViewport { int32_t displayId; // -1 if invalid - int32_t orientation; + ui::Rotation orientation; int32_t logicalLeft; int32_t logicalTop; int32_t logicalRight; @@ -74,7 +68,7 @@ struct DisplayViewport { DisplayViewport() : displayId(ADISPLAY_ID_NONE), - orientation(DISPLAY_ORIENTATION_0), + orientation(ui::ROTATION_0), logicalLeft(0), logicalTop(0), logicalRight(0), @@ -111,7 +105,7 @@ struct DisplayViewport { void setNonDisplayViewport(int32_t width, int32_t height) { displayId = ADISPLAY_ID_NONE; - orientation = DISPLAY_ORIENTATION_0; + orientation = ui::ROTATION_0; logicalLeft = 0; logicalTop = 0; logicalRight = width; diff --git a/include/input/Input.h b/include/input/Input.h index d298d817f5..015efdd064 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -577,7 +577,7 @@ public: inline const ui::Transform& getTransform() const { return mTransform; } - int getSurfaceRotation() const; + std::optional<ui::Rotation> getSurfaceRotation() const; inline float getXPrecision() const { return mXPrecision; } diff --git a/include/input/TouchVideoFrame.h b/include/input/TouchVideoFrame.h index a616a95ab1..1e4f6e7a4c 100644 --- a/include/input/TouchVideoFrame.h +++ b/include/input/TouchVideoFrame.h @@ -16,6 +16,8 @@ #pragma once +#include <ui/Rotation.h> + #include <stdint.h> #include <sys/time.h> #include <vector> @@ -58,7 +60,7 @@ public: * Rotate the video frame. * The rotation value is an enum from ui/Rotation.h */ - void rotate(int32_t orientation); + void rotate(ui::Rotation orientation); private: uint32_t mHeight; diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 4b07608a79..ee081c485c 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -614,11 +614,14 @@ status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) { if (status_t status = readInt32(&fdIndex); status != OK) { return status; } - const auto& oldFd = otherRpcFields->mFds->at(fdIndex); + int oldFd = toRawFd(otherRpcFields->mFds->at(fdIndex)); // To match kernel binder behavior, we always dup, even if the // FD was unowned in the source parcel. - rpcFields->mFds->emplace_back( - base::unique_fd(fcntl(toRawFd(oldFd), F_DUPFD_CLOEXEC, 0))); + int newFd = -1; + if (status_t status = dupFileDescriptor(oldFd, &newFd); status != OK) { + ALOGW("Failed to duplicate file descriptor %d: %s", oldFd, strerror(-status)); + } + rpcFields->mFds->emplace_back(base::unique_fd(newFd)); // Fixup the index in the data. mDataPos = newDataPos + 4; if (status_t status = writeInt32(rpcFields->mFds->size() - 1); status != OK) { diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h index 81975e7b63..9949de2aac 100644 --- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h +++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h @@ -196,6 +196,10 @@ class BnCInterface : public INTERFACE { bool isRemote() override final { return false; } + static std::string makeServiceName(std::string_view instance) { + return INTERFACE::descriptor + ("/" + std::string(instance)); + } + protected: /** * This function should only be called by asBinder. Otherwise, there is a possibility of diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp index 738d16ac66..afd414a7cb 100644 --- a/libs/binder/rust/Android.bp +++ b/libs/binder/rust/Android.bp @@ -17,7 +17,6 @@ rust_library { rustlibs: [ "libbinder_ndk_sys", "libdowncast_rs", - "liblazy_static", "liblibc", ], host_supported: true, @@ -160,7 +159,6 @@ rust_test { rustlibs: [ "libbinder_ndk_sys", "libdowncast_rs", - "liblazy_static", "liblibc", ], } diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs index dee05d07cf..6f686fbd93 100644 --- a/libs/binder/rust/src/native.rs +++ b/libs/binder/rust/src/native.rs @@ -22,7 +22,6 @@ use crate::parcel::{BorrowedParcel, Serialize}; use crate::proxy::SpIBinder; use crate::sys; -use lazy_static::lazy_static; use std::convert::TryFrom; use std::ffi::{c_void, CStr, CString}; use std::fs::File; @@ -508,10 +507,8 @@ pub struct LazyServiceGuard { _private: (), } -lazy_static! { - // Count of how many LazyServiceGuard objects are in existence. - static ref GUARD_COUNT: Mutex<u64> = Mutex::new(0); -} +// Count of how many LazyServiceGuard objects are in existence. +static GUARD_COUNT: Mutex<u64> = Mutex::new(0); impl LazyServiceGuard { /// Create a new LazyServiceGuard to prevent the service manager prematurely killing this diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 68a827bb3e..02aa45f916 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -913,6 +913,33 @@ TEST_P(BinderRpc, SendTooManyFiles) { EXPECT_EQ(status.transactionError(), BAD_VALUE) << status; } +TEST_P(BinderRpc, AppendInvalidFd) { + auto proc = createRpcTestSocketServerProcess({ + .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX, + .serverSupportedFileDescriptorTransportModes = + {RpcSession::FileDescriptorTransportMode::UNIX}, + }); + + int badFd = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 0); + ASSERT_NE(badFd, -1); + + // Close the file descriptor so it becomes invalid for dup + close(badFd); + + Parcel p1; + p1.markForBinder(proc.rootBinder); + p1.writeInt32(3); + EXPECT_EQ(OK, p1.writeFileDescriptor(badFd, false)); + + Parcel pRaw; + pRaw.markForBinder(proc.rootBinder); + EXPECT_EQ(OK, pRaw.appendFrom(&p1, 0, p1.dataSize())); + + pRaw.setDataPosition(0); + EXPECT_EQ(3, pRaw.readInt32()); + ASSERT_EQ(-1, pRaw.readFileDescriptor()); +} + TEST_P(BinderRpc, WorksWithLibbinderNdkPing) { if constexpr (!kEnableSharedLibs) { GTEST_SKIP() << "Test disabled because Binder was built as a static library"; diff --git a/libs/binder/trusty/include/log/log.h b/libs/binder/trusty/include/log/log.h index bf877a3179..d88d18a7be 100644 --- a/libs/binder/trusty/include/log/log.h +++ b/libs/binder/trusty/include/log/log.h @@ -120,3 +120,7 @@ static inline void __ignore_va_args__(...) {} do { \ TLOGE("android_errorWriteLog: tag:%x subTag:%s\n", tag, subTag); \ } while (0) + +extern "C" inline void __assert(const char* file, int line, const char* str) { + LOG_ALWAYS_FATAL("%s:%d: assertion \"%s\" failed", file, line, str); +} diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index c4fb1cf408..edb18a86ee 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1108,9 +1108,12 @@ void Surface::applyGrallocMetadataLocked( ATRACE_CALL(); auto& mapper = GraphicBufferMapper::get(); mapper.setDataspace(buffer->handle, static_cast<ui::Dataspace>(queueBufferInput.dataSpace)); - mapper.setSmpte2086(buffer->handle, queueBufferInput.getHdrMetadata().getSmpte2086()); - mapper.setCta861_3(buffer->handle, queueBufferInput.getHdrMetadata().getCta8613()); - mapper.setSmpte2094_40(buffer->handle, queueBufferInput.getHdrMetadata().getHdr10Plus()); + if (mHdrMetadataIsSet & HdrMetadata::SMPTE2086) + mapper.setSmpte2086(buffer->handle, queueBufferInput.getHdrMetadata().getSmpte2086()); + if (mHdrMetadataIsSet & HdrMetadata::CTA861_3) + mapper.setCta861_3(buffer->handle, queueBufferInput.getHdrMetadata().getCta8613()); + if (mHdrMetadataIsSet & HdrMetadata::HDR10PLUS) + mapper.setSmpte2094_40(buffer->handle, queueBufferInput.getHdrMetadata().getHdr10Plus()); } void Surface::onBufferQueuedLocked(int slot, sp<Fence> fence, @@ -2252,6 +2255,7 @@ int Surface::setBuffersDataSpace(Dataspace dataSpace) int Surface::setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata) { ALOGV("Surface::setBuffersSmpte2086Metadata"); Mutex::Autolock lock(mMutex); + mHdrMetadataIsSet |= HdrMetadata::SMPTE2086; if (metadata) { mHdrMetadata.smpte2086 = *metadata; mHdrMetadata.validTypes |= HdrMetadata::SMPTE2086; @@ -2264,6 +2268,7 @@ int Surface::setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metad int Surface::setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata) { ALOGV("Surface::setBuffersCta8613Metadata"); Mutex::Autolock lock(mMutex); + mHdrMetadataIsSet |= HdrMetadata::CTA861_3; if (metadata) { mHdrMetadata.cta8613 = *metadata; mHdrMetadata.validTypes |= HdrMetadata::CTA861_3; @@ -2276,6 +2281,7 @@ int Surface::setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata int Surface::setBuffersHdr10PlusMetadata(const size_t size, const uint8_t* metadata) { ALOGV("Surface::setBuffersBlobMetadata"); Mutex::Autolock lock(mMutex); + mHdrMetadataIsSet |= HdrMetadata::HDR10PLUS; if (size > 0) { mHdrMetadata.hdr10plus.assign(metadata, metadata + size); mHdrMetadata.validTypes |= HdrMetadata::HDR10PLUS; diff --git a/libs/gui/fuzzer/Android.bp b/libs/gui/fuzzer/Android.bp index 1c61d6bb8b..82e1b5ae4d 100644 --- a/libs/gui/fuzzer/Android.bp +++ b/libs/gui/fuzzer/Android.bp @@ -62,7 +62,6 @@ cc_defaults { "libutils", "libnativewindow", "libvndksupport", - "libbufferhubqueue", ], header_libs: [ "libdvr_headers", diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 7aec0bf09d..b9ccdc9124 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -486,6 +486,11 @@ protected: // queue operation. There is no HDR metadata by default. HdrMetadata mHdrMetadata; + // mHdrMetadataIsSet is a bitfield to track which HDR metadata has been set. + // Prevent Surface from resetting HDR metadata that was set on a bufer when + // HDR metadata is not set on this Surface. + uint32_t mHdrMetadataIsSet{0}; + // mCrop is the crop rectangle that will be used for the next buffer // that gets queued. It is set by calling setCrop. Rect mCrop; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 3685f54a53..9e8ebf30c5 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -21,6 +21,7 @@ #include <cutils/compiler.h> #include <inttypes.h> #include <string.h> +#include <optional> #include <android-base/file.h> #include <android-base/logging.h> @@ -552,21 +553,21 @@ void MotionEvent::addSample( &pointerCoords[getPointerCount()]); } -int MotionEvent::getSurfaceRotation() const { +std::optional<ui::Rotation> MotionEvent::getSurfaceRotation() const { // The surface rotation is the rotation from the window's coordinate space to that of the // display. Since the event's transform takes display space coordinates to window space, the // returned surface rotation is the inverse of the rotation for the surface. switch (mTransform.getOrientation()) { case ui::Transform::ROT_0: - return DISPLAY_ORIENTATION_0; + return ui::ROTATION_0; case ui::Transform::ROT_90: - return DISPLAY_ORIENTATION_270; + return ui::ROTATION_270; case ui::Transform::ROT_180: - return DISPLAY_ORIENTATION_180; + return ui::ROTATION_180; case ui::Transform::ROT_270: - return DISPLAY_ORIENTATION_90; + return ui::ROTATION_90; default: - return -1; + return std::nullopt; } } diff --git a/libs/input/TouchVideoFrame.cpp b/libs/input/TouchVideoFrame.cpp index c62e0985f1..c9393f4451 100644 --- a/libs/input/TouchVideoFrame.cpp +++ b/libs/input/TouchVideoFrame.cpp @@ -40,17 +40,20 @@ const std::vector<int16_t>& TouchVideoFrame::getData() const { return mData; } const struct timeval& TouchVideoFrame::getTimestamp() const { return mTimestamp; } -void TouchVideoFrame::rotate(int32_t orientation) { +void TouchVideoFrame::rotate(ui::Rotation orientation) { switch (orientation) { - case DISPLAY_ORIENTATION_90: + case ui::ROTATION_90: rotateQuarterTurn(false /*clockwise*/); break; - case DISPLAY_ORIENTATION_180: + case ui::ROTATION_180: rotate180(); break; - case DISPLAY_ORIENTATION_270: + case ui::ROTATION_270: rotateQuarterTurn(true /*clockwise*/); break; + case ui::ROTATION_0: + // No need to rotate if there's no rotation. + break; } } diff --git a/libs/input/tests/TouchVideoFrame_test.cpp b/libs/input/tests/TouchVideoFrame_test.cpp index 654b236bda..081a995a6f 100644 --- a/libs/input/tests/TouchVideoFrame_test.cpp +++ b/libs/input/tests/TouchVideoFrame_test.cpp @@ -73,38 +73,38 @@ TEST(TouchVideoFrame, Equality) { TEST(TouchVideoFrame, Rotate90_0x0) { TouchVideoFrame frame(0, 0, {}, TIMESTAMP); TouchVideoFrame frameRotated(0, 0, {}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_90); + frame.rotate(ui::ROTATION_90); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate90_1x1) { TouchVideoFrame frame(1, 1, {1}, TIMESTAMP); TouchVideoFrame frameRotated(1, 1, {1}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_90); + frame.rotate(ui::ROTATION_90); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate90_2x2) { TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP); TouchVideoFrame frameRotated(2, 2, {2, 4, 1, 3}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_90); + frame.rotate(ui::ROTATION_90); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate90_3x2) { TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP); TouchVideoFrame frameRotated(2, 3, {2, 4, 6, 1, 3, 5}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_90); + frame.rotate(ui::ROTATION_90); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate90_3x2_4times) { TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP); TouchVideoFrame frameOriginal(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_90); - frame.rotate(DISPLAY_ORIENTATION_90); - frame.rotate(DISPLAY_ORIENTATION_90); - frame.rotate(DISPLAY_ORIENTATION_90); + frame.rotate(ui::ROTATION_90); + frame.rotate(ui::ROTATION_90); + frame.rotate(ui::ROTATION_90); + frame.rotate(ui::ROTATION_90); ASSERT_EQ(frame, frameOriginal); } @@ -113,43 +113,43 @@ TEST(TouchVideoFrame, Rotate90_3x2_4times) { TEST(TouchVideoFrame, Rotate180_0x0) { TouchVideoFrame frame(0, 0, {}, TIMESTAMP); TouchVideoFrame frameRotated(0, 0, {}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_180); + frame.rotate(ui::ROTATION_180); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate180_1x1) { TouchVideoFrame frame(1, 1, {1}, TIMESTAMP); TouchVideoFrame frameRotated(1, 1, {1}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_180); + frame.rotate(ui::ROTATION_180); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate180_2x2) { TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP); TouchVideoFrame frameRotated(2, 2, {4, 3, 2, 1}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_180); + frame.rotate(ui::ROTATION_180); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate180_3x2) { TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP); TouchVideoFrame frameRotated(3, 2, {6, 5, 4, 3, 2, 1}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_180); + frame.rotate(ui::ROTATION_180); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate180_3x2_2times) { TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP); TouchVideoFrame frameOriginal(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_180); - frame.rotate(DISPLAY_ORIENTATION_180); + frame.rotate(ui::ROTATION_180); + frame.rotate(ui::ROTATION_180); ASSERT_EQ(frame, frameOriginal); } TEST(TouchVideoFrame, Rotate180_3x3) { TouchVideoFrame frame(3, 3, {1, 2, 3, 4, 5, 6, 7, 8, 9}, TIMESTAMP); TouchVideoFrame frameRotated(3, 3, {9, 8, 7, 6, 5, 4, 3, 2, 1}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_180); + frame.rotate(ui::ROTATION_180); ASSERT_EQ(frame, frameRotated); } @@ -158,38 +158,38 @@ TEST(TouchVideoFrame, Rotate180_3x3) { TEST(TouchVideoFrame, Rotate270_0x0) { TouchVideoFrame frame(0, 0, {}, TIMESTAMP); TouchVideoFrame frameRotated(0, 0, {}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_270); + frame.rotate(ui::ROTATION_270); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate270_1x1) { TouchVideoFrame frame(1, 1, {1}, TIMESTAMP); TouchVideoFrame frameRotated(1, 1, {1}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_270); + frame.rotate(ui::ROTATION_270); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate270_2x2) { TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP); TouchVideoFrame frameRotated(2, 2, {3, 1, 4, 2}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_270); + frame.rotate(ui::ROTATION_270); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate270_3x2) { TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP); TouchVideoFrame frameRotated(2, 3, {5, 3, 1, 6, 4, 2}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_270); + frame.rotate(ui::ROTATION_270); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate270_3x2_4times) { TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP); TouchVideoFrame frameOriginal(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP); - frame.rotate(DISPLAY_ORIENTATION_270); - frame.rotate(DISPLAY_ORIENTATION_270); - frame.rotate(DISPLAY_ORIENTATION_270); - frame.rotate(DISPLAY_ORIENTATION_270); + frame.rotate(ui::ROTATION_270); + frame.rotate(ui::ROTATION_270); + frame.rotate(ui::ROTATION_270); + frame.rotate(ui::ROTATION_270); ASSERT_EQ(frame, frameOriginal); } diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h index fe7a651ffb..0fb64d3c15 100644 --- a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h +++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h @@ -27,6 +27,8 @@ namespace android::recoverymap { // Framework const float kSdrWhiteNits = 100.0f; +const float kHlgMaxNits = 1000.0f; +const float kPqMaxNits = 10000.0f; struct Color { union { @@ -113,9 +115,14 @@ inline Color operator/(const Color& lhs, const float rhs) { //////////////////////////////////////////////////////////////////////////////// // sRGB transformations +// NOTE: sRGB has the same color primaries as BT.709, but different transfer +// function. For this reason, all sRGB transformations here apply to BT.709, +// except for those concerning transfer functions. /* * Calculate the luminance of a linear RGB sRGB pixel, according to IEC 61966-2-1. + * + * [0.0, 1.0] range in and out. */ float srgbLuminance(Color e); @@ -142,7 +149,9 @@ Color srgbInvOetf(Color e_gamma); // Display-P3 transformations /* - * Calculated the luminance of a linear RGB P3 pixel, according to EG 432-1. + * Calculated the luminance of a linear RGB P3 pixel, according to SMPTE EG 432-1. + * + * [0.0, 1.0] range in and out. */ float p3Luminance(Color e); @@ -152,6 +161,8 @@ float p3Luminance(Color e); /* * Calculate the luminance of a linear RGB BT.2100 pixel. + * + * [0.0, 1.0] range in and out. */ float bt2100Luminance(Color e); @@ -166,23 +177,35 @@ Color bt2100RgbToYuv(Color e_gamma); Color bt2100YuvToRgb(Color e_gamma); /* - * Convert from scene luminance in nits to HLG. + * Convert from scene luminance to HLG. + * + * [0.0, 1.0] range in and out. */ +float hlgOetf(float e); Color hlgOetf(Color e); /* - * Convert from HLG to scene luminance in nits. + * Convert from HLG to scene luminance. + * + * [0.0, 1.0] range in and out. */ +float hlgInvOetf(float e_gamma); Color hlgInvOetf(Color e_gamma); /* - * Convert from scene luminance in nits to PQ. + * Convert from scene luminance to PQ. + * + * [0.0, 1.0] range in and out. */ +float pqOetf(float e); Color pqOetf(Color e); /* * Convert from PQ to scene luminance in nits. + * + * [0.0, 1.0] range in and out. */ +float pqInvOetf(float e_gamma); Color pqInvOetf(Color e_gamma); @@ -230,34 +253,36 @@ uint8_t encodeRecovery(float y_sdr, float y_hdr, float hdr_ratio); Color applyRecovery(Color e, float recovery, float hdr_ratio); /* - * Helper for sampling from images. + * Helper for sampling from YUV 420 images. */ Color getYuv420Pixel(jr_uncompressed_ptr image, size_t x, size_t y); /* - * Helper for sampling from images. + * Helper for sampling from P010 images. + * + * Expect narrow-range image data for P010. */ Color getP010Pixel(jr_uncompressed_ptr image, size_t x, size_t y); /* - * Sample the recovery value for the map from a given x,y coordinate on a scale - * that is map scale factor larger than the map size. + * Sample the image at the provided location, with a weighting based on nearby + * pixels and the map scale factor. */ -float sampleMap(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y); +Color sampleYuv420(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y); /* - * Sample the image Y value at the provided location, with a weighting based on nearby pixels - * and the map scale factor. + * Sample the image at the provided location, with a weighting based on nearby + * pixels and the map scale factor. * * Expect narrow-range image data for P010. */ -Color sampleYuv420(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y); +Color sampleP010(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y); /* - * Sample the image Y value at the provided location, with a weighting based on nearby pixels - * and the map scale factor. Assumes narrow-range image data for P010. + * Sample the recovery value for the map from a given x,y coordinate on a scale + * that is map scale factor larger than the map size. */ -Color sampleP010(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y); +float sampleMap(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y); /* * Convert from Color to RGBA1010102. diff --git a/libs/jpegrecoverymap/recoverymap.cpp b/libs/jpegrecoverymap/recoverymap.cpp index 4a209ec381..f7f36223d4 100644 --- a/libs/jpegrecoverymap/recoverymap.cpp +++ b/libs/jpegrecoverymap/recoverymap.cpp @@ -390,12 +390,15 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4 map_data.reset(reinterpret_cast<uint8_t*>(dest->data)); ColorTransformFn hdrInvOetf = nullptr; + float hdr_white_nits = 0.0f; switch (metadata->transferFunction) { case JPEGR_TF_HLG: hdrInvOetf = hlgInvOetf; + hdr_white_nits = kHlgMaxNits; break; case JPEGR_TF_PQ: hdrInvOetf = pqInvOetf; + hdr_white_nits = kPqMaxNits; break; } @@ -426,7 +429,7 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4 Color hdr_rgb_gamma = bt2100YuvToRgb(hdr_yuv_gamma); Color hdr_rgb = hdrInvOetf(hdr_rgb_gamma); hdr_rgb = hdrGamutConversionFn(hdr_rgb); - float hdr_y_nits = luminanceFn(hdr_rgb); + float hdr_y_nits = luminanceFn(hdr_rgb) * hdr_white_nits; hdr_y_nits_avg += hdr_y_nits; if (hdr_y_nits > hdr_y_nits_max) { @@ -448,13 +451,13 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4 kMapDimensionScaleFactor, x, y); Color sdr_rgb_gamma = srgbYuvToRgb(sdr_yuv_gamma); Color sdr_rgb = srgbInvOetf(sdr_rgb_gamma); - float sdr_y_nits = luminanceFn(sdr_rgb); + float sdr_y_nits = luminanceFn(sdr_rgb) * kSdrWhiteNits; Color hdr_yuv_gamma = sampleP010(uncompressed_p010_image, kMapDimensionScaleFactor, x, y); Color hdr_rgb_gamma = bt2100YuvToRgb(hdr_yuv_gamma); Color hdr_rgb = hdrInvOetf(hdr_rgb_gamma); hdr_rgb = hdrGamutConversionFn(hdr_rgb); - float hdr_y_nits = luminanceFn(hdr_rgb); + float hdr_y_nits = luminanceFn(hdr_rgb) * hdr_white_nits; size_t pixel_idx = x + y * map_width; reinterpret_cast<uint8_t*>(dest->data)[pixel_idx] = diff --git a/libs/jpegrecoverymap/recoverymapmath.cpp b/libs/jpegrecoverymap/recoverymapmath.cpp index 6dcbca3707..e838f43b58 100644 --- a/libs/jpegrecoverymap/recoverymapmath.cpp +++ b/libs/jpegrecoverymap/recoverymapmath.cpp @@ -23,12 +23,14 @@ namespace android::recoverymap { //////////////////////////////////////////////////////////////////////////////// // sRGB transformations -static const float kSrgbR = 0.299f, kSrgbG = 0.587f, kSrgbB = 0.114f; +// See IEC 61966-2-1, Equation F.7. +static const float kSrgbR = 0.2126f, kSrgbG = 0.7152f, kSrgbB = 0.0722f; float srgbLuminance(Color e) { return kSrgbR * e.r + kSrgbG * e.g + kSrgbB * e.b; } +// See ECMA TR/98, Section 7. static const float kSrgbRCr = 1.402f, kSrgbGCb = 0.34414f, kSrgbGCr = 0.71414f, kSrgbBCb = 1.772f; Color srgbYuvToRgb(Color e_gamma) { @@ -37,15 +39,18 @@ Color srgbYuvToRgb(Color e_gamma) { e_gamma.y + kSrgbBCb * e_gamma.u }}}; } +// See ECMA TR/98, Section 7. +static const float kSrgbYR = 0.299f, kSrgbYG = 0.587f, kSrgbYB = 0.114f; static const float kSrgbUR = -0.1687f, kSrgbUG = -0.3313f, kSrgbUB = 0.5f; static const float kSrgbVR = 0.5f, kSrgbVG = -0.4187f, kSrgbVB = -0.0813f; Color srgbRgbToYuv(Color e_gamma) { - return {{{ kSrgbR * e_gamma.r + kSrgbG * e_gamma.g + kSrgbB * e_gamma.b, + return {{{ kSrgbYR * e_gamma.r + kSrgbYG * e_gamma.g + kSrgbYB * e_gamma.b, kSrgbUR * e_gamma.r + kSrgbUG * e_gamma.g + kSrgbUB * e_gamma.b, kSrgbVR * e_gamma.r + kSrgbVG * e_gamma.g + kSrgbVB * e_gamma.b }}}; } +// See IEC 61966-2-1, Equations F.5 and F.6. float srgbInvOetf(float e_gamma) { if (e_gamma <= 0.04045f) { return e_gamma / 12.92f; @@ -64,7 +69,8 @@ Color srgbInvOetf(Color e_gamma) { //////////////////////////////////////////////////////////////////////////////// // Display-P3 transformations -static const float kP3R = 0.22897f, kP3G = 0.69174f, kP3B = 0.07929f; +// See SMPTE EG 432-1, Table 7-2. +static const float kP3R = 0.20949f, kP3G = 0.72160f, kP3B = 0.06891f; float p3Luminance(Color e) { return kP3R * e.r + kP3G * e.g + kP3B * e.b; @@ -74,12 +80,14 @@ float p3Luminance(Color e) { //////////////////////////////////////////////////////////////////////////////// // BT.2100 transformations - according to ITU-R BT.2100-2 +// See ITU-R BT.2100-2, Table 5, HLG Reference OOTF static const float kBt2100R = 0.2627f, kBt2100G = 0.6780f, kBt2100B = 0.0593f; float bt2100Luminance(Color e) { return kBt2100R * e.r + kBt2100G * e.g + kBt2100B * e.b; } +// See ITU-R BT.2100-2, Table 6, Derivation of colour difference signals. static const float kBt2100Cb = 1.8814f, kBt2100Cr = 1.4746f; Color bt2100RgbToYuv(Color e_gamma) { @@ -89,9 +97,9 @@ Color bt2100RgbToYuv(Color e_gamma) { (e_gamma.r - y_gamma) / kBt2100Cr }}}; } -// Derived from the reverse of bt2100RgbToYuv. The derivation for R and B are -// pretty straight forward; we just reverse the formulas for U and V above. But -// deriving the formula for G is a bit more complicated: +// Derived by inversing bt2100RgbToYuv. The derivation for R and B are pretty +// straight forward; we just invert the formulas for U and V above. But deriving +// the formula for G is a bit more complicated: // // Start with equation for luminance: // Y = kBt2100R * R + kBt2100G * G + kBt2100B * B @@ -119,9 +127,10 @@ Color bt2100YuvToRgb(Color e_gamma) { e_gamma.y + kBt2100Cb * e_gamma.u }}}; } +// See ITU-R BT.2100-2, Table 5, HLG Reference OETF. static const float kHlgA = 0.17883277f, kHlgB = 0.28466892f, kHlgC = 0.55991073; -static float hlgOetf(float e) { +float hlgOetf(float e) { if (e <= 1.0f/12.0f) { return sqrt(3.0f * e); } else { @@ -133,7 +142,8 @@ Color hlgOetf(Color e) { return {{{ hlgOetf(e.r), hlgOetf(e.g), hlgOetf(e.b) }}}; } -static float hlgInvOetf(float e_gamma) { +// See ITU-R BT.2100-2, Table 5, HLG Reference EOTF. +float hlgInvOetf(float e_gamma) { if (e_gamma <= 0.5f) { return pow(e_gamma, 2.0f) / 3.0f; } else { @@ -147,13 +157,14 @@ Color hlgInvOetf(Color e_gamma) { hlgInvOetf(e_gamma.b) }}}; } +// See ITU-R BT.2100-2, Table 4, Reference PQ OETF. static const float kPqM1 = 2610.0f / 16384.0f, kPqM2 = 2523.0f / 4096.0f * 128.0f; static const float kPqC1 = 3424.0f / 4096.0f, kPqC2 = 2413.0f / 4096.0f * 32.0f, kPqC3 = 2392.0f / 4096.0f * 32.0f; -static float pqOetf(float e) { - if (e < 0.0f) e = 0.0f; - return pow((kPqC1 + kPqC2 * pow(e / 10000.0f, kPqM1)) / (1 + kPqC3 * pow(e / 10000.0f, kPqM1)), +float pqOetf(float e) { + if (e <= 0.0f) return 0.0f; + return pow((kPqC1 + kPqC2 * pow(e, kPqM1)) / (1 + kPqC3 * pow(e, kPqM1)), kPqM2); } @@ -161,10 +172,18 @@ Color pqOetf(Color e) { return {{{ pqOetf(e.r), pqOetf(e.g), pqOetf(e.b) }}}; } -static float pqInvOetf(float e_gamma) { - static const float kPqInvOetfCoef = log2(-(pow(kPqM1, 1.0f / kPqM2) - kPqC1) - / (kPqC3 * pow(kPqM1, 1.0f / kPqM2) - kPqC2)); - return kPqInvOetfCoef / log2(e_gamma * 10000.0f); +// Derived from the inverse of the Reference PQ OETF. +static const float kPqInvA = 128.0f, kPqInvB = 107.0f, kPqInvC = 2413.0f, kPqInvD = 2392.0f, + kPqInvE = 6.2773946361f, kPqInvF = 0.0126833f; + +float pqInvOetf(float e_gamma) { + // This equation blows up if e_gamma is 0.0, and checking on <= 0.0 doesn't + // always catch 0.0. So, check on 0.0001, since anything this small will + // effectively be crushed to zero anyways. + if (e_gamma <= 0.0001f) return 0.0f; + return pow((kPqInvA * pow(e_gamma, kPqInvF) - kPqInvB) + / (kPqInvC - kPqInvD * pow(e_gamma, kPqInvF)), + kPqInvE); } Color pqInvOetf(Color e_gamma) { @@ -217,7 +236,7 @@ Color bt2100ToP3(Color e) { // TODO: confirm we always want to convert like this before calculating // luminance. ColorTransformFn getHdrConversionFn(jpegr_color_gamut sdr_gamut, jpegr_color_gamut hdr_gamut) { - switch (sdr_gamut) { + switch (sdr_gamut) { case JPEGR_COLORGAMUT_BT709: switch (hdr_gamut) { case JPEGR_COLORGAMUT_BT709: @@ -269,13 +288,14 @@ uint8_t encodeRecovery(float y_sdr, float y_hdr, float hdr_ratio) { gain = y_hdr / y_sdr; } - if (gain < -hdr_ratio) gain = -hdr_ratio; + if (gain < (1.0f / hdr_ratio)) gain = 1.0f / hdr_ratio; if (gain > hdr_ratio) gain = hdr_ratio; return static_cast<uint8_t>(log2(gain) / log2(hdr_ratio) * 127.5f + 127.5f); } static float applyRecovery(float e, float recovery, float hdr_ratio) { + if (e <= 0.0f) return 0.0f; return exp2(log2(e) + recovery * log2(hdr_ratio)); } @@ -285,45 +305,6 @@ Color applyRecovery(Color e, float recovery, float hdr_ratio) { applyRecovery(e.b, recovery, hdr_ratio) }}}; } -// TODO: do we need something more clever for filtering either the map or images -// to generate the map? - -static size_t clamp(const size_t& val, const size_t& low, const size_t& high) { - return val < low ? low : (high < val ? high : val); -} - -static float mapUintToFloat(uint8_t map_uint) { - return (static_cast<float>(map_uint) - 127.5f) / 127.5f; -} - -float sampleMap(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y) { - float x_map = static_cast<float>(x) / static_cast<float>(map_scale_factor); - float y_map = static_cast<float>(y) / static_cast<float>(map_scale_factor); - - size_t x_lower = static_cast<size_t>(floor(x_map)); - size_t x_upper = x_lower + 1; - size_t y_lower = static_cast<size_t>(floor(y_map)); - size_t y_upper = y_lower + 1; - - x_lower = clamp(x_lower, 0, map->width - 1); - x_upper = clamp(x_upper, 0, map->width - 1); - y_lower = clamp(y_lower, 0, map->height - 1); - y_upper = clamp(y_upper, 0, map->height - 1); - - float x_influence = x_map - static_cast<float>(x_lower); - float y_influence = y_map - static_cast<float>(y_lower); - - float e1 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_lower + y_lower * map->width]); - float e2 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_lower + y_upper * map->width]); - float e3 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_upper + y_lower * map->width]); - float e4 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_upper + y_upper * map->width]); - - return e1 * (x_influence + y_influence) / 2.0f - + e2 * (x_influence + 1.0f - y_influence) / 2.0f - + e3 * (1.0f - x_influence + y_influence) / 2.0f - + e4 * (1.0f - x_influence + 1.0f - y_influence) / 2.0f; -} - Color getYuv420Pixel(jr_uncompressed_ptr image, size_t x, size_t y) { size_t pixel_count = image->width * image->height; @@ -382,6 +363,70 @@ Color sampleP010(jr_uncompressed_ptr image, size_t map_scale_factor, size_t x, s return samplePixels(image, map_scale_factor, x, y, getP010Pixel); } +// TODO: do we need something more clever for filtering either the map or images +// to generate the map? + +static size_t clamp(const size_t& val, const size_t& low, const size_t& high) { + return val < low ? low : (high < val ? high : val); +} + +static float mapUintToFloat(uint8_t map_uint) { + return (static_cast<float>(map_uint) - 127.5f) / 127.5f; +} + +static float pythDistance(float x_diff, float y_diff) { + return sqrt(pow(x_diff, 2.0f) + pow(y_diff, 2.0f)); +} + +float sampleMap(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y) { + float x_map = static_cast<float>(x) / static_cast<float>(map_scale_factor); + float y_map = static_cast<float>(y) / static_cast<float>(map_scale_factor); + + size_t x_lower = static_cast<size_t>(floor(x_map)); + size_t x_upper = x_lower + 1; + size_t y_lower = static_cast<size_t>(floor(y_map)); + size_t y_upper = y_lower + 1; + + x_lower = clamp(x_lower, 0, map->width - 1); + x_upper = clamp(x_upper, 0, map->width - 1); + y_lower = clamp(y_lower, 0, map->height - 1); + y_upper = clamp(y_upper, 0, map->height - 1); + + // Use Shepard's method for inverse distance weighting. For more information: + // en.wikipedia.org/wiki/Inverse_distance_weighting#Shepard's_method + + float e1 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_lower + y_lower * map->width]); + float e1_dist = pythDistance(x_map - static_cast<float>(x_lower), + y_map - static_cast<float>(y_lower)); + if (e1_dist == 0.0f) return e1; + + float e2 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_lower + y_upper * map->width]); + float e2_dist = pythDistance(x_map - static_cast<float>(x_lower), + y_map - static_cast<float>(y_upper)); + if (e2_dist == 0.0f) return e2; + + float e3 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_upper + y_lower * map->width]); + float e3_dist = pythDistance(x_map - static_cast<float>(x_upper), + y_map - static_cast<float>(y_lower)); + if (e3_dist == 0.0f) return e3; + + float e4 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_upper + y_upper * map->width]); + float e4_dist = pythDistance(x_map - static_cast<float>(x_upper), + y_map - static_cast<float>(y_upper)); + if (e4_dist == 0.0f) return e2; + + float e1_weight = 1.0f / e1_dist; + float e2_weight = 1.0f / e2_dist; + float e3_weight = 1.0f / e3_dist; + float e4_weight = 1.0f / e4_dist; + float total_weight = e1_weight + e2_weight + e3_weight + e4_weight; + + return e1 * (e1_weight / total_weight) + + e2 * (e2_weight / total_weight) + + e3 * (e3_weight / total_weight) + + e4 * (e4_weight / total_weight); +} + uint32_t colorToRgba1010102(Color e_gamma) { return (0x3ff & static_cast<uint32_t>(e_gamma.r * 1023.0f)) | ((0x3ff & static_cast<uint32_t>(e_gamma.g * 1023.0f)) << 10) diff --git a/libs/jpegrecoverymap/tests/Android.bp b/libs/jpegrecoverymap/tests/Android.bp index 8f37954841..b509478e73 100644 --- a/libs/jpegrecoverymap/tests/Android.bp +++ b/libs/jpegrecoverymap/tests/Android.bp @@ -26,13 +26,15 @@ cc_test { test_suites: ["device-tests"], srcs: [ "recoverymap_test.cpp", + "recoverymapmath_test.cpp", ], shared_libs: [ - "libimage_io", "libjpeg", "liblog", ], static_libs: [ + "libimage_io", + "libgmock", "libgtest", "libjpegdecoder", "libjpegencoder", diff --git a/libs/jpegrecoverymap/tests/data/jpeg_image.jpg b/libs/jpegrecoverymap/tests/data/jpeg_image.jpg Binary files differnew file mode 100644 index 0000000000..e2857425e7 --- /dev/null +++ b/libs/jpegrecoverymap/tests/data/jpeg_image.jpg diff --git a/libs/jpegrecoverymap/tests/data/raw_p010_image.p010 b/libs/jpegrecoverymap/tests/data/raw_p010_image.p010 Binary files differnew file mode 100644 index 0000000000..01673bf6d5 --- /dev/null +++ b/libs/jpegrecoverymap/tests/data/raw_p010_image.p010 diff --git a/libs/jpegrecoverymap/tests/recoverymap_test.cpp b/libs/jpegrecoverymap/tests/recoverymap_test.cpp index b3cd37e7e8..ade33a0e4f 100644 --- a/libs/jpegrecoverymap/tests/recoverymap_test.cpp +++ b/libs/jpegrecoverymap/tests/recoverymap_test.cpp @@ -14,8 +14,19 @@ * limitations under the License. */ -#include <gtest/gtest.h> #include <jpegrecoverymap/recoverymap.h> +#include <fcntl.h> +#include <fstream> +#include <gtest/gtest.h> +#include <utils/Log.h> + +#define RAW_P010_IMAGE "/sdcard/Documents/raw_p010_image.p010" +#define RAW_P010_IMAGE_WIDTH 1280 +#define RAW_P010_IMAGE_HEIGHT 720 +#define JPEG_IMAGE "/sdcard/Documents/jpeg_image.jpg" + +#define SAVE_ENCODING_RESULT true +#define SAVE_DECODING_RESULT true namespace android::recoverymap { @@ -26,13 +37,50 @@ public: protected: virtual void SetUp(); virtual void TearDown(); + + struct jpegr_uncompressed_struct mRawP010Image; + struct jpegr_compressed_struct mJpegImage; }; RecoveryMapTest::RecoveryMapTest() {} RecoveryMapTest::~RecoveryMapTest() {} void RecoveryMapTest::SetUp() {} -void RecoveryMapTest::TearDown() {} +void RecoveryMapTest::TearDown() { + free(mRawP010Image.data); + free(mJpegImage.data); +} + +static size_t getFileSize(int fd) { + struct stat st; + if (fstat(fd, &st) < 0) { + ALOGW("%s : fstat failed", __func__); + return 0; + } + return st.st_size; // bytes +} + +static bool loadFile(const char filename[], void*& result, int* fileLength) { + int fd = open(filename, O_CLOEXEC); + if (fd < 0) { + return false; + } + int length = getFileSize(fd); + if (length == 0) { + close(fd); + return false; + } + if (fileLength != nullptr) { + *fileLength = length; + } + result = malloc(length); + if (read(fd, result, length) != static_cast<ssize_t>(length)) { + close(fd); + return false; + } + close(fd); + return true; +} TEST_F(RecoveryMapTest, build) { // Force all of the recovery map lib to be linked by calling all public functions. @@ -45,4 +93,61 @@ TEST_F(RecoveryMapTest, build) { recovery_map.decodeJPEGR(nullptr, nullptr, nullptr, false); } +TEST_F(RecoveryMapTest, encodeFromJpegThenDecode) { + int ret; + + // Load input files. + if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) { + FAIL() << "Load file " << RAW_P010_IMAGE << " failed"; + } + mRawP010Image.width = RAW_P010_IMAGE_WIDTH; + mRawP010Image.height = RAW_P010_IMAGE_HEIGHT; + mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100; + + if (!loadFile(JPEG_IMAGE, mJpegImage.data, &mJpegImage.length)) { + FAIL() << "Load file " << JPEG_IMAGE << " failed"; + } + mJpegImage.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT709; + + RecoveryMap recoveryMap; + + jpegr_compressed_struct jpegR; + jpegR.maxLength = RAW_P010_IMAGE_WIDTH * RAW_P010_IMAGE_HEIGHT * sizeof(uint8_t); + jpegR.data = malloc(jpegR.maxLength); + ret = recoveryMap.encodeJPEGR( + &mRawP010Image, &mJpegImage, jpegr_transfer_function::JPEGR_TF_HLG, &jpegR); + if (ret != OK) { + FAIL() << "Error code is " << ret; + } + if (SAVE_ENCODING_RESULT) { + // Output image data to file + std::string filePath = "/sdcard/Documents/encoded_from_jpeg_input.jpgr"; + std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); + if (!imageFile.is_open()) { + ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); + } + imageFile.write((const char*)jpegR.data, jpegR.length); + } + + jpegr_uncompressed_struct decodedJpegR; + int decodedJpegRSize = RAW_P010_IMAGE_WIDTH * RAW_P010_IMAGE_HEIGHT * 4; + decodedJpegR.data = malloc(decodedJpegRSize); + ret = recoveryMap.decodeJPEGR(&jpegR, &decodedJpegR); + if (ret != OK) { + FAIL() << "Error code is " << ret; + } + if (SAVE_DECODING_RESULT) { + // Output image data to file + std::string filePath = "/sdcard/Documents/decoded_from_jpeg_input.rgb10"; + std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); + if (!imageFile.is_open()) { + ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); + } + imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize); + } + + free(jpegR.data); + free(decodedJpegR.data); +} + } // namespace android::recoverymap diff --git a/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp b/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp new file mode 100644 index 0000000000..169201c73b --- /dev/null +++ b/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp @@ -0,0 +1,882 @@ +/* + * Copyright 2022 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 <cmath> +#include <gtest/gtest.h> +#include <gmock/gmock.h> +#include <jpegrecoverymap/recoverymapmath.h> + +namespace android::recoverymap { + +class RecoveryMapMathTest : public testing::Test { +public: + RecoveryMapMathTest(); + ~RecoveryMapMathTest(); + + float ComparisonEpsilon() { return 1e-4f; } + float LuminanceEpsilon() { return 1e-2f; } + + Color Yuv420(uint8_t y, uint8_t u, uint8_t v) { + return {{{ static_cast<float>(y) / 255.0f, + (static_cast<float>(u) - 128.0f) / 255.0f, + (static_cast<float>(v) - 128.0f) / 255.0f }}}; + } + + Color P010(uint16_t y, uint16_t u, uint16_t v) { + return {{{ static_cast<float>(y) / 940.0f, + (static_cast<float>(u) - 64.0f) / 940.0f - 0.5f, + (static_cast<float>(v) - 64.0f) / 940.0f - 0.5f }}}; + } + + float Map(uint8_t e) { + return (static_cast<float>(e) - 127.5f) / 127.5f; + } + + Color ColorMin(Color e1, Color e2) { + return {{{ fmin(e1.r, e2.r), fmin(e1.g, e2.g), fmin(e1.b, e2.b) }}}; + } + + Color ColorMax(Color e1, Color e2) { + return {{{ fmax(e1.r, e2.r), fmax(e1.g, e2.g), fmax(e1.b, e2.b) }}}; + } + + Color RgbBlack() { return {{{ 0.0f, 0.0f, 0.0f }}}; } + Color RgbWhite() { return {{{ 1.0f, 1.0f, 1.0f }}}; } + + Color RgbRed() { return {{{ 1.0f, 0.0f, 0.0f }}}; } + Color RgbGreen() { return {{{ 0.0f, 1.0f, 0.0f }}}; } + Color RgbBlue() { return {{{ 0.0f, 0.0f, 1.0f }}}; } + + Color YuvBlack() { return {{{ 0.0f, 0.0f, 0.0f }}}; } + Color YuvWhite() { return {{{ 1.0f, 0.0f, 0.0f }}}; } + + Color SrgbYuvRed() { return {{{ 0.299f, -0.1687f, 0.5f }}}; } + Color SrgbYuvGreen() { return {{{ 0.587f, -0.3313f, -0.4187f }}}; } + Color SrgbYuvBlue() { return {{{ 0.114f, 0.5f, -0.0813f }}}; } + + Color Bt2100YuvRed() { return {{{ 0.2627f, -0.13963f, 0.5f }}}; } + Color Bt2100YuvGreen() { return {{{ 0.6780f, -0.36037f, -0.45979f }}}; } + Color Bt2100YuvBlue() { return {{{ 0.0593f, 0.5f, -0.04021f }}}; } + + float SrgbYuvToLuminance(Color yuv_gamma, ColorCalculationFn luminanceFn) { + Color rgb_gamma = srgbYuvToRgb(yuv_gamma); + Color rgb = srgbInvOetf(rgb_gamma); + float luminance_scaled = luminanceFn(rgb); + return luminance_scaled * kSdrWhiteNits; + } + + float Bt2100YuvToLuminance(Color yuv_gamma, ColorTransformFn hdrInvOetf, + ColorTransformFn gamutConversionFn, ColorCalculationFn luminanceFn, + float scale_factor) { + Color rgb_gamma = bt2100YuvToRgb(yuv_gamma); + Color rgb = hdrInvOetf(rgb_gamma); + rgb = gamutConversionFn(rgb); + float luminance_scaled = luminanceFn(rgb); + return luminance_scaled * scale_factor; + } + + Color Recover(Color yuv_gamma, float recovery, float range_scaling_factor) { + Color rgb_gamma = srgbYuvToRgb(yuv_gamma); + Color rgb = srgbInvOetf(rgb_gamma); + return applyRecovery(rgb, recovery, range_scaling_factor); + } + + jpegr_uncompressed_struct Yuv420Image() { + static uint8_t pixels[] = { + // Y + 0x00, 0x10, 0x20, 0x30, + 0x01, 0x11, 0x21, 0x31, + 0x02, 0x12, 0x22, 0x32, + 0x03, 0x13, 0x23, 0x33, + // U + 0xA0, 0xA1, + 0xA2, 0xA3, + // V + 0xB0, 0xB1, + 0xB2, 0xB3, + }; + return { pixels, 4, 4, JPEGR_COLORGAMUT_BT709 }; + } + + Color (*Yuv420Colors())[4] { + static Color colors[4][4] = { + { + Yuv420(0x00, 0xA0, 0xB0), Yuv420(0x10, 0xA0, 0xB0), + Yuv420(0x20, 0xA1, 0xB1), Yuv420(0x30, 0xA1, 0xB1), + }, { + Yuv420(0x01, 0xA0, 0xB0), Yuv420(0x11, 0xA0, 0xB0), + Yuv420(0x21, 0xA1, 0xB1), Yuv420(0x31, 0xA1, 0xB1), + }, { + Yuv420(0x02, 0xA2, 0xB2), Yuv420(0x12, 0xA2, 0xB2), + Yuv420(0x22, 0xA3, 0xB3), Yuv420(0x32, 0xA3, 0xB3), + }, { + Yuv420(0x03, 0xA2, 0xB2), Yuv420(0x13, 0xA2, 0xB2), + Yuv420(0x23, 0xA3, 0xB3), Yuv420(0x33, 0xA3, 0xB3), + }, + }; + return colors; + } + + jpegr_uncompressed_struct P010Image() { + static uint16_t pixels[] = { + // Y + 0x00 << 6, 0x10 << 6, 0x20 << 6, 0x30 << 6, + 0x01 << 6, 0x11 << 6, 0x21 << 6, 0x31 << 6, + 0x02 << 6, 0x12 << 6, 0x22 << 6, 0x32 << 6, + 0x03 << 6, 0x13 << 6, 0x23 << 6, 0x33 << 6, + // UV + 0xA0 << 6, 0xB0 << 6, 0xA1 << 6, 0xB1 << 6, + 0xA2 << 6, 0xB2 << 6, 0xA3 << 6, 0xB3 << 6, + }; + return { pixels, 4, 4, JPEGR_COLORGAMUT_BT709 }; + } + + Color (*P010Colors())[4] { + static Color colors[4][4] = { + { + P010(0x00, 0xA0, 0xB0), P010(0x10, 0xA0, 0xB0), + P010(0x20, 0xA1, 0xB1), P010(0x30, 0xA1, 0xB1), + }, { + P010(0x01, 0xA0, 0xB0), P010(0x11, 0xA0, 0xB0), + P010(0x21, 0xA1, 0xB1), P010(0x31, 0xA1, 0xB1), + }, { + P010(0x02, 0xA2, 0xB2), P010(0x12, 0xA2, 0xB2), + P010(0x22, 0xA3, 0xB3), P010(0x32, 0xA3, 0xB3), + }, { + P010(0x03, 0xA2, 0xB2), P010(0x13, 0xA2, 0xB2), + P010(0x23, 0xA3, 0xB3), P010(0x33, 0xA3, 0xB3), + }, + }; + return colors; + } + + jpegr_uncompressed_struct MapImage() { + static uint8_t pixels[] = { + 0x00, 0x10, 0x20, 0x30, + 0x01, 0x11, 0x21, 0x31, + 0x02, 0x12, 0x22, 0x32, + 0x03, 0x13, 0x23, 0x33, + }; + return { pixels, 4, 4, JPEGR_COLORGAMUT_UNSPECIFIED }; + } + + float (*MapValues())[4] { + static float values[4][4] = { + { + Map(0x00), Map(0x10), Map(0x20), Map(0x30), + }, { + Map(0x01), Map(0x11), Map(0x21), Map(0x31), + }, { + Map(0x02), Map(0x12), Map(0x22), Map(0x32), + }, { + Map(0x03), Map(0x13), Map(0x23), Map(0x33), + }, + }; + return values; + } + +protected: + virtual void SetUp(); + virtual void TearDown(); +}; + +RecoveryMapMathTest::RecoveryMapMathTest() {} +RecoveryMapMathTest::~RecoveryMapMathTest() {} + +void RecoveryMapMathTest::SetUp() {} +void RecoveryMapMathTest::TearDown() {} + +#define EXPECT_RGB_EQ(e1, e2) \ + EXPECT_FLOAT_EQ((e1).r, (e2).r); \ + EXPECT_FLOAT_EQ((e1).g, (e2).g); \ + EXPECT_FLOAT_EQ((e1).b, (e2).b) + +#define EXPECT_RGB_NEAR(e1, e2) \ + EXPECT_NEAR((e1).r, (e2).r, ComparisonEpsilon()); \ + EXPECT_NEAR((e1).g, (e2).g, ComparisonEpsilon()); \ + EXPECT_NEAR((e1).b, (e2).b, ComparisonEpsilon()) + +#define EXPECT_RGB_CLOSE(e1, e2) \ + EXPECT_NEAR((e1).r, (e2).r, ComparisonEpsilon() * 10.0f); \ + EXPECT_NEAR((e1).g, (e2).g, ComparisonEpsilon() * 10.0f); \ + EXPECT_NEAR((e1).b, (e2).b, ComparisonEpsilon() * 10.0f) + +#define EXPECT_YUV_EQ(e1, e2) \ + EXPECT_FLOAT_EQ((e1).y, (e2).y); \ + EXPECT_FLOAT_EQ((e1).u, (e2).u); \ + EXPECT_FLOAT_EQ((e1).v, (e2).v) + +#define EXPECT_YUV_NEAR(e1, e2) \ + EXPECT_NEAR((e1).y, (e2).y, ComparisonEpsilon()); \ + EXPECT_NEAR((e1).u, (e2).u, ComparisonEpsilon()); \ + EXPECT_NEAR((e1).v, (e2).v, ComparisonEpsilon()) + +#define EXPECT_YUV_BETWEEN(e, min, max) \ + EXPECT_THAT((e).y, testing::AllOf(testing::Ge((min).y), testing::Le((max).y))); \ + EXPECT_THAT((e).u, testing::AllOf(testing::Ge((min).u), testing::Le((max).u))); \ + EXPECT_THAT((e).v, testing::AllOf(testing::Ge((min).v), testing::Le((max).v))) + +// TODO: a bunch of these tests can be parameterized. + +TEST_F(RecoveryMapMathTest, ColorConstruct) { + Color e1 = {{{ 0.1f, 0.2f, 0.3f }}}; + + EXPECT_FLOAT_EQ(e1.r, 0.1f); + EXPECT_FLOAT_EQ(e1.g, 0.2f); + EXPECT_FLOAT_EQ(e1.b, 0.3f); + + EXPECT_FLOAT_EQ(e1.y, 0.1f); + EXPECT_FLOAT_EQ(e1.u, 0.2f); + EXPECT_FLOAT_EQ(e1.v, 0.3f); +} + +TEST_F(RecoveryMapMathTest, ColorAddColor) { + Color e1 = {{{ 0.1f, 0.2f, 0.3f }}}; + + Color e2 = e1 + e1; + EXPECT_FLOAT_EQ(e2.r, e1.r * 2.0f); + EXPECT_FLOAT_EQ(e2.g, e1.g * 2.0f); + EXPECT_FLOAT_EQ(e2.b, e1.b * 2.0f); + + e2 += e1; + EXPECT_FLOAT_EQ(e2.r, e1.r * 3.0f); + EXPECT_FLOAT_EQ(e2.g, e1.g * 3.0f); + EXPECT_FLOAT_EQ(e2.b, e1.b * 3.0f); +} + +TEST_F(RecoveryMapMathTest, ColorAddFloat) { + Color e1 = {{{ 0.1f, 0.2f, 0.3f }}}; + + Color e2 = e1 + 0.1f; + EXPECT_FLOAT_EQ(e2.r, e1.r + 0.1f); + EXPECT_FLOAT_EQ(e2.g, e1.g + 0.1f); + EXPECT_FLOAT_EQ(e2.b, e1.b + 0.1f); + + e2 += 0.1f; + EXPECT_FLOAT_EQ(e2.r, e1.r + 0.2f); + EXPECT_FLOAT_EQ(e2.g, e1.g + 0.2f); + EXPECT_FLOAT_EQ(e2.b, e1.b + 0.2f); +} + +TEST_F(RecoveryMapMathTest, ColorSubtractColor) { + Color e1 = {{{ 0.1f, 0.2f, 0.3f }}}; + + Color e2 = e1 - e1; + EXPECT_FLOAT_EQ(e2.r, 0.0f); + EXPECT_FLOAT_EQ(e2.g, 0.0f); + EXPECT_FLOAT_EQ(e2.b, 0.0f); + + e2 -= e1; + EXPECT_FLOAT_EQ(e2.r, -e1.r); + EXPECT_FLOAT_EQ(e2.g, -e1.g); + EXPECT_FLOAT_EQ(e2.b, -e1.b); +} + +TEST_F(RecoveryMapMathTest, ColorSubtractFloat) { + Color e1 = {{{ 0.1f, 0.2f, 0.3f }}}; + + Color e2 = e1 - 0.1f; + EXPECT_FLOAT_EQ(e2.r, e1.r - 0.1f); + EXPECT_FLOAT_EQ(e2.g, e1.g - 0.1f); + EXPECT_FLOAT_EQ(e2.b, e1.b - 0.1f); + + e2 -= 0.1f; + EXPECT_FLOAT_EQ(e2.r, e1.r - 0.2f); + EXPECT_FLOAT_EQ(e2.g, e1.g - 0.2f); + EXPECT_FLOAT_EQ(e2.b, e1.b - 0.2f); +} + +TEST_F(RecoveryMapMathTest, ColorMultiplyFloat) { + Color e1 = {{{ 0.1f, 0.2f, 0.3f }}}; + + Color e2 = e1 * 2.0f; + EXPECT_FLOAT_EQ(e2.r, e1.r * 2.0f); + EXPECT_FLOAT_EQ(e2.g, e1.g * 2.0f); + EXPECT_FLOAT_EQ(e2.b, e1.b * 2.0f); + + e2 *= 2.0f; + EXPECT_FLOAT_EQ(e2.r, e1.r * 4.0f); + EXPECT_FLOAT_EQ(e2.g, e1.g * 4.0f); + EXPECT_FLOAT_EQ(e2.b, e1.b * 4.0f); +} + +TEST_F(RecoveryMapMathTest, ColorDivideFloat) { + Color e1 = {{{ 0.1f, 0.2f, 0.3f }}}; + + Color e2 = e1 / 2.0f; + EXPECT_FLOAT_EQ(e2.r, e1.r / 2.0f); + EXPECT_FLOAT_EQ(e2.g, e1.g / 2.0f); + EXPECT_FLOAT_EQ(e2.b, e1.b / 2.0f); + + e2 /= 2.0f; + EXPECT_FLOAT_EQ(e2.r, e1.r / 4.0f); + EXPECT_FLOAT_EQ(e2.g, e1.g / 4.0f); + EXPECT_FLOAT_EQ(e2.b, e1.b / 4.0f); +} + +TEST_F(RecoveryMapMathTest, SrgbLuminance) { + EXPECT_FLOAT_EQ(srgbLuminance(RgbBlack()), 0.0f); + EXPECT_FLOAT_EQ(srgbLuminance(RgbWhite()), 1.0f); + EXPECT_FLOAT_EQ(srgbLuminance(RgbRed()), 0.2126f); + EXPECT_FLOAT_EQ(srgbLuminance(RgbGreen()), 0.7152f); + EXPECT_FLOAT_EQ(srgbLuminance(RgbBlue()), 0.0722f); +} + +TEST_F(RecoveryMapMathTest, SrgbYuvToRgb) { + Color rgb_black = srgbYuvToRgb(YuvBlack()); + EXPECT_RGB_NEAR(rgb_black, RgbBlack()); + + Color rgb_white = srgbYuvToRgb(YuvWhite()); + EXPECT_RGB_NEAR(rgb_white, RgbWhite()); + + Color rgb_r = srgbYuvToRgb(SrgbYuvRed()); + EXPECT_RGB_NEAR(rgb_r, RgbRed()); + + Color rgb_g = srgbYuvToRgb(SrgbYuvGreen()); + EXPECT_RGB_NEAR(rgb_g, RgbGreen()); + + Color rgb_b = srgbYuvToRgb(SrgbYuvBlue()); + EXPECT_RGB_NEAR(rgb_b, RgbBlue()); +} + +TEST_F(RecoveryMapMathTest, SrgbRgbToYuv) { + Color yuv_black = srgbRgbToYuv(RgbBlack()); + EXPECT_YUV_NEAR(yuv_black, YuvBlack()); + + Color yuv_white = srgbRgbToYuv(RgbWhite()); + EXPECT_YUV_NEAR(yuv_white, YuvWhite()); + + Color yuv_r = srgbRgbToYuv(RgbRed()); + EXPECT_YUV_NEAR(yuv_r, SrgbYuvRed()); + + Color yuv_g = srgbRgbToYuv(RgbGreen()); + EXPECT_YUV_NEAR(yuv_g, SrgbYuvGreen()); + + Color yuv_b = srgbRgbToYuv(RgbBlue()); + EXPECT_YUV_NEAR(yuv_b, SrgbYuvBlue()); +} + +TEST_F(RecoveryMapMathTest, SrgbRgbYuvRoundtrip) { + Color rgb_black = srgbYuvToRgb(srgbRgbToYuv(RgbBlack())); + EXPECT_RGB_NEAR(rgb_black, RgbBlack()); + + Color rgb_white = srgbYuvToRgb(srgbRgbToYuv(RgbWhite())); + EXPECT_RGB_NEAR(rgb_white, RgbWhite()); + + Color rgb_r = srgbYuvToRgb(srgbRgbToYuv(RgbRed())); + EXPECT_RGB_NEAR(rgb_r, RgbRed()); + + Color rgb_g = srgbYuvToRgb(srgbRgbToYuv(RgbGreen())); + EXPECT_RGB_NEAR(rgb_g, RgbGreen()); + + Color rgb_b = srgbYuvToRgb(srgbRgbToYuv(RgbBlue())); + EXPECT_RGB_NEAR(rgb_b, RgbBlue()); +} + +TEST_F(RecoveryMapMathTest, SrgbTransferFunction) { + EXPECT_FLOAT_EQ(srgbInvOetf(0.0f), 0.0f); + EXPECT_NEAR(srgbInvOetf(0.02f), 0.00154f, ComparisonEpsilon()); + EXPECT_NEAR(srgbInvOetf(0.04045f), 0.00313f, ComparisonEpsilon()); + EXPECT_NEAR(srgbInvOetf(0.5f), 0.21404f, ComparisonEpsilon()); + EXPECT_FLOAT_EQ(srgbInvOetf(1.0f), 1.0f); +} + +TEST_F(RecoveryMapMathTest, P3Luminance) { + EXPECT_FLOAT_EQ(p3Luminance(RgbBlack()), 0.0f); + EXPECT_FLOAT_EQ(p3Luminance(RgbWhite()), 1.0f); + EXPECT_FLOAT_EQ(p3Luminance(RgbRed()), 0.20949f); + EXPECT_FLOAT_EQ(p3Luminance(RgbGreen()), 0.72160f); + EXPECT_FLOAT_EQ(p3Luminance(RgbBlue()), 0.06891f); +} + +TEST_F(RecoveryMapMathTest, Bt2100Luminance) { + EXPECT_FLOAT_EQ(bt2100Luminance(RgbBlack()), 0.0f); + EXPECT_FLOAT_EQ(bt2100Luminance(RgbWhite()), 1.0f); + EXPECT_FLOAT_EQ(bt2100Luminance(RgbRed()), 0.2627f); + EXPECT_FLOAT_EQ(bt2100Luminance(RgbGreen()), 0.6780f); + EXPECT_FLOAT_EQ(bt2100Luminance(RgbBlue()), 0.0593f); +} + +TEST_F(RecoveryMapMathTest, Bt2100YuvToRgb) { + Color rgb_black = bt2100YuvToRgb(YuvBlack()); + EXPECT_RGB_NEAR(rgb_black, RgbBlack()); + + Color rgb_white = bt2100YuvToRgb(YuvWhite()); + EXPECT_RGB_NEAR(rgb_white, RgbWhite()); + + Color rgb_r = bt2100YuvToRgb(Bt2100YuvRed()); + EXPECT_RGB_NEAR(rgb_r, RgbRed()); + + Color rgb_g = bt2100YuvToRgb(Bt2100YuvGreen()); + EXPECT_RGB_NEAR(rgb_g, RgbGreen()); + + Color rgb_b = bt2100YuvToRgb(Bt2100YuvBlue()); + EXPECT_RGB_NEAR(rgb_b, RgbBlue()); +} + +TEST_F(RecoveryMapMathTest, Bt2100RgbToYuv) { + Color yuv_black = bt2100RgbToYuv(RgbBlack()); + EXPECT_YUV_NEAR(yuv_black, YuvBlack()); + + Color yuv_white = bt2100RgbToYuv(RgbWhite()); + EXPECT_YUV_NEAR(yuv_white, YuvWhite()); + + Color yuv_r = bt2100RgbToYuv(RgbRed()); + EXPECT_YUV_NEAR(yuv_r, Bt2100YuvRed()); + + Color yuv_g = bt2100RgbToYuv(RgbGreen()); + EXPECT_YUV_NEAR(yuv_g, Bt2100YuvGreen()); + + Color yuv_b = bt2100RgbToYuv(RgbBlue()); + EXPECT_YUV_NEAR(yuv_b, Bt2100YuvBlue()); +} + +TEST_F(RecoveryMapMathTest, Bt2100RgbYuvRoundtrip) { + Color rgb_black = bt2100YuvToRgb(bt2100RgbToYuv(RgbBlack())); + EXPECT_RGB_NEAR(rgb_black, RgbBlack()); + + Color rgb_white = bt2100YuvToRgb(bt2100RgbToYuv(RgbWhite())); + EXPECT_RGB_NEAR(rgb_white, RgbWhite()); + + Color rgb_r = bt2100YuvToRgb(bt2100RgbToYuv(RgbRed())); + EXPECT_RGB_NEAR(rgb_r, RgbRed()); + + Color rgb_g = bt2100YuvToRgb(bt2100RgbToYuv(RgbGreen())); + EXPECT_RGB_NEAR(rgb_g, RgbGreen()); + + Color rgb_b = bt2100YuvToRgb(bt2100RgbToYuv(RgbBlue())); + EXPECT_RGB_NEAR(rgb_b, RgbBlue()); +} + +TEST_F(RecoveryMapMathTest, HlgOetf) { + EXPECT_FLOAT_EQ(hlgOetf(0.0f), 0.0f); + EXPECT_NEAR(hlgOetf(0.04167f), 0.35357f, ComparisonEpsilon()); + EXPECT_NEAR(hlgOetf(0.08333f), 0.5f, ComparisonEpsilon()); + EXPECT_NEAR(hlgOetf(0.5f), 0.87164f, ComparisonEpsilon()); + EXPECT_FLOAT_EQ(hlgOetf(1.0f), 1.0f); + + Color e = {{{ 0.04167f, 0.08333f, 0.5f }}}; + Color e_gamma = {{{ 0.35357f, 0.5f, 0.87164f }}}; + EXPECT_RGB_NEAR(hlgOetf(e), e_gamma); +} + +TEST_F(RecoveryMapMathTest, HlgInvOetf) { + EXPECT_FLOAT_EQ(hlgInvOetf(0.0f), 0.0f); + EXPECT_NEAR(hlgInvOetf(0.25f), 0.02083f, ComparisonEpsilon()); + EXPECT_NEAR(hlgInvOetf(0.5f), 0.08333f, ComparisonEpsilon()); + EXPECT_NEAR(hlgInvOetf(0.75f), 0.26496f, ComparisonEpsilon()); + EXPECT_FLOAT_EQ(hlgInvOetf(1.0f), 1.0f); + + Color e_gamma = {{{ 0.25f, 0.5f, 0.75f }}}; + Color e = {{{ 0.02083f, 0.08333f, 0.26496f }}}; + EXPECT_RGB_NEAR(hlgInvOetf(e_gamma), e); +} + +TEST_F(RecoveryMapMathTest, HlgTransferFunctionRoundtrip) { + EXPECT_FLOAT_EQ(hlgInvOetf(hlgOetf(0.0f)), 0.0f); + EXPECT_NEAR(hlgInvOetf(hlgOetf(0.04167f)), 0.04167f, ComparisonEpsilon()); + EXPECT_NEAR(hlgInvOetf(hlgOetf(0.08333f)), 0.08333f, ComparisonEpsilon()); + EXPECT_NEAR(hlgInvOetf(hlgOetf(0.5f)), 0.5f, ComparisonEpsilon()); + EXPECT_FLOAT_EQ(hlgInvOetf(hlgOetf(1.0f)), 1.0f); +} + +TEST_F(RecoveryMapMathTest, PqOetf) { + EXPECT_FLOAT_EQ(pqOetf(0.0f), 0.0f); + EXPECT_NEAR(pqOetf(0.01f), 0.50808f, ComparisonEpsilon()); + EXPECT_NEAR(pqOetf(0.5f), 0.92655f, ComparisonEpsilon()); + EXPECT_NEAR(pqOetf(0.99f), 0.99895f, ComparisonEpsilon()); + EXPECT_FLOAT_EQ(pqOetf(1.0f), 1.0f); + + Color e = {{{ 0.01f, 0.5f, 0.99f }}}; + Color e_gamma = {{{ 0.50808f, 0.92655f, 0.99895f }}}; + EXPECT_RGB_NEAR(pqOetf(e), e_gamma); +} + +TEST_F(RecoveryMapMathTest, PqInvOetf) { + EXPECT_FLOAT_EQ(pqInvOetf(0.0f), 0.0f); + EXPECT_NEAR(pqInvOetf(0.01f), 2.31017e-7f, ComparisonEpsilon()); + EXPECT_NEAR(pqInvOetf(0.5f), 0.00922f, ComparisonEpsilon()); + EXPECT_NEAR(pqInvOetf(0.99f), 0.90903f, ComparisonEpsilon()); + EXPECT_FLOAT_EQ(pqInvOetf(1.0f), 1.0f); + + Color e_gamma = {{{ 0.01f, 0.5f, 0.99f }}}; + Color e = {{{ 2.31017e-7f, 0.00922f, 0.90903f }}}; + EXPECT_RGB_NEAR(pqInvOetf(e_gamma), e); +} + +TEST_F(RecoveryMapMathTest, PqTransferFunctionRoundtrip) { + EXPECT_FLOAT_EQ(pqInvOetf(pqOetf(0.0f)), 0.0f); + EXPECT_NEAR(pqInvOetf(pqOetf(0.01f)), 0.01f, ComparisonEpsilon()); + EXPECT_NEAR(pqInvOetf(pqOetf(0.5f)), 0.5f, ComparisonEpsilon()); + EXPECT_NEAR(pqInvOetf(pqOetf(0.99f)), 0.99f, ComparisonEpsilon()); + EXPECT_FLOAT_EQ(pqInvOetf(pqOetf(1.0f)), 1.0f); +} + +TEST_F(RecoveryMapMathTest, ColorConversionLookup) { + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_UNSPECIFIED), + nullptr); + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_BT709), + identityConversion); + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_P3), + p3ToBt709); + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_BT2100), + bt2100ToBt709); + + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_UNSPECIFIED), + nullptr); + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_BT709), + bt709ToP3); + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_P3), + identityConversion); + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_BT2100), + bt2100ToP3); + + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_UNSPECIFIED), + nullptr); + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_BT709), + bt709ToBt2100); + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_P3), + p3ToBt2100); + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_BT2100), + identityConversion); + + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_UNSPECIFIED), + nullptr); + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_BT709), + nullptr); + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_P3), + nullptr); + EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_BT2100), + nullptr); +} + +TEST_F(RecoveryMapMathTest, EncodeRecovery) { + EXPECT_EQ(encodeRecovery(0.0f, 0.0f, 4.0f), 127); + EXPECT_EQ(encodeRecovery(0.0f, 1.0f, 4.0f), 127); + EXPECT_EQ(encodeRecovery(1.0f, 0.0f, 4.0f), 0); + EXPECT_EQ(encodeRecovery(0.5f, 0.0f, 4.0f), 0); + + EXPECT_EQ(encodeRecovery(1.0f, 1.0f, 4.0f), 127); + EXPECT_EQ(encodeRecovery(1.0f, 4.0f, 4.0f), 255); + EXPECT_EQ(encodeRecovery(1.0f, 5.0f, 4.0f), 255); + EXPECT_EQ(encodeRecovery(4.0f, 1.0f, 4.0f), 0); + EXPECT_EQ(encodeRecovery(4.0f, 0.5f, 4.0f), 0); + EXPECT_EQ(encodeRecovery(1.0f, 2.0f, 4.0f), 191); + EXPECT_EQ(encodeRecovery(2.0f, 1.0f, 4.0f), 63); + + EXPECT_EQ(encodeRecovery(1.0f, 2.0f, 2.0f), 255); + EXPECT_EQ(encodeRecovery(2.0f, 1.0f, 2.0f), 0); + EXPECT_EQ(encodeRecovery(1.0f, 1.41421f, 2.0f), 191); + EXPECT_EQ(encodeRecovery(1.41421f, 1.0f, 2.0f), 63); + + EXPECT_EQ(encodeRecovery(1.0f, 8.0f, 8.0f), 255); + EXPECT_EQ(encodeRecovery(8.0f, 1.0f, 8.0f), 0); + EXPECT_EQ(encodeRecovery(1.0f, 2.82843f, 8.0f), 191); + EXPECT_EQ(encodeRecovery(2.82843f, 1.0f, 8.0f), 63); +} + +TEST_F(RecoveryMapMathTest, ApplyRecovery) { + EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), -1.0f, 4.0f), RgbBlack()); + EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 0.0f, 4.0f), RgbBlack()); + EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 1.0f, 4.0f), RgbBlack()); + + EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -1.0f, 4.0f), RgbWhite() / 4.0f); + EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -0.5f, 4.0f), RgbWhite() / 2.0f); + EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, 4.0f), RgbWhite()); + EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, 4.0f), RgbWhite() * 2.0f); + EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, 4.0f), RgbWhite() * 4.0f); + + EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -1.0f, 2.0f), RgbWhite() / 2.0f); + EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -0.5f, 2.0f), RgbWhite() / 1.41421f); + EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, 2.0f), RgbWhite()); + EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, 2.0f), RgbWhite() * 1.41421f); + EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, 2.0f), RgbWhite() * 2.0f); + + EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -1.0f, 8.0f), RgbWhite() / 8.0f); + EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -0.5f, 8.0f), RgbWhite() / 2.82843f); + EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, 8.0f), RgbWhite()); + EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, 8.0f), RgbWhite() * 2.82843f); + EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, 8.0f), RgbWhite() * 8.0f); + + Color e = {{{ 0.0f, 0.5f, 1.0f }}}; + + EXPECT_RGB_NEAR(applyRecovery(e, -1.0f, 4.0f), e / 4.0f); + EXPECT_RGB_NEAR(applyRecovery(e, -0.5f, 4.0f), e / 2.0f); + EXPECT_RGB_NEAR(applyRecovery(e, 0.0f, 4.0f), e); + EXPECT_RGB_NEAR(applyRecovery(e, 0.5f, 4.0f), e * 2.0f); + EXPECT_RGB_NEAR(applyRecovery(e, 1.0f, 4.0f), e * 4.0f); +} + +TEST_F(RecoveryMapMathTest, GetYuv420Pixel) { + jpegr_uncompressed_struct image = Yuv420Image(); + Color (*colors)[4] = Yuv420Colors(); + + for (size_t y = 0; y < 4; ++y) { + for (size_t x = 0; x < 4; ++x) { + EXPECT_YUV_NEAR(getYuv420Pixel(&image, x, y), colors[y][x]); + } + } +} + +TEST_F(RecoveryMapMathTest, GetP010Pixel) { + jpegr_uncompressed_struct image = P010Image(); + Color (*colors)[4] = P010Colors(); + + for (size_t y = 0; y < 4; ++y) { + for (size_t x = 0; x < 4; ++x) { + EXPECT_YUV_NEAR(getP010Pixel(&image, x, y), colors[y][x]); + } + } +} + +TEST_F(RecoveryMapMathTest, SampleYuv420) { + jpegr_uncompressed_struct image = Yuv420Image(); + Color (*colors)[4] = Yuv420Colors(); + + static const size_t kMapScaleFactor = 2; + for (size_t y = 0; y < 4 / kMapScaleFactor; ++y) { + for (size_t x = 0; x < 4 / kMapScaleFactor; ++x) { + Color min = {{{ 1.0f, 1.0f, 1.0f }}}; + Color max = {{{ -1.0f, -1.0f, -1.0f }}}; + + for (size_t dy = 0; dy < kMapScaleFactor; ++dy) { + for (size_t dx = 0; dx < kMapScaleFactor; ++dx) { + Color e = colors[y * kMapScaleFactor + dy][x * kMapScaleFactor + dx]; + min = ColorMin(min, e); + max = ColorMax(max, e); + } + } + + // Instead of reimplementing the sampling algorithm, confirm that the + // sample output is within the range of the min and max of the nearest + // points. + EXPECT_YUV_BETWEEN(sampleYuv420(&image, kMapScaleFactor, x, y), min, max); + } + } +} + +TEST_F(RecoveryMapMathTest, SampleP010) { + jpegr_uncompressed_struct image = P010Image(); + Color (*colors)[4] = P010Colors(); + + static const size_t kMapScaleFactor = 2; + for (size_t y = 0; y < 4 / kMapScaleFactor; ++y) { + for (size_t x = 0; x < 4 / kMapScaleFactor; ++x) { + Color min = {{{ 1.0f, 1.0f, 1.0f }}}; + Color max = {{{ -1.0f, -1.0f, -1.0f }}}; + + for (size_t dy = 0; dy < kMapScaleFactor; ++dy) { + for (size_t dx = 0; dx < kMapScaleFactor; ++dx) { + Color e = colors[y * kMapScaleFactor + dy][x * kMapScaleFactor + dx]; + min = ColorMin(min, e); + max = ColorMax(max, e); + } + } + + // Instead of reimplementing the sampling algorithm, confirm that the + // sample output is within the range of the min and max of the nearest + // points. + EXPECT_YUV_BETWEEN(sampleP010(&image, kMapScaleFactor, x, y), min, max); + } + } +} + +TEST_F(RecoveryMapMathTest, SampleMap) { + jpegr_uncompressed_struct image = MapImage(); + float (*values)[4] = MapValues(); + + static const size_t kMapScaleFactor = 2; + for (size_t y = 0; y < 4 * kMapScaleFactor; ++y) { + for (size_t x = 0; x < 4 * kMapScaleFactor; ++x) { + size_t x_base = x / kMapScaleFactor; + size_t y_base = y / kMapScaleFactor; + + float min = 1.0f; + float max = -1.0f; + + min = fmin(min, values[y_base][x_base]); + max = fmax(max, values[y_base][x_base]); + if (y_base + 1 < 4) { + min = fmin(min, values[y_base + 1][x_base]); + max = fmax(max, values[y_base + 1][x_base]); + } + if (x_base + 1 < 4) { + min = fmin(min, values[y_base][x_base + 1]); + max = fmax(max, values[y_base][x_base + 1]); + } + if (y_base + 1 < 4 && x_base + 1 < 4) { + min = fmin(min, values[y_base + 1][x_base + 1]); + max = fmax(max, values[y_base + 1][x_base + 1]); + } + + // Instead of reimplementing the sampling algorithm, confirm that the + // sample output is within the range of the min and max of the nearest + // points. + EXPECT_THAT(sampleMap(&image, kMapScaleFactor, x, y), + testing::AllOf(testing::Ge(min), testing::Le(max))); + } + } +} + +TEST_F(RecoveryMapMathTest, ColorToRgba1010102) { + EXPECT_EQ(colorToRgba1010102(RgbBlack()), 0x3 << 30); + EXPECT_EQ(colorToRgba1010102(RgbWhite()), 0xFFFFFFFF); + EXPECT_EQ(colorToRgba1010102(RgbRed()), 0x3 << 30 | 0x3ff); + EXPECT_EQ(colorToRgba1010102(RgbGreen()), 0x3 << 30 | 0x3ff << 10); + EXPECT_EQ(colorToRgba1010102(RgbBlue()), 0x3 << 30 | 0x3ff << 20); + + Color e_gamma = {{{ 0.1f, 0.2f, 0.3f }}}; + EXPECT_EQ(colorToRgba1010102(e_gamma), + 0x3 << 30 + | static_cast<uint32_t>(0.1f * static_cast<float>(0x3ff)) + | static_cast<uint32_t>(0.2f * static_cast<float>(0x3ff)) << 10 + | static_cast<uint32_t>(0.3f * static_cast<float>(0x3ff)) << 20); +} + +TEST_F(RecoveryMapMathTest, GenerateMapLuminanceSrgb) { + EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvBlack(), srgbLuminance), + 0.0f); + EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvWhite(), srgbLuminance), + kSdrWhiteNits); + EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvRed(), srgbLuminance), + srgbLuminance(RgbRed()) * kSdrWhiteNits, LuminanceEpsilon()); + EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvGreen(), srgbLuminance), + srgbLuminance(RgbGreen()) * kSdrWhiteNits, LuminanceEpsilon()); + EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvBlue(), srgbLuminance), + srgbLuminance(RgbBlue()) * kSdrWhiteNits, LuminanceEpsilon()); +} + +TEST_F(RecoveryMapMathTest, GenerateMapLuminanceSrgbP3) { + EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvBlack(), p3Luminance), + 0.0f); + EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvWhite(), p3Luminance), + kSdrWhiteNits); + EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvRed(), p3Luminance), + p3Luminance(RgbRed()) * kSdrWhiteNits, LuminanceEpsilon()); + EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvGreen(), p3Luminance), + p3Luminance(RgbGreen()) * kSdrWhiteNits, LuminanceEpsilon()); + EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvBlue(), p3Luminance), + p3Luminance(RgbBlue()) * kSdrWhiteNits, LuminanceEpsilon()); +} + +TEST_F(RecoveryMapMathTest, GenerateMapLuminanceSrgbBt2100) { + EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvBlack(), bt2100Luminance), + 0.0f); + EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvWhite(), bt2100Luminance), + kSdrWhiteNits); + EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvRed(), bt2100Luminance), + bt2100Luminance(RgbRed()) * kSdrWhiteNits, LuminanceEpsilon()); + EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvGreen(), bt2100Luminance), + bt2100Luminance(RgbGreen()) * kSdrWhiteNits, LuminanceEpsilon()); + EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvBlue(), bt2100Luminance), + bt2100Luminance(RgbBlue()) * kSdrWhiteNits, LuminanceEpsilon()); +} + +TEST_F(RecoveryMapMathTest, GenerateMapLuminanceHlg) { + EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvBlack(), hlgInvOetf, identityConversion, + bt2100Luminance, kHlgMaxNits), + 0.0f); + EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvWhite(), hlgInvOetf, identityConversion, + bt2100Luminance, kHlgMaxNits), + kHlgMaxNits); + EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvRed(), hlgInvOetf, identityConversion, + bt2100Luminance, kHlgMaxNits), + bt2100Luminance(RgbRed()) * kHlgMaxNits, LuminanceEpsilon()); + EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvGreen(), hlgInvOetf, identityConversion, + bt2100Luminance, kHlgMaxNits), + bt2100Luminance(RgbGreen()) * kHlgMaxNits, LuminanceEpsilon()); + EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvBlue(), hlgInvOetf, identityConversion, + bt2100Luminance, kHlgMaxNits), + bt2100Luminance(RgbBlue()) * kHlgMaxNits, LuminanceEpsilon()); +} + +TEST_F(RecoveryMapMathTest, GenerateMapLuminancePq) { + EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvBlack(), pqInvOetf, identityConversion, + bt2100Luminance, kPqMaxNits), + 0.0f); + EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvWhite(), pqInvOetf, identityConversion, + bt2100Luminance, kPqMaxNits), + kPqMaxNits); + EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvRed(), pqInvOetf, identityConversion, + bt2100Luminance, kPqMaxNits), + bt2100Luminance(RgbRed()) * kPqMaxNits, LuminanceEpsilon()); + EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvGreen(), pqInvOetf, identityConversion, + bt2100Luminance, kPqMaxNits), + bt2100Luminance(RgbGreen()) * kPqMaxNits, LuminanceEpsilon()); + EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvBlue(), pqInvOetf, identityConversion, + bt2100Luminance, kPqMaxNits), + bt2100Luminance(RgbBlue()) * kPqMaxNits, LuminanceEpsilon()); +} + +//Color Recover(Color yuv_gamma, float recovery, float range_scaling_factor) { +TEST_F(RecoveryMapMathTest, ApplyMap) { + EXPECT_RGB_EQ(Recover(YuvWhite(), 1.0f, 8.0f), + RgbWhite() * 8.0f); + EXPECT_RGB_EQ(Recover(YuvBlack(), 1.0f, 8.0f), + RgbBlack()); + EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 1.0f, 8.0f), + RgbRed() * 8.0f); + EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 1.0f, 8.0f), + RgbGreen() * 8.0f); + EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 1.0f, 8.0f), + RgbBlue() * 8.0f); + + EXPECT_RGB_EQ(Recover(YuvWhite(), 0.5f, 8.0f), + RgbWhite() * sqrt(8.0f)); + EXPECT_RGB_EQ(Recover(YuvBlack(), 0.5f, 8.0f), + RgbBlack()); + EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.5f, 8.0f), + RgbRed() * sqrt(8.0f)); + EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.5f, 8.0f), + RgbGreen() * sqrt(8.0f)); + EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.5f, 8.0f), + RgbBlue() * sqrt(8.0f)); + + EXPECT_RGB_EQ(Recover(YuvWhite(), 0.0f, 8.0f), + RgbWhite()); + EXPECT_RGB_EQ(Recover(YuvBlack(), 0.0f, 8.0f), + RgbBlack()); + EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.0f, 8.0f), + RgbRed()); + EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.0f, 8.0f), + RgbGreen()); + EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.0f, 8.0f), + RgbBlue()); + + EXPECT_RGB_EQ(Recover(YuvWhite(), -0.5f, 8.0f), + RgbWhite() / sqrt(8.0f)); + EXPECT_RGB_EQ(Recover(YuvBlack(), -0.5f, 8.0f), + RgbBlack()); + EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), -0.5f, 8.0f), + RgbRed() / sqrt(8.0f)); + EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), -0.5f, 8.0f), + RgbGreen() / sqrt(8.0f)); + EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), -0.5f, 8.0f), + RgbBlue() / sqrt(8.0f)); + + EXPECT_RGB_EQ(Recover(YuvWhite(), -1.0f, 8.0f), + RgbWhite() / 8.0f); + EXPECT_RGB_EQ(Recover(YuvBlack(), -1.0f, 8.0f), + RgbBlack()); + EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), -1.0f, 8.0f), + RgbRed() / 8.0f); + EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), -1.0f, 8.0f), + RgbGreen() / 8.0f); + EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), -1.0f, 8.0f), + RgbBlue() / 8.0f); +} + +} // namespace android::recoverymap diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index 539cbaa341..e64165fef3 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -14,13 +14,10 @@ * limitations under the License. */ -#define LOG_TAG "Choreographer" -//#define LOG_NDEBUG 0 - #include <android-base/thread_annotations.h> #include <android/gui/ISurfaceComposer.h> -#include <gui/DisplayEventDispatcher.h> #include <jni.h> +#include <nativedisplay/Choreographer.h> #include <private/android/choreographer.h> #include <utils/Looper.h> #include <utils/Timers.h> @@ -31,444 +28,9 @@ #include <queue> #include <thread> -namespace { -struct { - // Global JVM that is provided by zygote - JavaVM* jvm = nullptr; - struct { - jclass clazz; - jmethodID getInstance; - jmethodID registerNativeChoreographerForRefreshRateCallbacks; - jmethodID unregisterNativeChoreographerForRefreshRateCallbacks; - } displayManagerGlobal; -} gJni; - -// Gets the JNIEnv* for this thread, and performs one-off initialization if we -// have never retrieved a JNIEnv* pointer before. -JNIEnv* getJniEnv() { - if (gJni.jvm == nullptr) { - ALOGW("AChoreographer: No JVM provided!"); - return nullptr; - } - - JNIEnv* env = nullptr; - if (gJni.jvm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) { - ALOGD("Attaching thread to JVM for AChoreographer"); - JavaVMAttachArgs args = {JNI_VERSION_1_4, "AChoreographer_env", NULL}; - jint attachResult = gJni.jvm->AttachCurrentThreadAsDaemon(&env, (void*)&args); - if (attachResult != JNI_OK) { - ALOGE("Unable to attach thread. Error: %d", attachResult); - return nullptr; - } - } - if (env == nullptr) { - ALOGW("AChoreographer: No JNI env available!"); - } - return env; -} - -inline const char* toString(bool value) { - return value ? "true" : "false"; -} -} // namespace - -namespace android { -using gui::VsyncEventData; - -struct FrameCallback { - AChoreographer_frameCallback callback; - AChoreographer_frameCallback64 callback64; - AChoreographer_vsyncCallback vsyncCallback; - void* data; - nsecs_t dueTime; - - inline bool operator<(const FrameCallback& rhs) const { - // Note that this is intentionally flipped because we want callbacks due sooner to be at - // the head of the queue - return dueTime > rhs.dueTime; - } -}; - -struct RefreshRateCallback { - AChoreographer_refreshRateCallback callback; - void* data; - bool firstCallbackFired = false; -}; - -class Choreographer; - -/** - * Implementation of AChoreographerFrameCallbackData. - */ -struct ChoreographerFrameCallbackDataImpl { - int64_t frameTimeNanos{0}; - - VsyncEventData vsyncEventData; - - const Choreographer* choreographer; -}; - -struct { - std::mutex lock; - std::vector<Choreographer*> ptrs GUARDED_BY(lock); - std::map<AVsyncId, int64_t> startTimes GUARDED_BY(lock); - bool registeredToDisplayManager GUARDED_BY(lock) = false; - - std::atomic<nsecs_t> mLastKnownVsync = -1; -} gChoreographers; - -class Choreographer : public DisplayEventDispatcher, public MessageHandler { -public: - explicit Choreographer(const sp<Looper>& looper) EXCLUDES(gChoreographers.lock); - void postFrameCallbackDelayed(AChoreographer_frameCallback cb, - AChoreographer_frameCallback64 cb64, - AChoreographer_vsyncCallback vsyncCallback, void* data, - nsecs_t delay); - void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) - EXCLUDES(gChoreographers.lock); - void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data); - // Drains the queue of pending vsync periods and dispatches refresh rate - // updates to callbacks. - // The assumption is that this method is only called on a single - // processing thread, either by looper or by AChoreographer_handleEvents - void handleRefreshRateUpdates(); - void scheduleLatestConfigRequest(); - - enum { - MSG_SCHEDULE_CALLBACKS = 0, - MSG_SCHEDULE_VSYNC = 1, - MSG_HANDLE_REFRESH_RATE_UPDATES = 2, - }; - virtual void handleMessage(const Message& message) override; - - static Choreographer* getForThread(); - virtual ~Choreographer() override EXCLUDES(gChoreographers.lock); - int64_t getFrameInterval() const; - bool inCallback() const; - -private: - Choreographer(const Choreographer&) = delete; - - void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count, - VsyncEventData vsyncEventData) override; - void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override; - void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId, - nsecs_t vsyncPeriod) override; - void dispatchNullEvent(nsecs_t, PhysicalDisplayId) override; - void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId, - std::vector<FrameRateOverride> overrides) override; - - void scheduleCallbacks(); - - ChoreographerFrameCallbackDataImpl createFrameCallbackData(nsecs_t timestamp) const; - void registerStartTime() const; - - std::mutex mLock; - // Protected by mLock - std::priority_queue<FrameCallback> mFrameCallbacks; - std::vector<RefreshRateCallback> mRefreshRateCallbacks; - - nsecs_t mLatestVsyncPeriod = -1; - VsyncEventData mLastVsyncEventData; - bool mInCallback = false; - - const sp<Looper> mLooper; - const std::thread::id mThreadId; - - // Approximation of num_threads_using_choreographer * num_frames_of_history with leeway. - static constexpr size_t kMaxStartTimes = 250; -}; - -static thread_local Choreographer* gChoreographer; -Choreographer* Choreographer::getForThread() { - if (gChoreographer == nullptr) { - sp<Looper> looper = Looper::getForThread(); - if (!looper.get()) { - ALOGW("No looper prepared for thread"); - return nullptr; - } - gChoreographer = new Choreographer(looper); - status_t result = gChoreographer->initialize(); - if (result != OK) { - ALOGW("Failed to initialize"); - return nullptr; - } - } - return gChoreographer; -} - -Choreographer::Choreographer(const sp<Looper>& looper) - : DisplayEventDispatcher(looper, gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp), - mLooper(looper), - mThreadId(std::this_thread::get_id()) { - std::lock_guard<std::mutex> _l(gChoreographers.lock); - gChoreographers.ptrs.push_back(this); -} - -Choreographer::~Choreographer() { - std::lock_guard<std::mutex> _l(gChoreographers.lock); - gChoreographers.ptrs.erase(std::remove_if(gChoreographers.ptrs.begin(), - gChoreographers.ptrs.end(), - [=](Choreographer* c) { return c == this; }), - gChoreographers.ptrs.end()); - // Only poke DisplayManagerGlobal to unregister if we previously registered - // callbacks. - if (gChoreographers.ptrs.empty() && gChoreographers.registeredToDisplayManager) { - gChoreographers.registeredToDisplayManager = false; - JNIEnv* env = getJniEnv(); - if (env == nullptr) { - ALOGW("JNI environment is unavailable, skipping choreographer cleanup"); - return; - } - jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz, - gJni.displayManagerGlobal.getInstance); - if (dmg == nullptr) { - ALOGW("DMS is not initialized yet, skipping choreographer cleanup"); - } else { - env->CallVoidMethod(dmg, - gJni.displayManagerGlobal - .unregisterNativeChoreographerForRefreshRateCallbacks); - env->DeleteLocalRef(dmg); - } - } -} - -void Choreographer::postFrameCallbackDelayed(AChoreographer_frameCallback cb, - AChoreographer_frameCallback64 cb64, - AChoreographer_vsyncCallback vsyncCallback, void* data, - nsecs_t delay) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - FrameCallback callback{cb, cb64, vsyncCallback, data, now + delay}; - { - std::lock_guard<std::mutex> _l{mLock}; - mFrameCallbacks.push(callback); - } - if (callback.dueTime <= now) { - if (std::this_thread::get_id() != mThreadId) { - if (mLooper != nullptr) { - Message m{MSG_SCHEDULE_VSYNC}; - mLooper->sendMessage(this, m); - } else { - scheduleVsync(); - } - } else { - scheduleVsync(); - } - } else { - if (mLooper != nullptr) { - Message m{MSG_SCHEDULE_CALLBACKS}; - mLooper->sendMessageDelayed(delay, this, m); - } else { - scheduleCallbacks(); - } - } -} - -void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) { - std::lock_guard<std::mutex> _l{mLock}; - for (const auto& callback : mRefreshRateCallbacks) { - // Don't re-add callbacks. - if (cb == callback.callback && data == callback.data) { - return; - } - } - mRefreshRateCallbacks.emplace_back( - RefreshRateCallback{.callback = cb, .data = data, .firstCallbackFired = false}); - bool needsRegistration = false; - { - std::lock_guard<std::mutex> _l2(gChoreographers.lock); - needsRegistration = !gChoreographers.registeredToDisplayManager; - } - if (needsRegistration) { - JNIEnv* env = getJniEnv(); - if (env == nullptr) { - ALOGW("JNI environment is unavailable, skipping registration"); - return; - } - jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz, - gJni.displayManagerGlobal.getInstance); - if (dmg == nullptr) { - ALOGW("DMS is not initialized yet: skipping registration"); - return; - } else { - env->CallVoidMethod(dmg, - gJni.displayManagerGlobal - .registerNativeChoreographerForRefreshRateCallbacks, - reinterpret_cast<int64_t>(this)); - env->DeleteLocalRef(dmg); - { - std::lock_guard<std::mutex> _l2(gChoreographers.lock); - gChoreographers.registeredToDisplayManager = true; - } - } - } else { - scheduleLatestConfigRequest(); - } -} - -void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, - void* data) { - std::lock_guard<std::mutex> _l{mLock}; - mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(), - mRefreshRateCallbacks.end(), - [&](const RefreshRateCallback& callback) { - return cb == callback.callback && - data == callback.data; - }), - mRefreshRateCallbacks.end()); -} - -void Choreographer::scheduleLatestConfigRequest() { - if (mLooper != nullptr) { - Message m{MSG_HANDLE_REFRESH_RATE_UPDATES}; - mLooper->sendMessage(this, m); - } else { - // If the looper thread is detached from Choreographer, then refresh rate - // changes will be handled in AChoreographer_handlePendingEvents, so we - // need to wake up the looper thread by writing to the write-end of the - // socket the looper is listening on. - // Fortunately, these events are small so sending packets across the - // socket should be atomic across processes. - DisplayEventReceiver::Event event; - event.header = - DisplayEventReceiver::Event::Header{DisplayEventReceiver::DISPLAY_EVENT_NULL, - PhysicalDisplayId::fromPort(0), systemTime()}; - injectEvent(event); - } -} - -void Choreographer::scheduleCallbacks() { - const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - nsecs_t dueTime; - { - std::lock_guard<std::mutex> _l{mLock}; - // If there are no pending callbacks then don't schedule a vsync - if (mFrameCallbacks.empty()) { - return; - } - dueTime = mFrameCallbacks.top().dueTime; - } - - if (dueTime <= now) { - ALOGV("choreographer %p ~ scheduling vsync", this); - scheduleVsync(); - return; - } -} - -void Choreographer::handleRefreshRateUpdates() { - std::vector<RefreshRateCallback> callbacks{}; - const nsecs_t pendingPeriod = gChoreographers.mLastKnownVsync.load(); - const nsecs_t lastPeriod = mLatestVsyncPeriod; - if (pendingPeriod > 0) { - mLatestVsyncPeriod = pendingPeriod; - } - { - std::lock_guard<std::mutex> _l{mLock}; - for (auto& cb : mRefreshRateCallbacks) { - callbacks.push_back(cb); - cb.firstCallbackFired = true; - } - } - - for (auto& cb : callbacks) { - if (!cb.firstCallbackFired || (pendingPeriod > 0 && pendingPeriod != lastPeriod)) { - cb.callback(pendingPeriod, cb.data); - } - } -} - -// TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the -// internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for -// the internal display implicitly. -void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t, - VsyncEventData vsyncEventData) { - std::vector<FrameCallback> callbacks{}; - { - std::lock_guard<std::mutex> _l{mLock}; - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) { - callbacks.push_back(mFrameCallbacks.top()); - mFrameCallbacks.pop(); - } - } - mLastVsyncEventData = vsyncEventData; - for (const auto& cb : callbacks) { - if (cb.vsyncCallback != nullptr) { - const ChoreographerFrameCallbackDataImpl frameCallbackData = - createFrameCallbackData(timestamp); - registerStartTime(); - mInCallback = true; - cb.vsyncCallback(reinterpret_cast<const AChoreographerFrameCallbackData*>( - &frameCallbackData), - cb.data); - mInCallback = false; - } else if (cb.callback64 != nullptr) { - cb.callback64(timestamp, cb.data); - } else if (cb.callback != nullptr) { - cb.callback(timestamp, cb.data); - } - } -} - -void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) { - ALOGV("choreographer %p ~ received hotplug event (displayId=%s, connected=%s), ignoring.", this, - to_string(displayId).c_str(), toString(connected)); -} - -void Choreographer::dispatchModeChanged(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t) { - LOG_ALWAYS_FATAL("dispatchModeChanged was called but was never registered"); -} - -void Choreographer::dispatchFrameRateOverrides(nsecs_t, PhysicalDisplayId, - std::vector<FrameRateOverride>) { - LOG_ALWAYS_FATAL("dispatchFrameRateOverrides was called but was never registered"); -} - -void Choreographer::dispatchNullEvent(nsecs_t, PhysicalDisplayId) { - ALOGV("choreographer %p ~ received null event.", this); - handleRefreshRateUpdates(); -} - -void Choreographer::handleMessage(const Message& message) { - switch (message.what) { - case MSG_SCHEDULE_CALLBACKS: - scheduleCallbacks(); - break; - case MSG_SCHEDULE_VSYNC: - scheduleVsync(); - break; - case MSG_HANDLE_REFRESH_RATE_UPDATES: - handleRefreshRateUpdates(); - break; - } -} - -int64_t Choreographer::getFrameInterval() const { - return mLastVsyncEventData.frameInterval; -} - -bool Choreographer::inCallback() const { - return mInCallback; -} - -ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const { - return {.frameTimeNanos = timestamp, - .vsyncEventData = mLastVsyncEventData, - .choreographer = this}; -} - -void Choreographer::registerStartTime() const { - std::scoped_lock _l(gChoreographers.lock); - for (VsyncEventData::FrameTimeline frameTimeline : mLastVsyncEventData.frameTimelines) { - while (gChoreographers.startTimes.size() >= kMaxStartTimes) { - gChoreographers.startTimes.erase(gChoreographers.startTimes.begin()); - } - gChoreographers.startTimes[frameTimeline.vsyncId] = systemTime(SYSTEM_TIME_MONOTONIC); - } -} +#undef LOG_TAG +#define LOG_TAG "AChoreographer" -} // namespace android using namespace android; static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) { @@ -488,27 +50,12 @@ AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl( // Glue for private C api namespace android { -void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) EXCLUDES(gChoreographers.lock) { - std::lock_guard<std::mutex> _l(gChoreographers.lock); - gChoreographers.mLastKnownVsync.store(vsyncPeriod); - for (auto c : gChoreographers.ptrs) { - c->scheduleLatestConfigRequest(); - } +void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) { + Choreographer::signalRefreshRateCallbacks(vsyncPeriod); } void AChoreographer_initJVM(JNIEnv* env) { - env->GetJavaVM(&gJni.jvm); - // Now we need to find the java classes. - jclass dmgClass = env->FindClass("android/hardware/display/DisplayManagerGlobal"); - gJni.displayManagerGlobal.clazz = static_cast<jclass>(env->NewGlobalRef(dmgClass)); - gJni.displayManagerGlobal.getInstance = - env->GetStaticMethodID(dmgClass, "getInstance", - "()Landroid/hardware/display/DisplayManagerGlobal;"); - gJni.displayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks = - env->GetMethodID(dmgClass, "registerNativeChoreographerForRefreshRateCallbacks", "()V"); - gJni.displayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks = - env->GetMethodID(dmgClass, "unregisterNativeChoreographerForRefreshRateCallbacks", - "()V"); + Choreographer::initJVM(env); } AChoreographer* AChoreographer_routeGetInstance() { @@ -583,13 +130,7 @@ int64_t AChoreographer_getFrameInterval(const AChoreographer* choreographer) { } int64_t AChoreographer_getStartTimeNanosForVsyncId(AVsyncId vsyncId) { - std::scoped_lock _l(gChoreographers.lock); - const auto iter = gChoreographers.startTimes.find(vsyncId); - if (iter == gChoreographers.startTimes.end()) { - ALOGW("Start time was not found for vsync id: %" PRId64, vsyncId); - return 0; - } - return iter->second; + return Choreographer::getStartTimeNanosForVsyncId(vsyncId); } } // namespace android diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp index 8d8a2bc244..70de33da12 100644 --- a/libs/nativedisplay/Android.bp +++ b/libs/nativedisplay/Android.bp @@ -56,6 +56,7 @@ cc_library_shared { ":libgui_frame_event_aidl", "AChoreographer.cpp", "ADisplay.cpp", + "Choreographer.cpp", "surfacetexture/surface_texture.cpp", "surfacetexture/SurfaceTexture.cpp", "surfacetexture/ImageConsumer.cpp", diff --git a/libs/nativedisplay/Choreographer.cpp b/libs/nativedisplay/Choreographer.cpp new file mode 100644 index 0000000000..01e9f04d15 --- /dev/null +++ b/libs/nativedisplay/Choreographer.cpp @@ -0,0 +1,390 @@ +/* + * Copyright 2022 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. + */ + +// #define LOG_NDEBUG 0 + +#include <jni.h> +#include <nativedisplay/Choreographer.h> + +#undef LOG_TAG +#define LOG_TAG "AChoreographer" + +namespace { +struct { + // Global JVM that is provided by zygote + JavaVM* jvm = nullptr; + struct { + jclass clazz; + jmethodID getInstance; + jmethodID registerNativeChoreographerForRefreshRateCallbacks; + jmethodID unregisterNativeChoreographerForRefreshRateCallbacks; + } displayManagerGlobal; +} gJni; + +// Gets the JNIEnv* for this thread, and performs one-off initialization if we +// have never retrieved a JNIEnv* pointer before. +JNIEnv* getJniEnv() { + if (gJni.jvm == nullptr) { + ALOGW("AChoreographer: No JVM provided!"); + return nullptr; + } + + JNIEnv* env = nullptr; + if (gJni.jvm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) { + ALOGD("Attaching thread to JVM for AChoreographer"); + JavaVMAttachArgs args = {JNI_VERSION_1_4, "AChoreographer_env", NULL}; + jint attachResult = gJni.jvm->AttachCurrentThreadAsDaemon(&env, (void*)&args); + if (attachResult != JNI_OK) { + ALOGE("Unable to attach thread. Error: %d", attachResult); + return nullptr; + } + } + if (env == nullptr) { + ALOGW("AChoreographer: No JNI env available!"); + } + return env; +} + +inline const char* toString(bool value) { + return value ? "true" : "false"; +} +} // namespace + +namespace android { + +Choreographer::Context Choreographer::gChoreographers; + +static thread_local Choreographer* gChoreographer; + +void Choreographer::initJVM(JNIEnv* env) { + env->GetJavaVM(&gJni.jvm); + // Now we need to find the java classes. + jclass dmgClass = env->FindClass("android/hardware/display/DisplayManagerGlobal"); + gJni.displayManagerGlobal.clazz = static_cast<jclass>(env->NewGlobalRef(dmgClass)); + gJni.displayManagerGlobal.getInstance = + env->GetStaticMethodID(dmgClass, "getInstance", + "()Landroid/hardware/display/DisplayManagerGlobal;"); + gJni.displayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks = + env->GetMethodID(dmgClass, "registerNativeChoreographerForRefreshRateCallbacks", "()V"); + gJni.displayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks = + env->GetMethodID(dmgClass, "unregisterNativeChoreographerForRefreshRateCallbacks", + "()V"); +} + +Choreographer* Choreographer::getForThread() { + if (gChoreographer == nullptr) { + sp<Looper> looper = Looper::getForThread(); + if (!looper.get()) { + ALOGW("No looper prepared for thread"); + return nullptr; + } + gChoreographer = new Choreographer(looper); + status_t result = gChoreographer->initialize(); + if (result != OK) { + ALOGW("Failed to initialize"); + return nullptr; + } + } + return gChoreographer; +} + +Choreographer::Choreographer(const sp<Looper>& looper) + : DisplayEventDispatcher(looper, gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp), + mLooper(looper), + mThreadId(std::this_thread::get_id()) { + std::lock_guard<std::mutex> _l(gChoreographers.lock); + gChoreographers.ptrs.push_back(this); +} + +Choreographer::~Choreographer() { + std::lock_guard<std::mutex> _l(gChoreographers.lock); + gChoreographers.ptrs.erase(std::remove_if(gChoreographers.ptrs.begin(), + gChoreographers.ptrs.end(), + [=](Choreographer* c) { return c == this; }), + gChoreographers.ptrs.end()); + // Only poke DisplayManagerGlobal to unregister if we previously registered + // callbacks. + if (gChoreographers.ptrs.empty() && gChoreographers.registeredToDisplayManager) { + gChoreographers.registeredToDisplayManager = false; + JNIEnv* env = getJniEnv(); + if (env == nullptr) { + ALOGW("JNI environment is unavailable, skipping choreographer cleanup"); + return; + } + jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz, + gJni.displayManagerGlobal.getInstance); + if (dmg == nullptr) { + ALOGW("DMS is not initialized yet, skipping choreographer cleanup"); + } else { + env->CallVoidMethod(dmg, + gJni.displayManagerGlobal + .unregisterNativeChoreographerForRefreshRateCallbacks); + env->DeleteLocalRef(dmg); + } + } +} + +void Choreographer::postFrameCallbackDelayed(AChoreographer_frameCallback cb, + AChoreographer_frameCallback64 cb64, + AChoreographer_vsyncCallback vsyncCallback, void* data, + nsecs_t delay) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + FrameCallback callback{cb, cb64, vsyncCallback, data, now + delay}; + { + std::lock_guard<std::mutex> _l{mLock}; + mFrameCallbacks.push(callback); + } + if (callback.dueTime <= now) { + if (std::this_thread::get_id() != mThreadId) { + if (mLooper != nullptr) { + Message m{MSG_SCHEDULE_VSYNC}; + mLooper->sendMessage(this, m); + } else { + scheduleVsync(); + } + } else { + scheduleVsync(); + } + } else { + if (mLooper != nullptr) { + Message m{MSG_SCHEDULE_CALLBACKS}; + mLooper->sendMessageDelayed(delay, this, m); + } else { + scheduleCallbacks(); + } + } +} + +void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) { + std::lock_guard<std::mutex> _l{mLock}; + for (const auto& callback : mRefreshRateCallbacks) { + // Don't re-add callbacks. + if (cb == callback.callback && data == callback.data) { + return; + } + } + mRefreshRateCallbacks.emplace_back( + RefreshRateCallback{.callback = cb, .data = data, .firstCallbackFired = false}); + bool needsRegistration = false; + { + std::lock_guard<std::mutex> _l2(gChoreographers.lock); + needsRegistration = !gChoreographers.registeredToDisplayManager; + } + if (needsRegistration) { + JNIEnv* env = getJniEnv(); + if (env == nullptr) { + ALOGW("JNI environment is unavailable, skipping registration"); + return; + } + jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz, + gJni.displayManagerGlobal.getInstance); + if (dmg == nullptr) { + ALOGW("DMS is not initialized yet: skipping registration"); + return; + } else { + env->CallVoidMethod(dmg, + gJni.displayManagerGlobal + .registerNativeChoreographerForRefreshRateCallbacks, + reinterpret_cast<int64_t>(this)); + env->DeleteLocalRef(dmg); + { + std::lock_guard<std::mutex> _l2(gChoreographers.lock); + gChoreographers.registeredToDisplayManager = true; + } + } + } else { + scheduleLatestConfigRequest(); + } +} + +void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, + void* data) { + std::lock_guard<std::mutex> _l{mLock}; + mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(), + mRefreshRateCallbacks.end(), + [&](const RefreshRateCallback& callback) { + return cb == callback.callback && + data == callback.data; + }), + mRefreshRateCallbacks.end()); +} + +void Choreographer::scheduleLatestConfigRequest() { + if (mLooper != nullptr) { + Message m{MSG_HANDLE_REFRESH_RATE_UPDATES}; + mLooper->sendMessage(this, m); + } else { + // If the looper thread is detached from Choreographer, then refresh rate + // changes will be handled in AChoreographer_handlePendingEvents, so we + // need to wake up the looper thread by writing to the write-end of the + // socket the looper is listening on. + // Fortunately, these events are small so sending packets across the + // socket should be atomic across processes. + DisplayEventReceiver::Event event; + event.header = + DisplayEventReceiver::Event::Header{DisplayEventReceiver::DISPLAY_EVENT_NULL, + PhysicalDisplayId::fromPort(0), systemTime()}; + injectEvent(event); + } +} + +void Choreographer::scheduleCallbacks() { + const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t dueTime; + { + std::lock_guard<std::mutex> _l{mLock}; + // If there are no pending callbacks then don't schedule a vsync + if (mFrameCallbacks.empty()) { + return; + } + dueTime = mFrameCallbacks.top().dueTime; + } + + if (dueTime <= now) { + ALOGV("choreographer %p ~ scheduling vsync", this); + scheduleVsync(); + return; + } +} + +void Choreographer::handleRefreshRateUpdates() { + std::vector<RefreshRateCallback> callbacks{}; + const nsecs_t pendingPeriod = gChoreographers.mLastKnownVsync.load(); + const nsecs_t lastPeriod = mLatestVsyncPeriod; + if (pendingPeriod > 0) { + mLatestVsyncPeriod = pendingPeriod; + } + { + std::lock_guard<std::mutex> _l{mLock}; + for (auto& cb : mRefreshRateCallbacks) { + callbacks.push_back(cb); + cb.firstCallbackFired = true; + } + } + + for (auto& cb : callbacks) { + if (!cb.firstCallbackFired || (pendingPeriod > 0 && pendingPeriod != lastPeriod)) { + cb.callback(pendingPeriod, cb.data); + } + } +} + +void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t, + VsyncEventData vsyncEventData) { + std::vector<FrameCallback> callbacks{}; + { + std::lock_guard<std::mutex> _l{mLock}; + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) { + callbacks.push_back(mFrameCallbacks.top()); + mFrameCallbacks.pop(); + } + } + mLastVsyncEventData = vsyncEventData; + for (const auto& cb : callbacks) { + if (cb.vsyncCallback != nullptr) { + const ChoreographerFrameCallbackDataImpl frameCallbackData = + createFrameCallbackData(timestamp); + registerStartTime(); + mInCallback = true; + cb.vsyncCallback(reinterpret_cast<const AChoreographerFrameCallbackData*>( + &frameCallbackData), + cb.data); + mInCallback = false; + } else if (cb.callback64 != nullptr) { + cb.callback64(timestamp, cb.data); + } else if (cb.callback != nullptr) { + cb.callback(timestamp, cb.data); + } + } +} + +void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) { + ALOGV("choreographer %p ~ received hotplug event (displayId=%s, connected=%s), ignoring.", this, + to_string(displayId).c_str(), toString(connected)); +} + +void Choreographer::dispatchModeChanged(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t) { + LOG_ALWAYS_FATAL("dispatchModeChanged was called but was never registered"); +} + +void Choreographer::dispatchFrameRateOverrides(nsecs_t, PhysicalDisplayId, + std::vector<FrameRateOverride>) { + LOG_ALWAYS_FATAL("dispatchFrameRateOverrides was called but was never registered"); +} + +void Choreographer::dispatchNullEvent(nsecs_t, PhysicalDisplayId) { + ALOGV("choreographer %p ~ received null event.", this); + handleRefreshRateUpdates(); +} + +void Choreographer::handleMessage(const Message& message) { + switch (message.what) { + case MSG_SCHEDULE_CALLBACKS: + scheduleCallbacks(); + break; + case MSG_SCHEDULE_VSYNC: + scheduleVsync(); + break; + case MSG_HANDLE_REFRESH_RATE_UPDATES: + handleRefreshRateUpdates(); + break; + } +} + +int64_t Choreographer::getFrameInterval() const { + return mLastVsyncEventData.frameInterval; +} + +bool Choreographer::inCallback() const { + return mInCallback; +} + +ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const { + return {.frameTimeNanos = timestamp, + .vsyncEventData = mLastVsyncEventData, + .choreographer = this}; +} + +void Choreographer::registerStartTime() const { + std::scoped_lock _l(gChoreographers.lock); + for (VsyncEventData::FrameTimeline frameTimeline : mLastVsyncEventData.frameTimelines) { + while (gChoreographers.startTimes.size() >= kMaxStartTimes) { + gChoreographers.startTimes.erase(gChoreographers.startTimes.begin()); + } + gChoreographers.startTimes[frameTimeline.vsyncId] = systemTime(SYSTEM_TIME_MONOTONIC); + } +} + +void Choreographer::signalRefreshRateCallbacks(nsecs_t vsyncPeriod) { + std::lock_guard<std::mutex> _l(gChoreographers.lock); + gChoreographers.mLastKnownVsync.store(vsyncPeriod); + for (auto c : gChoreographers.ptrs) { + c->scheduleLatestConfigRequest(); + } +} + +int64_t Choreographer::getStartTimeNanosForVsyncId(AVsyncId vsyncId) { + std::scoped_lock _l(gChoreographers.lock); + const auto iter = gChoreographers.startTimes.find(vsyncId); + if (iter == gChoreographers.startTimes.end()) { + ALOGW("Start time was not found for vsync id: %" PRId64, vsyncId); + return 0; + } + return iter->second; +} + +} // namespace android
\ No newline at end of file diff --git a/libs/nativedisplay/include/nativedisplay/Choreographer.h b/libs/nativedisplay/include/nativedisplay/Choreographer.h new file mode 100644 index 0000000000..bb63f291f9 --- /dev/null +++ b/libs/nativedisplay/include/nativedisplay/Choreographer.h @@ -0,0 +1,138 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <gui/DisplayEventDispatcher.h> +#include <private/android/choreographer.h> +#include <utils/Looper.h> + +#include <mutex> +#include <queue> +#include <thread> + +namespace android { +using gui::VsyncEventData; + +struct FrameCallback { + AChoreographer_frameCallback callback; + AChoreographer_frameCallback64 callback64; + AChoreographer_vsyncCallback vsyncCallback; + void* data; + nsecs_t dueTime; + + inline bool operator<(const FrameCallback& rhs) const { + // Note that this is intentionally flipped because we want callbacks due sooner to be at + // the head of the queue + return dueTime > rhs.dueTime; + } +}; + +struct RefreshRateCallback { + AChoreographer_refreshRateCallback callback; + void* data; + bool firstCallbackFired = false; +}; + +class Choreographer; + +/** + * Implementation of AChoreographerFrameCallbackData. + */ +struct ChoreographerFrameCallbackDataImpl { + int64_t frameTimeNanos{0}; + + VsyncEventData vsyncEventData; + + const Choreographer* choreographer; +}; + +class Choreographer : public DisplayEventDispatcher, public MessageHandler { +public: + struct Context { + std::mutex lock; + std::vector<Choreographer*> ptrs GUARDED_BY(lock); + std::map<AVsyncId, int64_t> startTimes GUARDED_BY(lock); + bool registeredToDisplayManager GUARDED_BY(lock) = false; + + std::atomic<nsecs_t> mLastKnownVsync = -1; + }; + static Context gChoreographers; + + explicit Choreographer(const sp<Looper>& looper) EXCLUDES(gChoreographers.lock); + void postFrameCallbackDelayed(AChoreographer_frameCallback cb, + AChoreographer_frameCallback64 cb64, + AChoreographer_vsyncCallback vsyncCallback, void* data, + nsecs_t delay); + void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) + EXCLUDES(gChoreographers.lock); + void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data); + // Drains the queue of pending vsync periods and dispatches refresh rate + // updates to callbacks. + // The assumption is that this method is only called on a single + // processing thread, either by looper or by AChoreographer_handleEvents + void handleRefreshRateUpdates(); + void scheduleLatestConfigRequest(); + + enum { + MSG_SCHEDULE_CALLBACKS = 0, + MSG_SCHEDULE_VSYNC = 1, + MSG_HANDLE_REFRESH_RATE_UPDATES = 2, + }; + virtual void handleMessage(const Message& message) override; + + static void initJVM(JNIEnv* env); + static Choreographer* getForThread(); + static void signalRefreshRateCallbacks(nsecs_t vsyncPeriod) EXCLUDES(gChoreographers.lock); + static int64_t getStartTimeNanosForVsyncId(AVsyncId vsyncId) EXCLUDES(gChoreographers.lock); + virtual ~Choreographer() override EXCLUDES(gChoreographers.lock); + int64_t getFrameInterval() const; + bool inCallback() const; + +private: + Choreographer(const Choreographer&) = delete; + + void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count, + VsyncEventData vsyncEventData) override; + void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override; + void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId, + nsecs_t vsyncPeriod) override; + void dispatchNullEvent(nsecs_t, PhysicalDisplayId) override; + void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId, + std::vector<FrameRateOverride> overrides) override; + + void scheduleCallbacks(); + + ChoreographerFrameCallbackDataImpl createFrameCallbackData(nsecs_t timestamp) const; + void registerStartTime() const; + + std::mutex mLock; + // Protected by mLock + std::priority_queue<FrameCallback> mFrameCallbacks; + std::vector<RefreshRateCallback> mRefreshRateCallbacks; + + nsecs_t mLatestVsyncPeriod = -1; + VsyncEventData mLastVsyncEventData; + bool mInCallback = false; + + const sp<Looper> mLooper; + const std::thread::id mThreadId; + + // Approximation of num_threads_using_choreographer * num_frames_of_history with leeway. + static constexpr size_t kMaxStartTimes = 250; +}; + +} // namespace android
\ No newline at end of file diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 180dce9ed7..bbafbffae0 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -702,6 +702,14 @@ uint32_t AHardwareBuffer_convertToPixelFormat(uint32_t ahardwarebuffer_format) { return ahardwarebuffer_format; } +int32_t AHardwareBuffer_getDataSpace(AHardwareBuffer* buffer) { + GraphicBuffer* gb = AHardwareBuffer_to_GraphicBuffer(buffer); + auto& mapper = GraphicBufferMapper::get(); + ui::Dataspace dataspace = ui::Dataspace::UNKNOWN; + mapper.getDataspace(gb->handle, &dataspace); + return static_cast<int32_t>(dataspace); +} + uint64_t AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage) { using android::hardware::graphics::common::V1_1::BufferUsage; static_assert(AHARDWAREBUFFER_USAGE_CPU_READ_NEVER == (uint64_t)BufferUsage::CPU_READ_NEVER, diff --git a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h index ddfd1d1918..6d3d295a0c 100644 --- a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h +++ b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h @@ -52,6 +52,11 @@ uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t format); // convert HAL format to AHardwareBuffer format (note: this is a no-op) uint32_t AHardwareBuffer_convertToPixelFormat(uint32_t format); +// retrieves a dataspace from the AHardwareBuffer metadata, if the device +// support gralloc metadata. Returns UNKNOWN if gralloc metadata is not +// supported. +int32_t AHardwareBuffer_getDataSpace(AHardwareBuffer* buffer); + // convert AHardwareBuffer usage bits to HAL usage bits (note: this is a no-op) uint64_t AHardwareBuffer_convertFromGrallocUsageBits(uint64_t usage); diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 76d23fab1d..e1ee490dc4 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -71,6 +71,7 @@ LIBNATIVEWINDOW_PLATFORM { android::AHardwareBuffer_convertToPixelFormat*; android::AHardwareBuffer_convertFromGrallocUsageBits*; android::AHardwareBuffer_convertToGrallocUsageBits*; + android::AHardwareBuffer_getDataSpace*; android::AHardwareBuffer_to_GraphicBuffer*; android::AHardwareBuffer_to_ANativeWindowBuffer*; android::AHardwareBuffer_from_GraphicBuffer*; diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp index 78f692bb0c..2278d391b5 100644 --- a/libs/sensor/ISensorServer.cpp +++ b/libs/sensor/ISensorServer.cpp @@ -42,6 +42,7 @@ enum { GET_DYNAMIC_SENSOR_LIST, CREATE_SENSOR_DIRECT_CONNECTION, SET_OPERATION_PARAMETER, + GET_RUNTIME_SENSOR_LIST, }; class BpSensorServer : public BpInterface<ISensorServer> @@ -90,6 +91,25 @@ public: return v; } + virtual Vector<Sensor> getRuntimeSensorList(const String16& opPackageName, int deviceId) + { + Parcel data, reply; + data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); + data.writeString16(opPackageName); + data.writeInt32(deviceId); + remote()->transact(GET_RUNTIME_SENSOR_LIST, data, &reply); + Sensor s; + Vector<Sensor> v; + uint32_t n = reply.readUint32(); + v.setCapacity(n); + while (n) { + n--; + reply.read(s); + v.add(s); + } + return v; + } + virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName, int mode, const String16& opPackageName, const String16& attributionTag) { @@ -194,6 +214,18 @@ status_t BnSensorServer::onTransact( } return NO_ERROR; } + case GET_RUNTIME_SENSOR_LIST: { + CHECK_INTERFACE(ISensorServer, data, reply); + const String16& opPackageName = data.readString16(); + const int deviceId = data.readInt32(); + Vector<Sensor> v(getRuntimeSensorList(opPackageName, deviceId)); + size_t n = v.size(); + reply->writeUint32(static_cast<uint32_t>(n)); + for (size_t i = 0; i < n; i++) { + reply->write(v[i]); + } + return NO_ERROR; + } case CREATE_SENSOR_DIRECT_CONNECTION: { CHECK_INTERFACE(ISensorServer, data, reply); const String16& opPackageName = data.readString16(); diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp index 0ba9704263..27482768f2 100644 --- a/libs/sensor/SensorManager.cpp +++ b/libs/sensor/SensorManager.cpp @@ -201,6 +201,19 @@ ssize_t SensorManager::getDynamicSensorList(Vector<Sensor> & dynamicSensors) { return static_cast<ssize_t>(count); } +ssize_t SensorManager::getRuntimeSensorList(int deviceId, Vector<Sensor>& runtimeSensors) { + Mutex::Autolock _l(mLock); + status_t err = assertStateLocked(); + if (err < 0) { + return static_cast<ssize_t>(err); + } + + runtimeSensors = mSensorServer->getRuntimeSensorList(mOpPackageName, deviceId); + size_t count = runtimeSensors.size(); + + return static_cast<ssize_t>(count); +} + ssize_t SensorManager::getDynamicSensorList(Sensor const* const** list) { Mutex::Autolock _l(mLock); status_t err = assertStateLocked(); diff --git a/libs/sensor/include/sensor/ISensorServer.h b/libs/sensor/include/sensor/ISensorServer.h index ce5c672da0..3295196ac4 100644 --- a/libs/sensor/include/sensor/ISensorServer.h +++ b/libs/sensor/include/sensor/ISensorServer.h @@ -43,6 +43,7 @@ public: virtual Vector<Sensor> getSensorList(const String16& opPackageName) = 0; virtual Vector<Sensor> getDynamicSensorList(const String16& opPackageName) = 0; + virtual Vector<Sensor> getRuntimeSensorList(const String16& opPackageName, int deviceId) = 0; virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName, int mode, const String16& opPackageName, const String16& attributionTag) = 0; diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h index 8d0a8a45d9..0798da292a 100644 --- a/libs/sensor/include/sensor/SensorManager.h +++ b/libs/sensor/include/sensor/SensorManager.h @@ -59,6 +59,7 @@ public: ssize_t getSensorList(Sensor const* const** list); ssize_t getDynamicSensorList(Vector<Sensor>& list); ssize_t getDynamicSensorList(Sensor const* const** list); + ssize_t getRuntimeSensorList(int deviceId, Vector<Sensor>& list); Sensor const* getDefaultSensor(int type); sp<SensorEventQueue> createEventQueue( String8 packageName = String8(""), int mode = 0, String16 attributionTag = String16("")); diff --git a/libs/shaders/include/shaders/shaders.h b/libs/shaders/include/shaders/shaders.h index 2a4a370078..42b0cc131c 100644 --- a/libs/shaders/include/shaders/shaders.h +++ b/libs/shaders/include/shaders/shaders.h @@ -68,6 +68,9 @@ struct LinearEffect { // fakeInputDataspace is used to essentially masquerade the input dataspace to be the output // dataspace for correct conversion to linear colors. ui::Dataspace fakeInputDataspace = ui::Dataspace::UNKNOWN; + + enum SkSLType { Shader, ColorFilter }; + SkSLType type = Shader; }; static inline bool operator==(const LinearEffect& lhs, const LinearEffect& rhs) { @@ -96,6 +99,10 @@ struct LinearEffectHasher { // 2. Apply color transform matrices in linear space std::string buildLinearEffectSkSL(const LinearEffect& linearEffect); +// Generates a shader string that applies color transforms in linear space. +// This is intended to be plugged into an SkColorFilter +std::string buildLinearEffectSkSLForColorFilter(const LinearEffect& linearEffect); + // Generates a list of uniforms to set on the LinearEffect shader above. std::vector<tonemap::ShaderUniform> buildLinearEffectUniforms( const LinearEffect& linearEffect, const mat4& colorTransform, float maxDisplayLuminance, diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp index f80e93f6f8..a3c403e551 100644 --- a/libs/shaders/shaders.cpp +++ b/libs/shaders/shaders.cpp @@ -386,12 +386,23 @@ void generateOETF(ui::Dataspace dataspace, std::string& shader) { } } -void generateEffectiveOOTF(bool undoPremultipliedAlpha, std::string& shader) { - shader.append(R"( - uniform shader child; - half4 main(float2 xy) { - float4 c = float4(child.eval(xy)); - )"); +void generateEffectiveOOTF(bool undoPremultipliedAlpha, LinearEffect::SkSLType type, + std::string& shader) { + switch (type) { + case LinearEffect::SkSLType::ColorFilter: + shader.append(R"( + half4 main(half4 inputColor) { + float4 c = float4(inputColor); + )"); + break; + case LinearEffect::SkSLType::Shader: + shader.append(R"( + uniform shader child; + half4 main(float2 xy) { + float4 c = float4(child.eval(xy)); + )"); + break; + } if (undoPremultipliedAlpha) { shader.append(R"( c.rgb = c.rgb / (c.a + 0.0019); @@ -459,7 +470,7 @@ std::string buildLinearEffectSkSL(const LinearEffect& linearEffect) { generateXYZTransforms(shaderString); generateOOTF(linearEffect.inputDataspace, linearEffect.outputDataspace, shaderString); generateOETF(linearEffect.outputDataspace, shaderString); - generateEffectiveOOTF(linearEffect.undoPremultipliedAlpha, shaderString); + generateEffectiveOOTF(linearEffect.undoPremultipliedAlpha, linearEffect.type, shaderString); return shaderString; } diff --git a/libs/ui/include/ui/Rotation.h b/libs/ui/include/ui/Rotation.h index 83d431dea3..c1d60f4f6c 100644 --- a/libs/ui/include/ui/Rotation.h +++ b/libs/ui/include/ui/Rotation.h @@ -20,7 +20,14 @@ namespace android::ui { -enum class Rotation { Rotation0 = 0, Rotation90 = 1, Rotation180 = 2, Rotation270 = 3 }; +enum class Rotation { + Rotation0 = 0, + Rotation90 = 1, + Rotation180 = 2, + Rotation270 = 3, + + ftl_last = Rotation270 +}; // Equivalent to Surface.java constants. constexpr auto ROTATION_0 = Rotation::Rotation0; diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp deleted file mode 100644 index 0bda7987a0..0000000000 --- a/libs/vr/libbufferhubqueue/Android.bp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (C) 2016 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_native_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_native_license"], -} - -sourceFiles = [ - "buffer_hub_queue_client.cpp", - "buffer_hub_queue_parcelable.cpp", -] - -includeFiles = [ - "include", -] - -staticLibraries = [ - "libbufferhub", -] - -sharedLibraries = [ - "libbinder", - "libcutils", - "liblog", - "libui", - "libutils", - "libpdx_default_transport", -] - -headerLibraries = [ - "libdvr_headers", - "libnativebase_headers", -] - -cc_library_shared { - name: "libbufferhubqueue", - cflags: [ - "-DLOG_TAG=\"libbufferhubqueue\"", - "-DTRACE=0", - "-DATRACE_TAG=ATRACE_TAG_GRAPHICS", - "-Wall", - "-Werror", - "-Wno-format", - "-Wno-unused-parameter", - "-Wno-unused-variable", - ], - srcs: sourceFiles, - export_include_dirs: includeFiles, - export_static_lib_headers: staticLibraries, - static_libs: staticLibraries, - shared_libs: sharedLibraries, - header_libs: headerLibraries, -} - -subdirs = ["benchmarks", "tests"] diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp deleted file mode 100644 index 2d3fa4aec0..0000000000 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp +++ /dev/null @@ -1,823 +0,0 @@ -#include "include/private/dvr/buffer_hub_queue_client.h" - -#include <inttypes.h> -#include <log/log.h> -#include <poll.h> -#include <sys/epoll.h> - -#include <array> - -#include <pdx/default_transport/client_channel.h> -#include <pdx/default_transport/client_channel_factory.h> -#include <pdx/file_handle.h> -#include <pdx/trace.h> - -#define RETRY_EINTR(fnc_call) \ - ([&]() -> decltype(fnc_call) { \ - decltype(fnc_call) result; \ - do { \ - result = (fnc_call); \ - } while (result == -1 && errno == EINTR); \ - return result; \ - })() - -using android::pdx::ErrorStatus; -using android::pdx::LocalChannelHandle; -using android::pdx::LocalHandle; -using android::pdx::Status; - -namespace android { -namespace dvr { - -namespace { - -std::pair<int32_t, int32_t> Unstuff(uint64_t value) { - return {static_cast<int32_t>(value >> 32), - static_cast<int32_t>(value & ((1ull << 32) - 1))}; -} - -uint64_t Stuff(int32_t a, int32_t b) { - const uint32_t ua = static_cast<uint32_t>(a); - const uint32_t ub = static_cast<uint32_t>(b); - return (static_cast<uint64_t>(ua) << 32) | static_cast<uint64_t>(ub); -} - -} // anonymous namespace - -BufferHubQueue::BufferHubQueue(LocalChannelHandle channel_handle) - : Client{pdx::default_transport::ClientChannel::Create( - std::move(channel_handle))} { - Initialize(); -} - -BufferHubQueue::BufferHubQueue(const std::string& endpoint_path) - : Client{ - pdx::default_transport::ClientChannelFactory::Create(endpoint_path)} { - Initialize(); -} - -void BufferHubQueue::Initialize() { - int ret = epoll_fd_.Create(); - if (ret < 0) { - ALOGE("BufferHubQueue::BufferHubQueue: Failed to create epoll fd: %s", - strerror(-ret)); - return; - } - - epoll_event event = { - .events = EPOLLIN | EPOLLET, - .data = {.u64 = Stuff(-1, BufferHubQueue::kEpollQueueEventIndex)}}; - ret = epoll_fd_.Control(EPOLL_CTL_ADD, event_fd(), &event); - if (ret < 0) { - ALOGE("%s: Failed to add event fd to epoll set: %s", __FUNCTION__, - strerror(-ret)); - } -} - -Status<void> BufferHubQueue::ImportQueue() { - auto status = InvokeRemoteMethod<BufferHubRPC::GetQueueInfo>(); - if (!status) { - ALOGE("%s: Failed to import queue: %s", __FUNCTION__, - status.GetErrorMessage().c_str()); - return ErrorStatus(status.error()); - } else { - SetupQueue(status.get()); - return {}; - } -} - -void BufferHubQueue::SetupQueue(const QueueInfo& queue_info) { - is_async_ = queue_info.producer_config.is_async; - default_width_ = queue_info.producer_config.default_width; - default_height_ = queue_info.producer_config.default_height; - default_format_ = queue_info.producer_config.default_format; - user_metadata_size_ = queue_info.producer_config.user_metadata_size; - id_ = queue_info.id; -} - -std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateConsumerQueue() { - if (auto status = CreateConsumerQueueHandle(/*silent*/ false)) - return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take())); - else - return nullptr; -} - -std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateSilentConsumerQueue() { - if (auto status = CreateConsumerQueueHandle(/*silent*/ true)) - return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take())); - else - return nullptr; -} - -Status<LocalChannelHandle> BufferHubQueue::CreateConsumerQueueHandle( - bool silent) { - auto status = InvokeRemoteMethod<BufferHubRPC::CreateConsumerQueue>(silent); - if (!status) { - ALOGE( - "BufferHubQueue::CreateConsumerQueue: Failed to create consumer queue: " - "%s", - status.GetErrorMessage().c_str()); - return ErrorStatus(status.error()); - } - - return status; -} - -pdx::Status<ConsumerQueueParcelable> -BufferHubQueue::CreateConsumerQueueParcelable(bool silent) { - auto status = CreateConsumerQueueHandle(silent); - if (!status) - return status.error_status(); - - // A temporary consumer queue client to pull its channel parcelable. - auto consumer_queue = - std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take())); - ConsumerQueueParcelable queue_parcelable( - consumer_queue->GetChannel()->TakeChannelParcelable()); - - if (!queue_parcelable.IsValid()) { - ALOGE("%s: Failed to create consumer queue parcelable.", __FUNCTION__); - return ErrorStatus(EINVAL); - } - - return {std::move(queue_parcelable)}; -} - -bool BufferHubQueue::WaitForBuffers(int timeout) { - ATRACE_NAME("BufferHubQueue::WaitForBuffers"); - std::array<epoll_event, kMaxEvents> events; - - // Loop at least once to check for hangups. - do { - ALOGD_IF( - TRACE, - "BufferHubQueue::WaitForBuffers: queue_id=%d count=%zu capacity=%zu", - id(), count(), capacity()); - - // If there is already a buffer then just check for hangup without waiting. - const int ret = epoll_fd_.Wait(events.data(), events.size(), - count() == 0 ? timeout : 0); - - if (ret == 0) { - ALOGI_IF(TRACE, - "BufferHubQueue::WaitForBuffers: No events before timeout: " - "queue_id=%d", - id()); - return count() != 0; - } - - if (ret < 0 && ret != -EINTR) { - ALOGE("%s: Failed to wait for buffers: %s", __FUNCTION__, strerror(-ret)); - return false; - } - - const int num_events = ret; - - // A BufferQueue's epoll fd tracks N+1 events, where there are N events, - // one for each buffer in the queue, and one extra event for the queue - // client itself. - for (int i = 0; i < num_events; i++) { - int32_t event_fd; - int32_t index; - std::tie(event_fd, index) = Unstuff(events[i].data.u64); - - PDX_TRACE_FORMAT( - "epoll_event|queue_id=%d;num_events=%d;event_index=%d;event_fd=%d;" - "slot=%d|", - id(), num_events, i, event_fd, index); - - ALOGD_IF(TRACE, - "BufferHubQueue::WaitForBuffers: event %d: event_fd=%d index=%d", - i, event_fd, index); - - if (is_buffer_event_index(index)) { - HandleBufferEvent(static_cast<size_t>(index), event_fd, - events[i].events); - } else if (is_queue_event_index(index)) { - HandleQueueEvent(events[i].events); - } else { - ALOGW( - "BufferHubQueue::WaitForBuffers: Unknown event type event_fd=%d " - "index=%d", - event_fd, index); - } - } - } while (count() == 0 && capacity() > 0 && !hung_up()); - - return count() != 0; -} - -Status<void> BufferHubQueue::HandleBufferEvent(size_t slot, int event_fd, - int poll_events) { - ATRACE_NAME("BufferHubQueue::HandleBufferEvent"); - if (!buffers_[slot]) { - ALOGW("BufferHubQueue::HandleBufferEvent: Invalid buffer slot: %zu", slot); - return ErrorStatus(ENOENT); - } - - auto status = buffers_[slot]->GetEventMask(poll_events); - if (!status) { - ALOGW("BufferHubQueue::HandleBufferEvent: Failed to get event mask: %s", - status.GetErrorMessage().c_str()); - return status.error_status(); - } - - const int events = status.get(); - PDX_TRACE_FORMAT( - "buffer|queue_id=%d;buffer_id=%d;slot=%zu;event_fd=%d;poll_events=%x;" - "events=%d|", - id(), buffers_[slot]->id(), slot, event_fd, poll_events, events); - - if (events & EPOLLIN) { - return Enqueue({buffers_[slot], slot, buffers_[slot]->GetQueueIndex()}); - } else if (events & EPOLLHUP) { - ALOGW( - "BufferHubQueue::HandleBufferEvent: Received EPOLLHUP event: slot=%zu " - "event_fd=%d buffer_id=%d", - slot, buffers_[slot]->event_fd(), buffers_[slot]->id()); - return RemoveBuffer(slot); - } else { - ALOGW( - "BufferHubQueue::HandleBufferEvent: Unknown event, slot=%zu, epoll " - "events=%d", - slot, events); - } - - return {}; -} - -Status<void> BufferHubQueue::HandleQueueEvent(int poll_event) { - ATRACE_NAME("BufferHubQueue::HandleQueueEvent"); - auto status = GetEventMask(poll_event); - if (!status) { - ALOGW("BufferHubQueue::HandleQueueEvent: Failed to get event mask: %s", - status.GetErrorMessage().c_str()); - return status.error_status(); - } - - const int events = status.get(); - if (events & EPOLLIN) { - // Note that after buffer imports, if |count()| still returns 0, epoll - // wait will be tried again to acquire the newly imported buffer. - auto buffer_status = OnBufferAllocated(); - if (!buffer_status) { - ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, - buffer_status.GetErrorMessage().c_str()); - } - } else if (events & EPOLLHUP) { - ALOGD_IF(TRACE, "%s: hang up event!", __FUNCTION__); - hung_up_ = true; - } else { - ALOGW("%s: Unknown epoll events=%x", __FUNCTION__, events); - } - - return {}; -} - -Status<void> BufferHubQueue::AddBuffer( - const std::shared_ptr<BufferHubBase>& buffer, size_t slot) { - ALOGD_IF(TRACE, "%s: buffer_id=%d slot=%zu", __FUNCTION__, buffer->id(), - slot); - - if (is_full()) { - ALOGE("%s: queue is at maximum capacity: %zu", __FUNCTION__, capacity_); - return ErrorStatus(E2BIG); - } - - if (buffers_[slot]) { - // Replace the buffer if the slot is occupied. This could happen when the - // producer side replaced the slot with a newly allocated buffer. Remove the - // buffer before setting up with the new one. - auto remove_status = RemoveBuffer(slot); - if (!remove_status) - return remove_status.error_status(); - } - - for (const auto& event_source : buffer->GetEventSources()) { - epoll_event event = {.events = event_source.event_mask | EPOLLET, - .data = {.u64 = Stuff(buffer->event_fd(), slot)}}; - const int ret = - epoll_fd_.Control(EPOLL_CTL_ADD, event_source.event_fd, &event); - if (ret < 0) { - ALOGE("%s: Failed to add buffer to epoll set: %s", __FUNCTION__, - strerror(-ret)); - return ErrorStatus(-ret); - } - } - - buffers_[slot] = buffer; - capacity_++; - return {}; -} - -Status<void> BufferHubQueue::RemoveBuffer(size_t slot) { - ALOGD_IF(TRACE, "%s: slot=%zu", __FUNCTION__, slot); - - if (buffers_[slot]) { - for (const auto& event_source : buffers_[slot]->GetEventSources()) { - const int ret = - epoll_fd_.Control(EPOLL_CTL_DEL, event_source.event_fd, nullptr); - if (ret < 0) { - ALOGE("%s: Failed to remove buffer from epoll set: %s", __FUNCTION__, - strerror(-ret)); - return ErrorStatus(-ret); - } - } - - // Trigger OnBufferRemoved callback if registered. - if (on_buffer_removed_) - on_buffer_removed_(buffers_[slot]); - - buffers_[slot] = nullptr; - capacity_--; - } - - return {}; -} - -Status<void> BufferHubQueue::Enqueue(Entry entry) { - if (!is_full()) { - // Find and remove the enqueued buffer from unavailable_buffers_slot if - // exist. - auto enqueued_buffer_iter = std::find_if( - unavailable_buffers_slot_.begin(), unavailable_buffers_slot_.end(), - [&entry](size_t slot) -> bool { return slot == entry.slot; }); - if (enqueued_buffer_iter != unavailable_buffers_slot_.end()) { - unavailable_buffers_slot_.erase(enqueued_buffer_iter); - } - - available_buffers_.push(std::move(entry)); - - // Trigger OnBufferAvailable callback if registered. - if (on_buffer_available_) - on_buffer_available_(); - - return {}; - } else { - ALOGE("%s: Buffer queue is full!", __FUNCTION__); - return ErrorStatus(E2BIG); - } -} - -Status<std::shared_ptr<BufferHubBase>> BufferHubQueue::Dequeue(int timeout, - size_t* slot) { - ALOGD_IF(TRACE, "%s: count=%zu, timeout=%d", __FUNCTION__, count(), timeout); - - PDX_TRACE_FORMAT("%s|count=%zu|", __FUNCTION__, count()); - - if (count() == 0) { - if (!WaitForBuffers(timeout)) - return ErrorStatus(ETIMEDOUT); - } - - auto& entry = available_buffers_.top(); - PDX_TRACE_FORMAT("buffer|buffer_id=%d;slot=%zu|", entry.buffer->id(), - entry.slot); - - std::shared_ptr<BufferHubBase> buffer = std::move(entry.buffer); - *slot = entry.slot; - - available_buffers_.pop(); - unavailable_buffers_slot_.push_back(*slot); - - return {std::move(buffer)}; -} - -void BufferHubQueue::SetBufferAvailableCallback( - BufferAvailableCallback callback) { - on_buffer_available_ = callback; -} - -void BufferHubQueue::SetBufferRemovedCallback(BufferRemovedCallback callback) { - on_buffer_removed_ = callback; -} - -pdx::Status<void> BufferHubQueue::FreeAllBuffers() { - // Clear all available buffers. - while (!available_buffers_.empty()) - available_buffers_.pop(); - - pdx::Status<void> last_error; // No error. - // Clear all buffers this producer queue is tracking. - for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) { - if (buffers_[slot] != nullptr) { - auto status = RemoveBuffer(slot); - if (!status) { - ALOGE( - "ProducerQueue::FreeAllBuffers: Failed to remove buffer at " - "slot=%zu.", - slot); - last_error = status.error_status(); - } - } - } - - return last_error; -} - -ProducerQueue::ProducerQueue(LocalChannelHandle handle) - : BASE(std::move(handle)) { - auto status = ImportQueue(); - if (!status) { - ALOGE("ProducerQueue::ProducerQueue: Failed to import queue: %s", - status.GetErrorMessage().c_str()); - Close(-status.error()); - } -} - -ProducerQueue::ProducerQueue(const ProducerQueueConfig& config, - const UsagePolicy& usage) - : BASE(BufferHubRPC::kClientPath) { - auto status = - InvokeRemoteMethod<BufferHubRPC::CreateProducerQueue>(config, usage); - if (!status) { - ALOGE("ProducerQueue::ProducerQueue: Failed to create producer queue: %s", - status.GetErrorMessage().c_str()); - Close(-status.error()); - return; - } - - SetupQueue(status.get()); -} - -Status<std::vector<size_t>> ProducerQueue::AllocateBuffers( - uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format, - uint64_t usage, size_t buffer_count) { - if (buffer_count == 0) { - return {std::vector<size_t>()}; - } - - if (capacity() + buffer_count > kMaxQueueCapacity) { - ALOGE( - "ProducerQueue::AllocateBuffers: queue is at capacity: %zu, cannot " - "allocate %zu more buffer(s).", - capacity(), buffer_count); - return ErrorStatus(E2BIG); - } - - Status<std::vector<std::pair<LocalChannelHandle, size_t>>> status = - InvokeRemoteMethod<BufferHubRPC::ProducerQueueAllocateBuffers>( - width, height, layer_count, format, usage, buffer_count); - if (!status) { - ALOGE("ProducerQueue::AllocateBuffers: failed to allocate buffers: %s", - status.GetErrorMessage().c_str()); - return status.error_status(); - } - - auto buffer_handle_slots = status.take(); - LOG_ALWAYS_FATAL_IF(buffer_handle_slots.size() != buffer_count, - "BufferHubRPC::ProducerQueueAllocateBuffers should " - "return %zu buffer handle(s), but returned %zu instead.", - buffer_count, buffer_handle_slots.size()); - - std::vector<size_t> buffer_slots; - buffer_slots.reserve(buffer_count); - - // Bookkeeping for each buffer. - for (auto& hs : buffer_handle_slots) { - auto& buffer_handle = hs.first; - size_t buffer_slot = hs.second; - - // Note that import might (though very unlikely) fail. If so, buffer_handle - // will be closed and included in returned buffer_slots. - if (AddBuffer(ProducerBuffer::Import(std::move(buffer_handle)), - buffer_slot)) { - ALOGD_IF(TRACE, "ProducerQueue::AllocateBuffers: new buffer at slot: %zu", - buffer_slot); - buffer_slots.push_back(buffer_slot); - } - } - - if (buffer_slots.size() != buffer_count) { - // Error out if the count of imported buffer(s) is not correct. - ALOGE( - "ProducerQueue::AllocateBuffers: requested to import %zu " - "buffers, but actually imported %zu buffers.", - buffer_count, buffer_slots.size()); - return ErrorStatus(ENOMEM); - } - - return {std::move(buffer_slots)}; -} - -Status<size_t> ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height, - uint32_t layer_count, - uint32_t format, uint64_t usage) { - // We only allocate one buffer at a time. - constexpr size_t buffer_count = 1; - auto status = - AllocateBuffers(width, height, layer_count, format, usage, buffer_count); - if (!status) { - ALOGE("ProducerQueue::AllocateBuffer: Failed to allocate buffer: %s", - status.GetErrorMessage().c_str()); - return status.error_status(); - } - - return {status.get()[0]}; -} - -Status<void> ProducerQueue::AddBuffer( - const std::shared_ptr<ProducerBuffer>& buffer, size_t slot) { - ALOGD_IF(TRACE, "ProducerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu", - id(), buffer->id(), slot); - // For producer buffer, we need to enqueue the newly added buffer - // immediately. Producer queue starts with all buffers in available state. - auto status = BufferHubQueue::AddBuffer(buffer, slot); - if (!status) - return status; - - return BufferHubQueue::Enqueue({buffer, slot, 0ULL}); -} - -Status<size_t> ProducerQueue::InsertBuffer( - const std::shared_ptr<ProducerBuffer>& buffer) { - if (buffer == nullptr || - !BufferHubDefs::isClientGained(buffer->buffer_state(), - buffer->client_state_mask())) { - ALOGE( - "ProducerQueue::InsertBuffer: Can only insert a buffer when it's in " - "gained state."); - return ErrorStatus(EINVAL); - } - - auto status_or_slot = - InvokeRemoteMethod<BufferHubRPC::ProducerQueueInsertBuffer>( - buffer->cid()); - if (!status_or_slot) { - ALOGE( - "ProducerQueue::InsertBuffer: Failed to insert producer buffer: " - "buffer_cid=%d, error: %s.", - buffer->cid(), status_or_slot.GetErrorMessage().c_str()); - return status_or_slot.error_status(); - } - - size_t slot = status_or_slot.get(); - - // Note that we are calling AddBuffer() from the base class to explicitly - // avoid Enqueue() the ProducerBuffer. - auto status = BufferHubQueue::AddBuffer(buffer, slot); - if (!status) { - ALOGE("ProducerQueue::InsertBuffer: Failed to add buffer: %s.", - status.GetErrorMessage().c_str()); - return status.error_status(); - } - return {slot}; -} - -Status<void> ProducerQueue::RemoveBuffer(size_t slot) { - auto status = - InvokeRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(slot); - if (!status) { - ALOGE("%s: Failed to remove producer buffer: %s", __FUNCTION__, - status.GetErrorMessage().c_str()); - return status.error_status(); - } - - return BufferHubQueue::RemoveBuffer(slot); -} - -Status<std::shared_ptr<ProducerBuffer>> ProducerQueue::Dequeue( - int timeout, size_t* slot, LocalHandle* release_fence) { - DvrNativeBufferMetadata canonical_meta; - return Dequeue(timeout, slot, &canonical_meta, release_fence); -} - -pdx::Status<std::shared_ptr<ProducerBuffer>> ProducerQueue::Dequeue( - int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta, - pdx::LocalHandle* release_fence, bool gain_posted_buffer) { - ATRACE_NAME("ProducerQueue::Dequeue"); - if (slot == nullptr || out_meta == nullptr || release_fence == nullptr) { - ALOGE("%s: Invalid parameter.", __FUNCTION__); - return ErrorStatus(EINVAL); - } - - std::shared_ptr<ProducerBuffer> buffer; - Status<std::shared_ptr<BufferHubBase>> dequeue_status = - BufferHubQueue::Dequeue(timeout, slot); - if (dequeue_status.ok()) { - buffer = std::static_pointer_cast<ProducerBuffer>(dequeue_status.take()); - } else { - if (gain_posted_buffer) { - Status<std::shared_ptr<ProducerBuffer>> dequeue_unacquired_status = - ProducerQueue::DequeueUnacquiredBuffer(slot); - if (!dequeue_unacquired_status.ok()) { - ALOGE("%s: DequeueUnacquiredBuffer returned error: %d", __FUNCTION__, - dequeue_unacquired_status.error()); - return dequeue_unacquired_status.error_status(); - } - buffer = dequeue_unacquired_status.take(); - } else { - return dequeue_status.error_status(); - } - } - const int ret = - buffer->GainAsync(out_meta, release_fence, gain_posted_buffer); - if (ret < 0 && ret != -EALREADY) - return ErrorStatus(-ret); - - return {std::move(buffer)}; -} - -Status<std::shared_ptr<ProducerBuffer>> ProducerQueue::DequeueUnacquiredBuffer( - size_t* slot) { - if (unavailable_buffers_slot_.size() < 1) { - ALOGE( - "%s: Failed to dequeue un-acquired buffer. All buffer(s) are in " - "acquired state if exist.", - __FUNCTION__); - return ErrorStatus(ENOMEM); - } - - // Find the first buffer that is not in acquired state from - // unavailable_buffers_slot_. - for (auto iter = unavailable_buffers_slot_.begin(); - iter != unavailable_buffers_slot_.end(); iter++) { - std::shared_ptr<ProducerBuffer> buffer = ProducerQueue::GetBuffer(*iter); - if (buffer == nullptr) { - ALOGE("%s failed. Buffer slot %d is null.", __FUNCTION__, - static_cast<int>(*slot)); - return ErrorStatus(EIO); - } - if (!BufferHubDefs::isAnyClientAcquired(buffer->buffer_state())) { - *slot = *iter; - unavailable_buffers_slot_.erase(iter); - unavailable_buffers_slot_.push_back(*slot); - ALOGD("%s: Producer queue dequeue unacquired buffer in slot %d", - __FUNCTION__, static_cast<int>(*slot)); - return {std::move(buffer)}; - } - } - ALOGE( - "%s: Failed to dequeue un-acquired buffer. No un-acquired buffer exist.", - __FUNCTION__); - return ErrorStatus(EBUSY); -} - -pdx::Status<ProducerQueueParcelable> ProducerQueue::TakeAsParcelable() { - if (capacity() != 0) { - ALOGE( - "%s: producer queue can only be taken out as a parcelable when empty. " - "Current queue capacity: %zu", - __FUNCTION__, capacity()); - return ErrorStatus(EINVAL); - } - - std::unique_ptr<pdx::ClientChannel> channel = TakeChannel(); - ProducerQueueParcelable queue_parcelable(channel->TakeChannelParcelable()); - - // Here the queue parcelable is returned and holds the underlying system - // resources backing the queue; while the original client channel of this - // producer queue is destroyed in place so that this client can no longer - // provide producer operations. - return {std::move(queue_parcelable)}; -} - -/*static */ -std::unique_ptr<ConsumerQueue> ConsumerQueue::Import( - LocalChannelHandle handle) { - return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(std::move(handle))); -} - -ConsumerQueue::ConsumerQueue(LocalChannelHandle handle) - : BufferHubQueue(std::move(handle)) { - auto status = ImportQueue(); - if (!status) { - ALOGE("%s: Failed to import queue: %s", __FUNCTION__, - status.GetErrorMessage().c_str()); - Close(-status.error()); - } - - auto import_status = ImportBuffers(); - if (import_status) { - ALOGI("%s: Imported %zu buffers.", __FUNCTION__, import_status.get()); - } else { - ALOGE("%s: Failed to import buffers: %s", __FUNCTION__, - import_status.GetErrorMessage().c_str()); - } -} - -Status<size_t> ConsumerQueue::ImportBuffers() { - auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>(); - if (!status) { - if (status.error() == EBADR) { - ALOGI("%s: Queue is silent, no buffers imported.", __FUNCTION__); - return {0}; - } else { - ALOGE("%s: Failed to import consumer buffer: %s", __FUNCTION__, - status.GetErrorMessage().c_str()); - return status.error_status(); - } - } - - int ret; - Status<void> last_error; - size_t imported_buffers_count = 0; - - auto buffer_handle_slots = status.take(); - for (auto& buffer_handle_slot : buffer_handle_slots) { - ALOGD_IF(TRACE, ": buffer_handle=%d", __FUNCTION__, - buffer_handle_slot.first.value()); - - std::unique_ptr<ConsumerBuffer> consumer_buffer = - ConsumerBuffer::Import(std::move(buffer_handle_slot.first)); - if (!consumer_buffer) { - ALOGE("%s: Failed to import buffer: slot=%zu", __FUNCTION__, - buffer_handle_slot.second); - last_error = ErrorStatus(EPIPE); - continue; - } - - auto add_status = - AddBuffer(std::move(consumer_buffer), buffer_handle_slot.second); - if (!add_status) { - ALOGE("%s: Failed to add buffer: %s", __FUNCTION__, - add_status.GetErrorMessage().c_str()); - last_error = add_status; - } else { - imported_buffers_count++; - } - } - - if (imported_buffers_count > 0) - return {imported_buffers_count}; - else - return last_error.error_status(); -} - -Status<void> ConsumerQueue::AddBuffer( - const std::shared_ptr<ConsumerBuffer>& buffer, size_t slot) { - ALOGD_IF(TRACE, "%s: queue_id=%d buffer_id=%d slot=%zu", __FUNCTION__, id(), - buffer->id(), slot); - return BufferHubQueue::AddBuffer(buffer, slot); -} - -Status<std::shared_ptr<ConsumerBuffer>> ConsumerQueue::Dequeue( - int timeout, size_t* slot, void* meta, size_t user_metadata_size, - LocalHandle* acquire_fence) { - if (user_metadata_size != user_metadata_size_) { - ALOGE( - "%s: Metadata size (%zu) for the dequeuing buffer does not match " - "metadata size (%zu) for the queue.", - __FUNCTION__, user_metadata_size, user_metadata_size_); - return ErrorStatus(EINVAL); - } - - DvrNativeBufferMetadata canonical_meta; - auto status = Dequeue(timeout, slot, &canonical_meta, acquire_fence); - if (!status) - return status.error_status(); - - if (meta && user_metadata_size) { - void* metadata_src = - reinterpret_cast<void*>(canonical_meta.user_metadata_ptr); - if (metadata_src) { - memcpy(meta, metadata_src, user_metadata_size); - } else { - ALOGW("%s: no user-defined metadata.", __FUNCTION__); - } - } - - return status; -} - -Status<std::shared_ptr<ConsumerBuffer>> ConsumerQueue::Dequeue( - int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta, - pdx::LocalHandle* acquire_fence) { - ATRACE_NAME("ConsumerQueue::Dequeue"); - if (slot == nullptr || out_meta == nullptr || acquire_fence == nullptr) { - ALOGE("%s: Invalid parameter.", __FUNCTION__); - return ErrorStatus(EINVAL); - } - - auto status = BufferHubQueue::Dequeue(timeout, slot); - if (!status) - return status.error_status(); - - auto buffer = std::static_pointer_cast<ConsumerBuffer>(status.take()); - const int ret = buffer->AcquireAsync(out_meta, acquire_fence); - if (ret < 0) - return ErrorStatus(-ret); - - return {std::move(buffer)}; -} - -Status<void> ConsumerQueue::OnBufferAllocated() { - ALOGD_IF(TRACE, "%s: queue_id=%d", __FUNCTION__, id()); - - auto status = ImportBuffers(); - if (!status) { - ALOGE("%s: Failed to import buffers: %s", __FUNCTION__, - status.GetErrorMessage().c_str()); - return ErrorStatus(status.error()); - } else if (status.get() == 0) { - ALOGW("%s: No new buffers allocated!", __FUNCTION__); - return ErrorStatus(ENOBUFS); - } else { - ALOGD_IF(TRACE, "%s: Imported %zu consumer buffers.", __FUNCTION__, - status.get()); - return {}; - } -} - -} // namespace dvr -} // namespace android diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp deleted file mode 100644 index f705749243..0000000000 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "include/private/dvr/buffer_hub_queue_parcelable.h" - -#include <binder/Parcel.h> -#include <pdx/default_transport/channel_parcelable.h> - -namespace android { -namespace dvr { - -template <BufferHubQueueParcelableMagic Magic> -bool BufferHubQueueParcelable<Magic>::IsValid() const { - return !!channel_parcelable_ && channel_parcelable_->IsValid(); -} - -template <BufferHubQueueParcelableMagic Magic> -pdx::LocalChannelHandle BufferHubQueueParcelable<Magic>::TakeChannelHandle() { - if (!IsValid()) { - ALOGE( - "BufferHubQueueParcelable::TakeChannelHandle: Invalid channel parcel."); - return {}; // Returns an empty channel handle. - } - - // Take channel handle out of the parcelable and reset the parcelable. - pdx::LocalChannelHandle handle = channel_parcelable_->TakeChannelHandle(); - // Now channel_parcelable_ should already be invalid, but reset it to release - // the invalid parcelable object from unique_ptr. - channel_parcelable_ = nullptr; - return handle; -} - -template <BufferHubQueueParcelableMagic Magic> -status_t BufferHubQueueParcelable<Magic>::writeToParcel(Parcel* parcel) const { - if (!IsValid()) { - ALOGE("BufferHubQueueParcelable::writeToParcel: Invalid channel."); - return -EINVAL; - } - - status_t res = parcel->writeUint32(Magic); - if (res != OK) { - ALOGE("BufferHubQueueParcelable::writeToParcel: Cannot write magic."); - return res; - } - - return channel_parcelable_->writeToParcel(parcel); -} - -template <BufferHubQueueParcelableMagic Magic> -status_t BufferHubQueueParcelable<Magic>::readFromParcel(const Parcel* parcel) { - if (IsValid()) { - ALOGE( - "BufferHubQueueParcelable::readFromParcel: This parcelable object has " - "been initialized already."); - return -EINVAL; - } - - uint32_t out_magic = 0; - status_t res = OK; - - res = parcel->readUint32(&out_magic); - if (res != OK) - return res; - - if (out_magic != Magic) { - ALOGE( - "BufferHubQueueParcelable::readFromParcel: Unexpected magic: 0x%x, " - "epxected: 0x%x", - out_magic, Magic); - return -EINVAL; - } - - // (Re)Alocate channel parcelable object. - channel_parcelable_ = - std::make_unique<pdx::default_transport::ChannelParcelable>(); - return channel_parcelable_->readFromParcel(parcel); -} - -template class BufferHubQueueParcelable< - BufferHubQueueParcelableMagic::Producer>; -template class BufferHubQueueParcelable< - BufferHubQueueParcelableMagic::Consumer>; - -} // namespace dvr -} // namespace android diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h deleted file mode 100644 index 74b4b3d67f..0000000000 --- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h +++ /dev/null @@ -1,476 +0,0 @@ -#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_ -#define ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_ - -#include <ui/BufferQueueDefs.h> - -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Weverything" -#endif - -// The following headers are included without checking every warning. -// TODO(b/72172820): Remove the workaround once we have enforced -Weverything -// in these headers and their dependencies. -#include <pdx/client.h> -#include <pdx/status.h> -#include <private/dvr/buffer_hub_queue_parcelable.h> -#include <private/dvr/bufferhub_rpc.h> -#include <private/dvr/consumer_buffer.h> -#include <private/dvr/epoll_file_descriptor.h> -#include <private/dvr/producer_buffer.h> - -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - -#include <memory> -#include <queue> -#include <vector> - -namespace android { -namespace dvr { - -class ConsumerQueue; - -// |BufferHubQueue| manages a queue of |BufferHubBase|s. Buffers are -// automatically re-requeued when released by the remote side. -class BufferHubQueue : public pdx::Client { - public: - using BufferAvailableCallback = std::function<void()>; - using BufferRemovedCallback = - std::function<void(const std::shared_ptr<BufferHubBase>&)>; - - virtual ~BufferHubQueue() {} - - // Creates a new consumer queue that is attached to the producer. Returns - // a new consumer queue client or nullptr on failure. - std::unique_ptr<ConsumerQueue> CreateConsumerQueue(); - - // Creates a new consumer queue that is attached to the producer. This queue - // sets each of its imported consumer buffers to the ignored state to avoid - // participation in lifecycle events. - std::unique_ptr<ConsumerQueue> CreateSilentConsumerQueue(); - - // Returns whether the buffer queue is in async mode. - bool is_async() const { return is_async_; } - - // Returns the default buffer width of this buffer queue. - uint32_t default_width() const { return default_width_; } - - // Returns the default buffer height of this buffer queue. - uint32_t default_height() const { return default_height_; } - - // Returns the default buffer format of this buffer queue. - uint32_t default_format() const { return default_format_; } - - // Creates a new consumer in handle form for immediate transport over RPC. - pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle( - bool silent = false); - - // Creates a new consumer in parcelable form for immediate transport over - // Binder. - pdx::Status<ConsumerQueueParcelable> CreateConsumerQueueParcelable( - bool silent = false); - - // Returns the number of buffers avaiable for dequeue. - size_t count() const { return available_buffers_.size(); } - - // Returns the total number of buffers that the queue is tracking. - size_t capacity() const { return capacity_; } - - // Returns the size of metadata structure associated with this queue. - size_t metadata_size() const { return user_metadata_size_; } - - // Returns whether the buffer queue is full. - bool is_full() const { - return available_buffers_.size() >= kMaxQueueCapacity; - } - - // Returns whether the buffer queue is connected to bufferhubd. - bool is_connected() const { return !!GetChannel(); } - - int GetBufferId(size_t slot) const { - return (slot < buffers_.size() && buffers_[slot]) ? buffers_[slot]->id() - : -1; - } - - std::shared_ptr<BufferHubBase> GetBuffer(size_t slot) const { - return buffers_[slot]; - } - - pdx::Status<int> GetEventMask(int events) { - if (auto* client_channel = GetChannel()) { - return client_channel->GetEventMask(events); - } else { - return pdx::ErrorStatus(EINVAL); - } - } - - // Returns an fd that signals pending queue events using - // EPOLLIN/POLLIN/readible. Either HandleQueueEvents or WaitForBuffers may be - // called to handle pending queue events. - int queue_fd() const { return epoll_fd_.Get(); } - - // Handles any pending events, returning available buffers to the queue and - // reaping disconnected buffers. Returns true if successful, false if an error - // occurred. - bool HandleQueueEvents() { return WaitForBuffers(0); } - - // Set buffer event callbacks, which are std::function wrappers. The caller is - // responsible for ensuring the validity of these callbacks' callable targets. - void SetBufferAvailableCallback(BufferAvailableCallback callback); - void SetBufferRemovedCallback(BufferRemovedCallback callback); - - // The queue tracks at most this many buffers. - static constexpr size_t kMaxQueueCapacity = - android::BufferQueueDefs::NUM_BUFFER_SLOTS; - - static constexpr int kNoTimeOut = -1; - - int id() const { return id_; } - bool hung_up() const { return hung_up_; } - - protected: - explicit BufferHubQueue(pdx::LocalChannelHandle channel); - explicit BufferHubQueue(const std::string& endpoint_path); - - // Imports the queue parameters by querying BufferHub for the parameters for - // this channel. - pdx::Status<void> ImportQueue(); - - // Sets up the queue with the given parameters. - void SetupQueue(const QueueInfo& queue_info); - - // Register a buffer for management by the queue. Used by subclasses to add a - // buffer to internal bookkeeping. - pdx::Status<void> AddBuffer(const std::shared_ptr<BufferHubBase>& buffer, - size_t slot); - - // Called by ProducerQueue::RemoveBuffer and ConsumerQueue::RemoveBuffer only - // to deregister a buffer for epoll and internal bookkeeping. - virtual pdx::Status<void> RemoveBuffer(size_t slot); - - // Free all buffers that belongs to this queue. Can only be called from - // producer side. - virtual pdx::Status<void> FreeAllBuffers(); - - // Dequeue a buffer from the free queue, blocking until one is available. The - // timeout argument specifies the number of milliseconds that |Dequeue()| will - // block. Specifying a timeout of -1 causes Dequeue() to block indefinitely, - // while specifying a timeout equal to zero cause Dequeue() to return - // immediately, even if no buffers are available. - pdx::Status<std::shared_ptr<BufferHubBase>> Dequeue(int timeout, - size_t* slot); - - // Waits for buffers to become available and adds them to the available queue. - bool WaitForBuffers(int timeout); - - pdx::Status<void> HandleBufferEvent(size_t slot, int event_fd, - int poll_events); - pdx::Status<void> HandleQueueEvent(int poll_events); - - // Entry in the priority queue of available buffers that stores related - // per-buffer data. - struct Entry { - Entry() : slot(0) {} - Entry(const std::shared_ptr<BufferHubBase>& in_buffer, size_t in_slot, - uint64_t in_index) - : buffer(in_buffer), slot(in_slot), index(in_index) {} - Entry(const std::shared_ptr<BufferHubBase>& in_buffer, - std::unique_ptr<uint8_t[]> in_metadata, pdx::LocalHandle in_fence, - size_t in_slot) - : buffer(in_buffer), - metadata(std::move(in_metadata)), - fence(std::move(in_fence)), - slot(in_slot) {} - Entry(Entry&&) = default; - Entry& operator=(Entry&&) = default; - - std::shared_ptr<BufferHubBase> buffer; - std::unique_ptr<uint8_t[]> metadata; - pdx::LocalHandle fence; - size_t slot; - uint64_t index; - }; - - struct EntryComparator { - bool operator()(const Entry& lhs, const Entry& rhs) { - return lhs.index > rhs.index; - } - }; - - // Enqueues a buffer to the available list (Gained for producer or Acquireed - // for consumer). - pdx::Status<void> Enqueue(Entry entry); - - // Called when a buffer is allocated remotely. - virtual pdx::Status<void> OnBufferAllocated() { return {}; } - - // Size of the metadata that buffers in this queue cary. - size_t user_metadata_size_{0}; - - // Buffers and related data that are available for dequeue. - std::priority_queue<Entry, std::vector<Entry>, EntryComparator> - available_buffers_; - - // Slot of the buffers that are not available for normal dequeue. For example, - // the slot of posted or acquired buffers in the perspective of a producer. - std::vector<size_t> unavailable_buffers_slot_; - - private: - void Initialize(); - - // Special epoll data field indicating that the epoll event refers to the - // queue. - static constexpr int64_t kEpollQueueEventIndex = -1; - - static constexpr size_t kMaxEvents = 128; - - // The u64 data field of an epoll event is interpreted as int64_t: - // When |index| >= 0 and |index| < kMaxQueueCapacity it refers to a specific - // element of |buffers_| as a direct index; - static bool is_buffer_event_index(int64_t index) { - return index >= 0 && - index < static_cast<int64_t>(BufferHubQueue::kMaxQueueCapacity); - } - - // When |index| == kEpollQueueEventIndex it refers to the queue itself. - static bool is_queue_event_index(int64_t index) { - return index == BufferHubQueue::kEpollQueueEventIndex; - } - - // Whether the buffer queue is operating in Async mode. - // From GVR's perspective of view, this means a buffer can be acquired - // asynchronously by the compositor. - // From Android Surface's perspective of view, this is equivalent to - // IGraphicBufferProducer's async mode. When in async mode, a producer - // will never block even if consumer is running slow. - bool is_async_{false}; - - // Default buffer width that is set during ProducerQueue's creation. - uint32_t default_width_{1}; - - // Default buffer height that is set during ProducerQueue's creation. - uint32_t default_height_{1}; - - // Default buffer format that is set during ProducerQueue's creation. - uint32_t default_format_{1}; // PIXEL_FORMAT_RGBA_8888 - - // Tracks the buffers belonging to this queue. Buffers are stored according to - // "slot" in this vector. Each slot is a logical id of the buffer within this - // queue regardless of its queue position or presence in the ring buffer. - std::array<std::shared_ptr<BufferHubBase>, kMaxQueueCapacity> buffers_; - - // Keeps track with how many buffers have been added into the queue. - size_t capacity_{0}; - - // Epoll fd used to manage buffer events. - EpollFileDescriptor epoll_fd_; - - // Flag indicating that the other side hung up. For ProducerQueues this - // triggers when BufferHub dies or explicitly closes the queue channel. For - // ConsumerQueues this can either mean the same or that the ProducerQueue on - // the other end hung up. - bool hung_up_{false}; - - // Global id for the queue that is consistent across processes. - int id_{-1}; - - // Buffer event callbacks - BufferAvailableCallback on_buffer_available_; - BufferRemovedCallback on_buffer_removed_; - - BufferHubQueue(const BufferHubQueue&) = delete; - void operator=(BufferHubQueue&) = delete; -}; - -class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { - public: - // Usage bits in |usage_set_mask| will be automatically masked on. Usage bits - // in |usage_clear_mask| will be automatically masked off. Note that - // |usage_set_mask| and |usage_clear_mask| may conflict with each other, but - // |usage_set_mask| takes precedence over |usage_clear_mask|. All buffer - // allocation through this producer queue shall not have any of the usage bits - // in |usage_deny_set_mask| set. Allocation calls violating this will be - // rejected. All buffer allocation through this producer queue must have all - // the usage bits in |usage_deny_clear_mask| set. Allocation calls violating - // this will be rejected. Note that |usage_deny_set_mask| and - // |usage_deny_clear_mask| shall not conflict with each other. Such - // configuration will be treated as invalid input on creation. - static std::unique_ptr<ProducerQueue> Create( - const ProducerQueueConfig& config, const UsagePolicy& usage) { - return BASE::Create(config, usage); - } - - // Import a ProducerQueue from a channel handle. - static std::unique_ptr<ProducerQueue> Import(pdx::LocalChannelHandle handle) { - return BASE::Create(std::move(handle)); - } - - // Get a producer buffer. Note that the method doesn't check whether the - // buffer slot has a valid buffer that has been allocated already. When no - // buffer has been imported before it returns nullptr; otherwise it returns - // a shared pointer to a ProducerBuffer. - std::shared_ptr<ProducerBuffer> GetBuffer(size_t slot) const { - return std::static_pointer_cast<ProducerBuffer>( - BufferHubQueue::GetBuffer(slot)); - } - - // Batch allocate buffers. Once allocated, producer buffers are automatically - // enqueue'd into the ProducerQueue and available to use (i.e. in GAINED - // state). Upon success, returns a list of slots for each buffer allocated. - pdx::Status<std::vector<size_t>> AllocateBuffers( - uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format, - uint64_t usage, size_t buffer_count); - - // Allocate producer buffer to populate the queue. Once allocated, a producer - // buffer is automatically enqueue'd into the ProducerQueue and available to - // use (i.e. in GAINED state). Upon success, returns the slot number for the - // buffer allocated. - pdx::Status<size_t> AllocateBuffer(uint32_t width, uint32_t height, - uint32_t layer_count, uint32_t format, - uint64_t usage); - - // Add a producer buffer to populate the queue. Once added, a producer buffer - // is available to use (i.e. in GAINED state). - pdx::Status<void> AddBuffer(const std::shared_ptr<ProducerBuffer>& buffer, - size_t slot); - - // Inserts a ProducerBuffer into the queue. On success, the method returns the - // |slot| number where the new buffer gets inserted. Note that the buffer - // being inserted should be in Gain'ed state prior to the call and it's - // considered as already Dequeued when the function returns. - pdx::Status<size_t> InsertBuffer( - const std::shared_ptr<ProducerBuffer>& buffer); - - // Remove producer buffer from the queue. - pdx::Status<void> RemoveBuffer(size_t slot) override; - - // Free all buffers on this producer queue. - pdx::Status<void> FreeAllBuffers() override { - return BufferHubQueue::FreeAllBuffers(); - } - - // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode, - // and caller should call Post() once it's done writing to release the buffer - // to the consumer side. - // @return a buffer in gained state, which was originally in released state. - pdx::Status<std::shared_ptr<ProducerBuffer>> Dequeue( - int timeout, size_t* slot, pdx::LocalHandle* release_fence); - - // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode, - // and caller should call Post() once it's done writing to release the buffer - // to the consumer side. - // - // @param timeout to dequeue a buffer. - // @param slot is the slot of the output ProducerBuffer. - // @param release_fence for gaining a buffer. - // @param out_meta metadata of the output buffer. - // @param gain_posted_buffer whether to gain posted buffer if no released - // buffer is available to gain. - // @return a buffer in gained state, which was originally in released state if - // gain_posted_buffer is false, or in posted/released state if - // gain_posted_buffer is true. - // TODO(b/112007999): gain_posted_buffer true is only used to prevent - // libdvrtracking from starving when there are non-responding clients. This - // gain_posted_buffer param can be removed once libdvrtracking start to use - // the new AHardwareBuffer API. - pdx::Status<std::shared_ptr<ProducerBuffer>> Dequeue( - int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta, - pdx::LocalHandle* release_fence, bool gain_posted_buffer = false); - - // Enqueues a producer buffer in the queue. - pdx::Status<void> Enqueue(const std::shared_ptr<ProducerBuffer>& buffer, - size_t slot, uint64_t index) { - return BufferHubQueue::Enqueue({buffer, slot, index}); - } - - // Takes out the current producer queue as a binder parcelable object. Note - // that the queue must be empty to be exportable. After successful export, the - // producer queue client should no longer be used. - pdx::Status<ProducerQueueParcelable> TakeAsParcelable(); - - private: - friend BASE; - - // Constructors are automatically exposed through ProducerQueue::Create(...) - // static template methods inherited from ClientBase, which take the same - // arguments as the constructors. - explicit ProducerQueue(pdx::LocalChannelHandle handle); - ProducerQueue(const ProducerQueueConfig& config, const UsagePolicy& usage); - - // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode, - // and caller should call Post() once it's done writing to release the buffer - // to the consumer side. - // - // @param slot the slot of the returned buffer. - // @return a buffer in gained state, which was originally in posted state or - // released state. - pdx::Status<std::shared_ptr<ProducerBuffer>> DequeueUnacquiredBuffer( - size_t* slot); -}; - -class ConsumerQueue : public BufferHubQueue { - public: - // Get a consumer buffer. Note that the method doesn't check whether the - // buffer slot has a valid buffer that has been imported already. When no - // buffer has been imported before it returns nullptr; otherwise returns a - // shared pointer to a ConsumerBuffer. - std::shared_ptr<ConsumerBuffer> GetBuffer(size_t slot) const { - return std::static_pointer_cast<ConsumerBuffer>( - BufferHubQueue::GetBuffer(slot)); - } - - // Import a ConsumerQueue from a channel handle. |ignore_on_import| controls - // whether or not buffers are set to be ignored when imported. This may be - // used to avoid participation in the buffer lifecycle by a consumer queue - // that is only used to spawn other consumer queues, such as in an - // intermediate service. - static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle); - - // Import newly created buffers from the service side. - // Returns number of buffers successfully imported or an error. - pdx::Status<size_t> ImportBuffers(); - - // Dequeue a consumer buffer to read. The returned buffer in |Acquired|'ed - // mode, and caller should call Releasse() once it's done writing to release - // the buffer to the producer side. |meta| is passed along from BufferHub, - // The user of ProducerBuffer is responsible with making sure that the - // Dequeue() is done with the corect metadata type and size with those used - // when the buffer is orignally created. - template <typename Meta> - pdx::Status<std::shared_ptr<ConsumerBuffer>> Dequeue( - int timeout, size_t* slot, Meta* meta, pdx::LocalHandle* acquire_fence) { - return Dequeue(timeout, slot, meta, sizeof(*meta), acquire_fence); - } - pdx::Status<std::shared_ptr<ConsumerBuffer>> Dequeue( - int timeout, size_t* slot, pdx::LocalHandle* acquire_fence) { - return Dequeue(timeout, slot, nullptr, 0, acquire_fence); - } - - pdx::Status<std::shared_ptr<ConsumerBuffer>> Dequeue( - int timeout, size_t* slot, void* meta, size_t user_metadata_size, - pdx::LocalHandle* acquire_fence); - pdx::Status<std::shared_ptr<ConsumerBuffer>> Dequeue( - int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta, - pdx::LocalHandle* acquire_fence); - - private: - friend BufferHubQueue; - - explicit ConsumerQueue(pdx::LocalChannelHandle handle); - - // Add a consumer buffer to populate the queue. Once added, a consumer buffer - // is NOT available to use until the producer side |Post| it. |WaitForBuffers| - // will catch the |Post| and |Acquire| the buffer to make it available for - // consumer. - pdx::Status<void> AddBuffer(const std::shared_ptr<ConsumerBuffer>& buffer, - size_t slot); - - pdx::Status<void> OnBufferAllocated() override; -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_ diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h deleted file mode 100644 index 36ab5f6ac7..0000000000 --- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_ -#define ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_ - -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Weverything" -#endif - -// The following headers are included without checking every warning. -// TODO(b/72172820): Remove the workaround once we have enforced -Weverything -// in these headers and their dependencies. -#include <pdx/channel_parcelable.h> - -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - -namespace android { -namespace dvr { - -enum BufferHubQueueParcelableMagic : uint32_t { - Producer = 0x62687170, // 'bhqp' - Consumer = 0x62687163, // 'bhqc' -}; - -template <BufferHubQueueParcelableMagic Magic> -class BufferHubQueueParcelable : public Parcelable { - public: - BufferHubQueueParcelable() = default; - - BufferHubQueueParcelable(BufferHubQueueParcelable&& other) noexcept = default; - BufferHubQueueParcelable& operator=(BufferHubQueueParcelable&& other) noexcept { - channel_parcelable_ = std::move(other.channel_parcelable_); - return *this; - } - - // Constructs an parcelable contains the channel parcelable. - explicit BufferHubQueueParcelable( - std::unique_ptr<pdx::ChannelParcelable> channel_parcelable) - : channel_parcelable_(std::move(channel_parcelable)) {} - - BufferHubQueueParcelable(const BufferHubQueueParcelable&) = delete; - void operator=(const BufferHubQueueParcelable&) = delete; - - bool IsValid() const; - - // Returns a channel handle constructed from this parcelable object and takes - // the ownership of all resources from the parcelable object. - pdx::LocalChannelHandle TakeChannelHandle(); - - // Serializes the queue parcelable into the given parcel. Note that no system - // resources are getting duplicated, nor did the parcel takes ownership of the - // queue parcelable. Thus, the parcelable object must remain valid for the - // lifetime of the parcel. - status_t writeToParcel(Parcel* parcel) const override; - - // Deserialize the queue parcelable from the given parcel. Note that system - // resources are duplicated from the parcel into the queue parcelable. Returns - // error if the targeting parcelable object is already valid. - status_t readFromParcel(const Parcel* parcel) override; - - private: - std::unique_ptr<pdx::ChannelParcelable> channel_parcelable_; -}; - -using ProducerQueueParcelable = - BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Producer>; -using ConsumerQueueParcelable = - BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Consumer>; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_ diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h b/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h deleted file mode 100644 index 2f14f7cd91..0000000000 --- a/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_ -#define ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_ - -#include <android-base/unique_fd.h> -#include <log/log.h> -#include <sys/epoll.h> - -namespace android { -namespace dvr { - -class EpollFileDescriptor { - public: - static const int CTL_ADD = EPOLL_CTL_ADD; - static const int CTL_MOD = EPOLL_CTL_MOD; - static const int CTL_DEL = EPOLL_CTL_DEL; - - EpollFileDescriptor() : fd_(-1) {} - - // Constructs an EpollFileDescriptor from an integer file descriptor and - // takes ownership. - explicit EpollFileDescriptor(int fd) : fd_(fd) {} - - bool IsValid() const { return fd_.get() >= 0; } - - int Create() { - if (IsValid()) { - ALOGW("epoll fd has already been created."); - return -EALREADY; - } - - fd_.reset(epoll_create1(EPOLL_CLOEXEC)); - - if (fd_.get() < 0) - return -errno; - else - return 0; - } - - int Control(int op, int target_fd, epoll_event* ev) { - if (epoll_ctl(fd_.get(), op, target_fd, ev) < 0) - return -errno; - else - return 0; - } - - int Wait(epoll_event* events, int maxevents, int timeout) { - int ret = epoll_wait(fd_.get(), events, maxevents, timeout); - - if (ret < 0) - return -errno; - else - return ret; - } - - int Get() const { return fd_.get(); } - - private: - base::unique_fd fd_; -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_ diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp deleted file mode 100644 index e373376ab9..0000000000 --- a/libs/vr/libbufferhubqueue/tests/Android.bp +++ /dev/null @@ -1,50 +0,0 @@ - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_native_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_native_license"], -} - -header_libraries = [ - "libdvr_headers", -] - -shared_libraries = [ - "libbase", - "libbinder", - "libbufferhubqueue", - "libcutils", - "libgui", - "liblog", - "libhardware", - "libui", - "libutils", - "libnativewindow", - "libpdx_default_transport", -] - -static_libraries = [ - "libchrome", - "libdvrcommon", - "libperformance", -] - -cc_test { - srcs: ["buffer_hub_queue-test.cpp"], - header_libs: header_libraries, - static_libs: static_libraries, - shared_libs: shared_libraries, - cflags: [ - "-DLOG_TAG=\"buffer_hub_queue-test\"", - "-DTRACE=0", - "-O0", - "-g", - "-Wall", - "-Werror", - "-Wno-error=sign-compare", // to fix later - ], - name: "buffer_hub_queue-test", -} diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp deleted file mode 100644 index 6ae603b892..0000000000 --- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp +++ /dev/null @@ -1,1083 +0,0 @@ -#include <base/logging.h> -#include <binder/Parcel.h> -#include <dvr/dvr_api.h> -#include <private/dvr/buffer_hub_queue_client.h> -#include <private/dvr/consumer_buffer.h> -#include <private/dvr/producer_buffer.h> - -#include <gtest/gtest.h> -#include <poll.h> -#include <sys/eventfd.h> - -#include <vector> - -// Enable/disable debug logging. -#define TRACE 0 - -namespace android { -namespace dvr { - -using pdx::LocalChannelHandle; -using pdx::LocalHandle; - -namespace { - -constexpr uint32_t kBufferWidth = 100; -constexpr uint32_t kBufferHeight = 1; -constexpr uint32_t kBufferLayerCount = 1; -constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB; -constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY; -constexpr int kTimeoutMs = 100; -constexpr int kNoTimeout = 0; - -class BufferHubQueueTest : public ::testing::Test { - public: - bool CreateProducerQueue(const ProducerQueueConfig& config, - const UsagePolicy& usage) { - producer_queue_ = ProducerQueue::Create(config, usage); - return producer_queue_ != nullptr; - } - - bool CreateConsumerQueue() { - if (producer_queue_) { - consumer_queue_ = producer_queue_->CreateConsumerQueue(); - return consumer_queue_ != nullptr; - } else { - return false; - } - } - - bool CreateQueues(const ProducerQueueConfig& config, - const UsagePolicy& usage) { - return CreateProducerQueue(config, usage) && CreateConsumerQueue(); - } - - void AllocateBuffer(size_t* slot_out = nullptr) { - // Create producer buffer. - auto status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight, - kBufferLayerCount, - kBufferFormat, kBufferUsage); - - ASSERT_TRUE(status.ok()); - size_t slot = status.take(); - if (slot_out) - *slot_out = slot; - } - - bool WaitAndHandleOnce(BufferHubQueue* queue, int timeout_ms) { - pollfd pfd{queue->queue_fd(), POLLIN, 0}; - int ret; - do { - ret = poll(&pfd, 1, timeout_ms); - } while (ret == -1 && errno == EINTR); - - if (ret < 0) { - ALOGW("Failed to poll queue %d's event fd, error: %s.", queue->id(), - strerror(errno)); - return false; - } else if (ret == 0) { - return false; - } - return queue->HandleQueueEvents(); - } - - protected: - ProducerQueueConfigBuilder config_builder_; - std::unique_ptr<ProducerQueue> producer_queue_; - std::unique_ptr<ConsumerQueue> consumer_queue_; -}; - -TEST_F(BufferHubQueueTest, TestDequeue) { - const int64_t nb_dequeue_times = 16; - - ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); - - // Allocate only one buffer. - AllocateBuffer(); - - // But dequeue multiple times. - for (int64_t i = 0; i < nb_dequeue_times; i++) { - size_t slot; - LocalHandle fence; - DvrNativeBufferMetadata mi, mo; - - // Producer gains a buffer. - auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - EXPECT_TRUE(p1_status.ok()); - auto p1 = p1_status.take(); - ASSERT_NE(p1, nullptr); - - // Producer posts the buffer. - mi.index = i; - EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0); - - // Consumer acquires a buffer. - auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - EXPECT_TRUE(c1_status.ok()) << c1_status.GetErrorMessage(); - auto c1 = c1_status.take(); - ASSERT_NE(c1, nullptr); - EXPECT_EQ(mi.index, i); - EXPECT_EQ(mo.index, i); - - // Consumer releases the buffer. - EXPECT_EQ(c1->ReleaseAsync(&mi, LocalHandle()), 0); - } -} - -TEST_F(BufferHubQueueTest, - TestDequeuePostedBufferIfNoAvailableReleasedBuffer_withConsumerBuffer) { - ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); - - // Allocate 3 buffers to use. - const size_t test_queue_capacity = 3; - for (int64_t i = 0; i < test_queue_capacity; i++) { - AllocateBuffer(); - } - EXPECT_EQ(producer_queue_->capacity(), test_queue_capacity); - - size_t producer_slot, consumer_slot; - LocalHandle fence; - DvrNativeBufferMetadata mi, mo; - - // Producer posts 2 buffers and remember their posted sequence. - std::deque<size_t> posted_slots; - for (int64_t i = 0; i < 2; i++) { - auto p1_status = - producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true); - EXPECT_TRUE(p1_status.ok()); - auto p1 = p1_status.take(); - ASSERT_NE(p1, nullptr); - - // Producer should not be gaining posted buffer when there are still - // available buffers to gain. - auto found_iter = - std::find(posted_slots.begin(), posted_slots.end(), producer_slot); - EXPECT_EQ(found_iter, posted_slots.end()); - posted_slots.push_back(producer_slot); - - // Producer posts the buffer. - mi.index = i; - EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle())); - } - - // Consumer acquires one buffer. - auto c1_status = - consumer_queue_->Dequeue(kTimeoutMs, &consumer_slot, &mo, &fence); - EXPECT_TRUE(c1_status.ok()); - auto c1 = c1_status.take(); - ASSERT_NE(c1, nullptr); - // Consumer should get the oldest posted buffer. No checks here. - // posted_slots[0] should be in acquired state now. - EXPECT_EQ(mo.index, 0); - // Consumer releases the buffer. - EXPECT_EQ(c1->ReleaseAsync(&mi, LocalHandle()), 0); - // posted_slots[0] should be in released state now. - - // Producer gain and post 2 buffers. - for (int64_t i = 0; i < 2; i++) { - auto p1_status = - producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true); - EXPECT_TRUE(p1_status.ok()); - auto p1 = p1_status.take(); - ASSERT_NE(p1, nullptr); - - // The gained buffer should be the one in released state or the one haven't - // been use. - EXPECT_NE(posted_slots[1], producer_slot); - - mi.index = i + 2; - EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle())); - } - - // Producer gains a buffer. - auto p1_status = - producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true); - EXPECT_TRUE(p1_status.ok()); - auto p1 = p1_status.take(); - ASSERT_NE(p1, nullptr); - - // The gained buffer should be the oldest posted buffer. - EXPECT_EQ(posted_slots[1], producer_slot); - - // Producer posts the buffer. - mi.index = 4; - EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle())); -} - -TEST_F(BufferHubQueueTest, - TestDequeuePostedBufferIfNoAvailableReleasedBuffer_noConsumerBuffer) { - ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); - - // Allocate 4 buffers to use. - const size_t test_queue_capacity = 4; - for (int64_t i = 0; i < test_queue_capacity; i++) { - AllocateBuffer(); - } - EXPECT_EQ(producer_queue_->capacity(), test_queue_capacity); - - // Post all allowed buffers and remember their posted sequence. - std::deque<size_t> posted_slots; - for (int64_t i = 0; i < test_queue_capacity; i++) { - size_t slot; - LocalHandle fence; - DvrNativeBufferMetadata mi, mo; - - // Producer gains a buffer. - auto p1_status = - producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence, true); - EXPECT_TRUE(p1_status.ok()); - auto p1 = p1_status.take(); - ASSERT_NE(p1, nullptr); - - // Producer should not be gaining posted buffer when there are still - // available buffers to gain. - auto found_iter = std::find(posted_slots.begin(), posted_slots.end(), slot); - EXPECT_EQ(found_iter, posted_slots.end()); - posted_slots.push_back(slot); - - // Producer posts the buffer. - mi.index = i; - EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0); - } - - // Gain posted buffers in sequence. - const int64_t nb_dequeue_all_times = 2; - for (int j = 0; j < nb_dequeue_all_times; ++j) { - for (int i = 0; i < test_queue_capacity; ++i) { - size_t slot; - LocalHandle fence; - DvrNativeBufferMetadata mi, mo; - - // Producer gains a buffer. - auto p1_status = - producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence, true); - EXPECT_TRUE(p1_status.ok()); - auto p1 = p1_status.take(); - ASSERT_NE(p1, nullptr); - - // The gained buffer should be the oldest posted buffer. - EXPECT_EQ(posted_slots[i], slot); - - // Producer posts the buffer. - mi.index = i + test_queue_capacity * (j + 1); - EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0); - } - } -} - -TEST_F(BufferHubQueueTest, TestProducerConsumer) { - const size_t kBufferCount = 16; - size_t slot; - DvrNativeBufferMetadata mi, mo; - LocalHandle fence; - - ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); - - for (size_t i = 0; i < kBufferCount; i++) { - AllocateBuffer(); - - // Producer queue has all the available buffers on initialize. - ASSERT_EQ(producer_queue_->count(), i + 1); - ASSERT_EQ(producer_queue_->capacity(), i + 1); - - // Consumer queue has no avaiable buffer on initialize. - ASSERT_EQ(consumer_queue_->count(), 0U); - // Consumer queue does not import buffers until a dequeue is issued. - ASSERT_EQ(consumer_queue_->capacity(), i); - // Dequeue returns timeout since no buffer is ready to consumer, but - // this implicitly triggers buffer import and bump up |capacity|. - auto status = consumer_queue_->Dequeue(kNoTimeout, &slot, &mo, &fence); - ASSERT_FALSE(status.ok()); - ASSERT_EQ(ETIMEDOUT, status.error()); - ASSERT_EQ(consumer_queue_->capacity(), i + 1); - } - - // Use eventfd as a stand-in for a fence. - LocalHandle post_fence(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); - - for (size_t i = 0; i < kBufferCount; i++) { - // First time there is no buffer available to dequeue. - auto consumer_status = - consumer_queue_->Dequeue(kNoTimeout, &slot, &mo, &fence); - ASSERT_FALSE(consumer_status.ok()); - ASSERT_EQ(consumer_status.error(), ETIMEDOUT); - - // Make sure Producer buffer is POSTED so that it's ready to Accquire - // in the consumer's Dequeue() function. - auto producer_status = - producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - ASSERT_TRUE(producer_status.ok()); - auto producer = producer_status.take(); - ASSERT_NE(nullptr, producer); - - mi.index = static_cast<int64_t>(i); - ASSERT_EQ(producer->PostAsync(&mi, post_fence), 0); - - // Second time the just the POSTED buffer should be dequeued. - consumer_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - ASSERT_TRUE(consumer_status.ok()); - EXPECT_TRUE(fence.IsValid()); - - auto consumer = consumer_status.take(); - ASSERT_NE(nullptr, consumer); - ASSERT_EQ(mi.index, mo.index); - } -} - -TEST_F(BufferHubQueueTest, TestInsertBuffer) { - ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{})); - - consumer_queue_ = producer_queue_->CreateConsumerQueue(); - ASSERT_TRUE(consumer_queue_ != nullptr); - EXPECT_EQ(producer_queue_->capacity(), 0); - EXPECT_EQ(consumer_queue_->capacity(), 0); - - std::shared_ptr<ProducerBuffer> p1 = ProducerBuffer::Create( - kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage, 0); - ASSERT_TRUE(p1 != nullptr); - ASSERT_EQ(p1->GainAsync(), 0); - - // Inserting a posted buffer will fail. - DvrNativeBufferMetadata meta; - EXPECT_EQ(p1->PostAsync(&meta, LocalHandle()), 0); - auto status_or_slot = producer_queue_->InsertBuffer(p1); - EXPECT_FALSE(status_or_slot.ok()); - EXPECT_EQ(status_or_slot.error(), EINVAL); - - // Inserting a gained buffer will succeed. - std::shared_ptr<ProducerBuffer> p2 = ProducerBuffer::Create( - kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage); - ASSERT_EQ(p2->GainAsync(), 0); - ASSERT_TRUE(p2 != nullptr); - status_or_slot = producer_queue_->InsertBuffer(p2); - EXPECT_TRUE(status_or_slot.ok()) << status_or_slot.GetErrorMessage(); - // This is the first buffer inserted, should take slot 0. - size_t slot = status_or_slot.get(); - EXPECT_EQ(slot, 0); - - // Wait and expect the consumer to kick up the newly inserted buffer. - WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs); - EXPECT_EQ(consumer_queue_->capacity(), 1ULL); -} - -TEST_F(BufferHubQueueTest, TestRemoveBuffer) { - ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{})); - DvrNativeBufferMetadata mo; - - // Allocate buffers. - const size_t kBufferCount = 4u; - for (size_t i = 0; i < kBufferCount; i++) { - AllocateBuffer(); - } - ASSERT_EQ(kBufferCount, producer_queue_->count()); - ASSERT_EQ(kBufferCount, producer_queue_->capacity()); - - consumer_queue_ = producer_queue_->CreateConsumerQueue(); - ASSERT_NE(nullptr, consumer_queue_); - - // Check that buffers are correctly imported on construction. - EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); - EXPECT_EQ(0u, consumer_queue_->count()); - - // Dequeue all the buffers and keep track of them in an array. This prevents - // the producer queue ring buffer ref counts from interfering with the tests. - struct Entry { - std::shared_ptr<ProducerBuffer> buffer; - LocalHandle fence; - size_t slot; - }; - std::array<Entry, kBufferCount> buffers; - - for (size_t i = 0; i < kBufferCount; i++) { - Entry* entry = &buffers[i]; - auto producer_status = - producer_queue_->Dequeue(kTimeoutMs, &entry->slot, &mo, &entry->fence); - ASSERT_TRUE(producer_status.ok()); - entry->buffer = producer_status.take(); - ASSERT_NE(nullptr, entry->buffer); - } - - // Remove a buffer and make sure both queues reflect the change. - ASSERT_TRUE(producer_queue_->RemoveBuffer(buffers[0].slot)); - EXPECT_EQ(kBufferCount - 1, producer_queue_->capacity()); - - // As long as the removed buffer is still alive the consumer queue won't know - // its gone. - EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); - EXPECT_FALSE(consumer_queue_->HandleQueueEvents()); - EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); - - // Release the removed buffer. - buffers[0].buffer = nullptr; - - // Now the consumer queue should know it's gone. - EXPECT_FALSE(WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs)); - ASSERT_EQ(kBufferCount - 1, consumer_queue_->capacity()); - - // Allocate a new buffer. This should take the first empty slot. - size_t slot; - AllocateBuffer(&slot); - ALOGE_IF(TRACE, "ALLOCATE %zu", slot); - EXPECT_EQ(buffers[0].slot, slot); - EXPECT_EQ(kBufferCount, producer_queue_->capacity()); - - // The consumer queue should pick up the new buffer. - EXPECT_EQ(kBufferCount - 1, consumer_queue_->capacity()); - EXPECT_FALSE(consumer_queue_->HandleQueueEvents()); - EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); - - // Remove and allocate a buffer. - ASSERT_TRUE(producer_queue_->RemoveBuffer(buffers[1].slot)); - EXPECT_EQ(kBufferCount - 1, producer_queue_->capacity()); - buffers[1].buffer = nullptr; - - AllocateBuffer(&slot); - ALOGE_IF(TRACE, "ALLOCATE %zu", slot); - EXPECT_EQ(buffers[1].slot, slot); - EXPECT_EQ(kBufferCount, producer_queue_->capacity()); - - // The consumer queue should pick up the new buffer but the count shouldn't - // change. - EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); - EXPECT_FALSE(consumer_queue_->HandleQueueEvents()); - EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); - - // Remove and allocate a buffer, but don't free the buffer right away. - ASSERT_TRUE(producer_queue_->RemoveBuffer(buffers[2].slot)); - EXPECT_EQ(kBufferCount - 1, producer_queue_->capacity()); - - AllocateBuffer(&slot); - ALOGE_IF(TRACE, "ALLOCATE %zu", slot); - EXPECT_EQ(buffers[2].slot, slot); - EXPECT_EQ(kBufferCount, producer_queue_->capacity()); - - EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); - EXPECT_FALSE(consumer_queue_->HandleQueueEvents()); - EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); - - // Release the producer buffer to trigger a POLLHUP event for an already - // removed buffer. - buffers[2].buffer = nullptr; - EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); - EXPECT_FALSE(consumer_queue_->HandleQueueEvents()); - EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); -} - -TEST_F(BufferHubQueueTest, TestMultipleConsumers) { - // ProducerConfigureBuilder doesn't set Metadata{size}, which means there - // is no metadata associated with this BufferQueue's buffer. - ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{})); - - // Allocate buffers. - const size_t kBufferCount = 4u; - for (size_t i = 0; i < kBufferCount; i++) { - AllocateBuffer(); - } - ASSERT_EQ(kBufferCount, producer_queue_->count()); - - // Build a silent consumer queue to test multi-consumer queue features. - auto silent_queue = producer_queue_->CreateSilentConsumerQueue(); - ASSERT_NE(nullptr, silent_queue); - - // Check that silent queue doesn't import buffers on creation. - EXPECT_EQ(silent_queue->capacity(), 0U); - - // Dequeue and post a buffer. - size_t slot; - LocalHandle fence; - DvrNativeBufferMetadata mi, mo; - auto producer_status = - producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - EXPECT_TRUE(producer_status.ok()); - auto producer_buffer = producer_status.take(); - ASSERT_NE(producer_buffer, nullptr); - EXPECT_EQ(producer_buffer->PostAsync(&mi, {}), 0); - // After post, check the number of remaining available buffers. - EXPECT_EQ(producer_queue_->count(), kBufferCount - 1); - - // Currently we expect no buffer to be available prior to calling - // WaitForBuffers/HandleQueueEvents. - // TODO(eieio): Note this behavior may change in the future. - EXPECT_EQ(silent_queue->count(), 0U); - EXPECT_FALSE(silent_queue->HandleQueueEvents()); - EXPECT_EQ(silent_queue->count(), 0U); - - // Build a new consumer queue to test multi-consumer queue features. - consumer_queue_ = silent_queue->CreateConsumerQueue(); - ASSERT_NE(consumer_queue_, nullptr); - - // Check that buffers are correctly imported on construction. - EXPECT_EQ(consumer_queue_->capacity(), kBufferCount); - // Buffers are only imported, but their availability is not checked until - // first call to Dequeue(). - EXPECT_EQ(consumer_queue_->count(), 0U); - - // Reclaim released/ignored buffers. - EXPECT_EQ(producer_queue_->count(), kBufferCount - 1); - - usleep(10000); - WaitAndHandleOnce(producer_queue_.get(), kTimeoutMs); - EXPECT_EQ(producer_queue_->count(), kBufferCount - 1); - - // Post another buffer. - producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - EXPECT_TRUE(producer_status.ok()); - producer_buffer = producer_status.take(); - ASSERT_NE(producer_buffer, nullptr); - EXPECT_EQ(producer_buffer->PostAsync(&mi, {}), 0); - - // Verify that the consumer queue receives it. - size_t consumer_queue_count = consumer_queue_->count(); - WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs); - EXPECT_GT(consumer_queue_->count(), consumer_queue_count); - - // Save the current consumer queue buffer count to compare after the dequeue. - consumer_queue_count = consumer_queue_->count(); - - // Dequeue and acquire/release (discard) buffers on the consumer end. - auto consumer_status = - consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - EXPECT_TRUE(consumer_status.ok()); - auto consumer_buffer = consumer_status.take(); - ASSERT_NE(consumer_buffer, nullptr); - consumer_buffer->Discard(); - - // Buffer should be returned to the producer queue without being handled by - // the silent consumer queue. - EXPECT_LT(consumer_queue_->count(), consumer_queue_count); - EXPECT_EQ(producer_queue_->count(), kBufferCount - 2); - - WaitAndHandleOnce(producer_queue_.get(), kTimeoutMs); - EXPECT_EQ(producer_queue_->count(), kBufferCount - 1); -} - -struct TestUserMetadata { - char a; - int32_t b; - int64_t c; -}; - -constexpr uint64_t kUserMetadataSize = - static_cast<uint64_t>(sizeof(TestUserMetadata)); - -TEST_F(BufferHubQueueTest, TestUserMetadata) { - ASSERT_TRUE(CreateQueues( - config_builder_.SetMetadata<TestUserMetadata>().Build(), UsagePolicy{})); - - AllocateBuffer(); - - std::vector<TestUserMetadata> user_metadata_list = { - {'0', 0, 0}, {'1', 10, 3333}, {'@', 123, 1000000000}}; - - for (auto user_metadata : user_metadata_list) { - size_t slot; - LocalHandle fence; - DvrNativeBufferMetadata mi, mo; - - auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - EXPECT_TRUE(p1_status.ok()); - auto p1 = p1_status.take(); - ASSERT_NE(p1, nullptr); - - // TODO(b/69469185): Test against metadata from consumer once we implement - // release metadata properly. - // EXPECT_EQ(mo.user_metadata_ptr, 0U); - // EXPECT_EQ(mo.user_metadata_size, 0U); - - mi.user_metadata_size = kUserMetadataSize; - mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata); - EXPECT_EQ(p1->PostAsync(&mi, {}), 0); - auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - EXPECT_TRUE(c1_status.ok()) << c1_status.GetErrorMessage(); - auto c1 = c1_status.take(); - ASSERT_NE(c1, nullptr); - - EXPECT_EQ(mo.user_metadata_size, kUserMetadataSize); - auto out_user_metadata = - reinterpret_cast<TestUserMetadata*>(mo.user_metadata_ptr); - EXPECT_EQ(user_metadata.a, out_user_metadata->a); - EXPECT_EQ(user_metadata.b, out_user_metadata->b); - EXPECT_EQ(user_metadata.c, out_user_metadata->c); - - // When release, empty metadata is also legit. - mi.user_metadata_size = 0U; - mi.user_metadata_ptr = 0U; - c1->ReleaseAsync(&mi, {}); - } -} - -TEST_F(BufferHubQueueTest, TestUserMetadataMismatch) { - ASSERT_TRUE(CreateQueues( - config_builder_.SetMetadata<TestUserMetadata>().Build(), UsagePolicy{})); - - AllocateBuffer(); - - TestUserMetadata user_metadata; - size_t slot; - LocalHandle fence; - DvrNativeBufferMetadata mi, mo; - auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - EXPECT_TRUE(p1_status.ok()); - auto p1 = p1_status.take(); - ASSERT_NE(p1, nullptr); - - // Post with mismatched user metadata size will fail. But the producer buffer - // itself should stay untouched. - mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata); - mi.user_metadata_size = kUserMetadataSize + 1; - EXPECT_EQ(p1->PostAsync(&mi, {}), -E2BIG); - // Post with the exact same user metdata size can success. - mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata); - mi.user_metadata_size = kUserMetadataSize; - EXPECT_EQ(p1->PostAsync(&mi, {}), 0); -} - -TEST_F(BufferHubQueueTest, TestEnqueue) { - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(), - UsagePolicy{})); - AllocateBuffer(); - - size_t slot; - LocalHandle fence; - DvrNativeBufferMetadata mo; - auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - ASSERT_TRUE(p1_status.ok()); - auto p1 = p1_status.take(); - ASSERT_NE(nullptr, p1); - - producer_queue_->Enqueue(p1, slot, 0ULL); - auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - ASSERT_FALSE(c1_status.ok()); -} - -TEST_F(BufferHubQueueTest, TestAllocateBuffer) { - ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); - - size_t ps1; - AllocateBuffer(); - LocalHandle fence; - DvrNativeBufferMetadata mi, mo; - auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &ps1, &mo, &fence); - ASSERT_TRUE(p1_status.ok()); - auto p1 = p1_status.take(); - ASSERT_NE(p1, nullptr); - - // producer queue is exhausted - size_t ps2; - auto p2_status = producer_queue_->Dequeue(kTimeoutMs, &ps2, &mo, &fence); - ASSERT_FALSE(p2_status.ok()); - ASSERT_EQ(ETIMEDOUT, p2_status.error()); - - // dynamically add buffer. - AllocateBuffer(); - ASSERT_EQ(producer_queue_->count(), 1U); - ASSERT_EQ(producer_queue_->capacity(), 2U); - - // now we can dequeue again - p2_status = producer_queue_->Dequeue(kTimeoutMs, &ps2, &mo, &fence); - ASSERT_TRUE(p2_status.ok()); - auto p2 = p2_status.take(); - ASSERT_NE(p2, nullptr); - ASSERT_EQ(producer_queue_->count(), 0U); - // p1 and p2 should have different slot number - ASSERT_NE(ps1, ps2); - - // Consumer queue does not import buffers until |Dequeue| or |ImportBuffers| - // are called. So far consumer_queue_ should be empty. - ASSERT_EQ(consumer_queue_->count(), 0U); - - int64_t seq = 1; - mi.index = seq; - ASSERT_EQ(p1->PostAsync(&mi, {}), 0); - - size_t cs1, cs2; - auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &cs1, &mo, &fence); - ASSERT_TRUE(c1_status.ok()) << c1_status.GetErrorMessage(); - auto c1 = c1_status.take(); - ASSERT_NE(c1, nullptr); - ASSERT_EQ(consumer_queue_->count(), 0U); - ASSERT_EQ(consumer_queue_->capacity(), 2U); - ASSERT_EQ(cs1, ps1); - - ASSERT_EQ(p2->PostAsync(&mi, {}), 0); - auto c2_status = consumer_queue_->Dequeue(kTimeoutMs, &cs2, &mo, &fence); - ASSERT_TRUE(c2_status.ok()); - auto c2 = c2_status.take(); - ASSERT_NE(c2, nullptr); - ASSERT_EQ(cs2, ps2); -} - -TEST_F(BufferHubQueueTest, TestAllocateTwoBuffers) { - ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); - ASSERT_EQ(producer_queue_->capacity(), 0); - auto status = producer_queue_->AllocateBuffers( - kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat, - kBufferUsage, /*buffer_count=*/2); - ASSERT_TRUE(status.ok()); - std::vector<size_t> buffer_slots = status.take(); - ASSERT_EQ(buffer_slots.size(), 2); - ASSERT_EQ(producer_queue_->capacity(), 2); -} - -TEST_F(BufferHubQueueTest, TestAllocateZeroBuffers) { - ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); - ASSERT_EQ(producer_queue_->capacity(), 0); - auto status = producer_queue_->AllocateBuffers( - kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat, - kBufferUsage, /*buffer_count=*/0); - ASSERT_TRUE(status.ok()); - std::vector<size_t> buffer_slots = status.take(); - ASSERT_EQ(buffer_slots.size(), 0); - ASSERT_EQ(producer_queue_->capacity(), 0); -} - -TEST_F(BufferHubQueueTest, TestUsageSetMask) { - const uint32_t set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN; - ASSERT_TRUE( - CreateQueues(config_builder_.Build(), UsagePolicy{set_mask, 0, 0, 0})); - - // When allocation, leave out |set_mask| from usage bits on purpose. - auto status = producer_queue_->AllocateBuffer( - kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat, - kBufferUsage & ~set_mask); - ASSERT_TRUE(status.ok()); - - LocalHandle fence; - size_t slot; - DvrNativeBufferMetadata mo; - auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - ASSERT_TRUE(p1_status.ok()); - auto p1 = p1_status.take(); - ASSERT_EQ(p1->usage() & set_mask, set_mask); -} - -TEST_F(BufferHubQueueTest, TestUsageClearMask) { - const uint32_t clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN; - ASSERT_TRUE( - CreateQueues(config_builder_.Build(), UsagePolicy{0, clear_mask, 0, 0})); - - // When allocation, add |clear_mask| into usage bits on purpose. - auto status = producer_queue_->AllocateBuffer( - kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat, - kBufferUsage | clear_mask); - ASSERT_TRUE(status.ok()); - - LocalHandle fence; - size_t slot; - DvrNativeBufferMetadata mo; - auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - ASSERT_TRUE(p1_status.ok()); - auto p1 = p1_status.take(); - ASSERT_EQ(p1->usage() & clear_mask, 0U); -} - -TEST_F(BufferHubQueueTest, TestUsageDenySetMask) { - const uint32_t deny_set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN; - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(), - UsagePolicy{0, 0, deny_set_mask, 0})); - - // Now that |deny_set_mask| is illegal, allocation without those bits should - // be able to succeed. - auto status = producer_queue_->AllocateBuffer( - kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat, - kBufferUsage & ~deny_set_mask); - ASSERT_TRUE(status.ok()); - - // While allocation with those bits should fail. - status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight, - kBufferLayerCount, kBufferFormat, - kBufferUsage | deny_set_mask); - ASSERT_FALSE(status.ok()); - ASSERT_EQ(EINVAL, status.error()); -} - -TEST_F(BufferHubQueueTest, TestUsageDenyClearMask) { - const uint32_t deny_clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN; - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(), - UsagePolicy{0, 0, 0, deny_clear_mask})); - - // Now that clearing |deny_clear_mask| is illegal (i.e. setting these bits are - // mandatory), allocation with those bits should be able to succeed. - auto status = producer_queue_->AllocateBuffer( - kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat, - kBufferUsage | deny_clear_mask); - ASSERT_TRUE(status.ok()); - - // While allocation without those bits should fail. - status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight, - kBufferLayerCount, kBufferFormat, - kBufferUsage & ~deny_clear_mask); - ASSERT_FALSE(status.ok()); - ASSERT_EQ(EINVAL, status.error()); -} - -TEST_F(BufferHubQueueTest, TestQueueInfo) { - static const bool kIsAsync = true; - ASSERT_TRUE(CreateQueues(config_builder_.SetIsAsync(kIsAsync) - .SetDefaultWidth(kBufferWidth) - .SetDefaultHeight(kBufferHeight) - .SetDefaultFormat(kBufferFormat) - .Build(), - UsagePolicy{})); - - EXPECT_EQ(producer_queue_->default_width(), kBufferWidth); - EXPECT_EQ(producer_queue_->default_height(), kBufferHeight); - EXPECT_EQ(producer_queue_->default_format(), kBufferFormat); - EXPECT_EQ(producer_queue_->is_async(), kIsAsync); - - EXPECT_EQ(consumer_queue_->default_width(), kBufferWidth); - EXPECT_EQ(consumer_queue_->default_height(), kBufferHeight); - EXPECT_EQ(consumer_queue_->default_format(), kBufferFormat); - EXPECT_EQ(consumer_queue_->is_async(), kIsAsync); -} - -TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { - constexpr size_t kBufferCount = 2; - -#define CHECK_NO_BUFFER_THEN_ALLOCATE(num_buffers) \ - EXPECT_EQ(consumer_queue_->count(), 0U); \ - EXPECT_EQ(consumer_queue_->capacity(), 0U); \ - EXPECT_EQ(producer_queue_->count(), 0U); \ - EXPECT_EQ(producer_queue_->capacity(), 0U); \ - for (size_t i = 0; i < num_buffers; i++) { \ - AllocateBuffer(); \ - } \ - EXPECT_EQ(producer_queue_->count(), num_buffers); \ - EXPECT_EQ(producer_queue_->capacity(), num_buffers); - - size_t slot; - LocalHandle fence; - pdx::Status<void> status; - pdx::Status<std::shared_ptr<ConsumerBuffer>> consumer_status; - pdx::Status<std::shared_ptr<ProducerBuffer>> producer_status; - std::shared_ptr<ConsumerBuffer> consumer_buffer; - std::shared_ptr<ProducerBuffer> producer_buffer; - DvrNativeBufferMetadata mi, mo; - - ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); - - // Free all buffers when buffers are avaible for dequeue. - CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); - status = producer_queue_->FreeAllBuffers(); - EXPECT_TRUE(status.ok()); - - // Free all buffers when one buffer is dequeued. - CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); - producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - ASSERT_TRUE(producer_status.ok()); - status = producer_queue_->FreeAllBuffers(); - EXPECT_TRUE(status.ok()); - - // Free all buffers when all buffers are dequeued. - CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); - for (size_t i = 0; i < kBufferCount; i++) { - producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - ASSERT_TRUE(producer_status.ok()); - } - status = producer_queue_->FreeAllBuffers(); - EXPECT_TRUE(status.ok()); - - // Free all buffers when one buffer is posted. - CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); - producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - ASSERT_TRUE(producer_status.ok()); - producer_buffer = producer_status.take(); - ASSERT_NE(nullptr, producer_buffer); - ASSERT_EQ(0, producer_buffer->PostAsync(&mi, fence)); - status = producer_queue_->FreeAllBuffers(); - EXPECT_TRUE(status.ok()); - - // Free all buffers when all buffers are posted. - CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); - for (size_t i = 0; i < kBufferCount; i++) { - producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - ASSERT_TRUE(producer_status.ok()); - producer_buffer = producer_status.take(); - ASSERT_NE(producer_buffer, nullptr); - ASSERT_EQ(producer_buffer->PostAsync(&mi, fence), 0); - } - status = producer_queue_->FreeAllBuffers(); - EXPECT_TRUE(status.ok()); - - // Free all buffers when all buffers are acquired. - CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); - for (size_t i = 0; i < kBufferCount; i++) { - producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - ASSERT_TRUE(producer_status.ok()); - producer_buffer = producer_status.take(); - ASSERT_NE(producer_buffer, nullptr); - ASSERT_EQ(producer_buffer->PostAsync(&mi, fence), 0); - consumer_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); - ASSERT_TRUE(consumer_status.ok()) << consumer_status.GetErrorMessage(); - } - - status = producer_queue_->FreeAllBuffers(); - EXPECT_TRUE(status.ok()); - - // In addition to FreeAllBuffers() from the queue, it is also required to - // delete all references to the ProducerBuffer (i.e. the PDX client). - producer_buffer = nullptr; - - // Crank consumer queue events to pickup EPOLLHUP events on the queue. - consumer_queue_->HandleQueueEvents(); - - // One last check. - CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); - -#undef CHECK_NO_BUFFER_THEN_ALLOCATE -} - -TEST_F(BufferHubQueueTest, TestProducerToParcelableNotEmpty) { - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(), - UsagePolicy{})); - - // Allocate only one buffer. - AllocateBuffer(); - - // Export should fail as the queue is not empty. - auto status = producer_queue_->TakeAsParcelable(); - EXPECT_FALSE(status.ok()); -} - -TEST_F(BufferHubQueueTest, TestProducerExportToParcelable) { - ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); - - auto s1 = producer_queue_->TakeAsParcelable(); - EXPECT_TRUE(s1.ok()); - - ProducerQueueParcelable output_parcelable = s1.take(); - EXPECT_TRUE(output_parcelable.IsValid()); - - Parcel parcel; - status_t res; - res = output_parcelable.writeToParcel(&parcel); - EXPECT_EQ(res, OK); - - // After written into parcelable, the output_parcelable is still valid has - // keeps the producer channel alive. - EXPECT_TRUE(output_parcelable.IsValid()); - - // Creating producer buffer should fail. - auto s2 = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight, - kBufferLayerCount, kBufferFormat, - kBufferUsage); - ASSERT_FALSE(s2.ok()); - - // Reset the data position so that we can read back from the same parcel - // without doing actually Binder IPC. - parcel.setDataPosition(0); - producer_queue_ = nullptr; - - // Recreate the producer queue from the parcel. - ProducerQueueParcelable input_parcelable; - EXPECT_FALSE(input_parcelable.IsValid()); - - res = input_parcelable.readFromParcel(&parcel); - EXPECT_EQ(res, OK); - EXPECT_TRUE(input_parcelable.IsValid()); - - EXPECT_EQ(producer_queue_, nullptr); - producer_queue_ = ProducerQueue::Import(input_parcelable.TakeChannelHandle()); - EXPECT_FALSE(input_parcelable.IsValid()); - ASSERT_NE(producer_queue_, nullptr); - - // Newly created queue from the parcel can allocate buffer, post buffer to - // consumer. - EXPECT_NO_FATAL_FAILURE(AllocateBuffer()); - EXPECT_EQ(producer_queue_->count(), 1U); - EXPECT_EQ(producer_queue_->capacity(), 1U); - - size_t slot; - DvrNativeBufferMetadata producer_meta; - DvrNativeBufferMetadata consumer_meta; - LocalHandle fence; - auto s3 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence); - EXPECT_TRUE(s3.ok()); - - std::shared_ptr<ProducerBuffer> p1 = s3.take(); - ASSERT_NE(p1, nullptr); - - producer_meta.timestamp = 42; - EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0); - - // Make sure the buffer can be dequeued from consumer side. - auto s4 = consumer_queue_->Dequeue(kTimeoutMs, &slot, &consumer_meta, &fence); - EXPECT_TRUE(s4.ok()) << s4.GetErrorMessage(); - EXPECT_EQ(consumer_queue_->capacity(), 1U); - - auto consumer = s4.take(); - ASSERT_NE(consumer, nullptr); - EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp); -} - -TEST_F(BufferHubQueueTest, TestCreateConsumerParcelable) { - ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{})); - - auto s1 = producer_queue_->CreateConsumerQueueParcelable(); - EXPECT_TRUE(s1.ok()); - ConsumerQueueParcelable output_parcelable = s1.take(); - EXPECT_TRUE(output_parcelable.IsValid()); - - // Write to a Parcel new object. - Parcel parcel; - status_t res; - res = output_parcelable.writeToParcel(&parcel); - - // Reset the data position so that we can read back from the same parcel - // without doing actually Binder IPC. - parcel.setDataPosition(0); - - // No consumer queue created yet. - EXPECT_EQ(consumer_queue_, nullptr); - - // If the parcel contains a consumer queue, read into a - // ProducerQueueParcelable should fail. - ProducerQueueParcelable wrongly_typed_parcelable; - EXPECT_FALSE(wrongly_typed_parcelable.IsValid()); - res = wrongly_typed_parcelable.readFromParcel(&parcel); - EXPECT_EQ(res, -EINVAL); - parcel.setDataPosition(0); - - // Create the consumer queue from the parcel. - ConsumerQueueParcelable input_parcelable; - EXPECT_FALSE(input_parcelable.IsValid()); - - res = input_parcelable.readFromParcel(&parcel); - EXPECT_EQ(res, OK); - EXPECT_TRUE(input_parcelable.IsValid()); - - consumer_queue_ = ConsumerQueue::Import(input_parcelable.TakeChannelHandle()); - EXPECT_FALSE(input_parcelable.IsValid()); - ASSERT_NE(consumer_queue_, nullptr); - - EXPECT_NO_FATAL_FAILURE(AllocateBuffer()); - EXPECT_EQ(producer_queue_->count(), 1U); - EXPECT_EQ(producer_queue_->capacity(), 1U); - - size_t slot; - DvrNativeBufferMetadata producer_meta; - DvrNativeBufferMetadata consumer_meta; - LocalHandle fence; - auto s2 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence); - EXPECT_TRUE(s2.ok()); - - std::shared_ptr<ProducerBuffer> p1 = s2.take(); - ASSERT_NE(p1, nullptr); - - producer_meta.timestamp = 42; - EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0); - - // Make sure the buffer can be dequeued from consumer side. - auto s3 = consumer_queue_->Dequeue(kTimeoutMs, &slot, &consumer_meta, &fence); - EXPECT_TRUE(s3.ok()) << s3.GetErrorMessage(); - EXPECT_EQ(consumer_queue_->capacity(), 1U); - - auto consumer = s3.take(); - ASSERT_NE(consumer, nullptr); - EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp); -} - -} // namespace - -} // namespace dvr -} // namespace android diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp deleted file mode 100644 index b0ed950c51..0000000000 --- a/libs/vr/libdisplay/Android.bp +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (C) 2015 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_native_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_native_license"], -} - -sourceFiles = [ - "display_client.cpp", - "display_manager_client.cpp", - "display_protocol.cpp", - "shared_buffer_helpers.cpp", - "vsync_service.cpp", -] - -localIncludeFiles = [ - "include", -] - -sharedLibraries = [ - "libbase", - "libbinder", - "libbufferhubqueue", - "libcutils", - "liblog", - "libutils", - "libui", - "libgui", - "libhardware", - "libsync", - "libnativewindow", - "libpdx_default_transport", -] - -staticLibraries = [ - "libdvrcommon", - "libbroadcastring", -] - -headerLibraries = [ - "vulkan_headers", - "libdvr_headers", -] - -cc_library { - srcs: sourceFiles, - cflags: ["-DLOG_TAG=\"libdisplay\"", - "-DTRACE=0", - "-DATRACE_TAG=ATRACE_TAG_GRAPHICS", - "-DGL_GLEXT_PROTOTYPES", - "-DEGL_EGLEXT_PROTOTYPES", - "-Wall", - "-Werror", - ], // + [ "-UNDEBUG", "-DDEBUG", "-O0", "-g" ], - export_include_dirs: localIncludeFiles, - shared_libs: sharedLibraries, - static_libs: staticLibraries, - header_libs: headerLibraries, - export_header_lib_headers: headerLibraries, - - name: "libdisplay", -} diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp deleted file mode 100644 index 62856dfbf8..0000000000 --- a/libs/vr/libdisplay/display_client.cpp +++ /dev/null @@ -1,261 +0,0 @@ -#include "include/private/dvr/display_client.h" - -#include <cutils/native_handle.h> -#include <log/log.h> -#include <pdx/default_transport/client_channel.h> -#include <pdx/default_transport/client_channel_factory.h> -#include <pdx/status.h> - -#include <mutex> - -#include <private/dvr/display_protocol.h> - -using android::pdx::ErrorStatus; -using android::pdx::LocalHandle; -using android::pdx::LocalChannelHandle; -using android::pdx::Status; -using android::pdx::Transaction; -using android::pdx::rpc::IfAnyOf; - -namespace android { -namespace dvr { -namespace display { - -Surface::Surface(LocalChannelHandle channel_handle, int* error) - : BASE{pdx::default_transport::ClientChannel::Create( - std::move(channel_handle))} { - auto status = InvokeRemoteMethod<DisplayProtocol::GetSurfaceInfo>(); - if (!status) { - ALOGE("Surface::Surface: Failed to get surface info: %s", - status.GetErrorMessage().c_str()); - Close(status.error()); - if (error) - *error = status.error(); - } - - surface_id_ = status.get().surface_id; - z_order_ = status.get().z_order; - visible_ = status.get().visible; -} - -Surface::Surface(const SurfaceAttributes& attributes, int* error) - : BASE{pdx::default_transport::ClientChannelFactory::Create( - DisplayProtocol::kClientPath), - kInfiniteTimeout} { - auto status = InvokeRemoteMethod<DisplayProtocol::CreateSurface>(attributes); - if (!status) { - ALOGE("Surface::Surface: Failed to create display surface: %s", - status.GetErrorMessage().c_str()); - Close(status.error()); - if (error) - *error = status.error(); - } - - surface_id_ = status.get().surface_id; - z_order_ = status.get().z_order; - visible_ = status.get().visible; -} - -Status<void> Surface::SetVisible(bool visible) { - return SetAttributes( - {{SurfaceAttribute::Visible, SurfaceAttributeValue{visible}}}); -} - -Status<void> Surface::SetZOrder(int z_order) { - return SetAttributes( - {{SurfaceAttribute::ZOrder, SurfaceAttributeValue{z_order}}}); -} - -Status<void> Surface::SetAttributes(const SurfaceAttributes& attributes) { - auto status = InvokeRemoteMethod<DisplayProtocol::SetAttributes>(attributes); - if (!status) { - ALOGE( - "Surface::SetAttributes: Failed to set display surface " - "attributes: %s", - status.GetErrorMessage().c_str()); - return status.error_status(); - } - - // Set the local cached copies of the attributes we care about from the full - // set of attributes sent to the display service. - for (const auto& attribute : attributes) { - const auto& key = attribute.first; - const auto* variant = &attribute.second; - bool invalid_value = false; - switch (key) { - case SurfaceAttribute::Visible: - invalid_value = - !IfAnyOf<int32_t, int64_t, bool>::Get(variant, &visible_); - break; - case SurfaceAttribute::ZOrder: - invalid_value = !IfAnyOf<int32_t>::Get(variant, &z_order_); - break; - } - - if (invalid_value) { - ALOGW( - "Surface::SetAttributes: Failed to set display surface " - "attribute %d because of incompatible type: %d", - key, variant->index()); - } - } - - return {}; -} - -Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue( - uint32_t width, uint32_t height, uint32_t format, size_t metadata_size) { - ALOGD_IF(TRACE, "Surface::CreateQueue: Creating empty queue."); - auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>( - ProducerQueueConfigBuilder() - .SetDefaultWidth(width) - .SetDefaultHeight(height) - .SetDefaultFormat(format) - .SetMetadataSize(metadata_size) - .Build()); - if (!status) { - ALOGE("Surface::CreateQueue: Failed to create queue: %s", - status.GetErrorMessage().c_str()); - return status.error_status(); - } - - auto producer_queue = ProducerQueue::Import(status.take()); - if (!producer_queue) { - ALOGE("Surface::CreateQueue: Failed to import producer queue!"); - return ErrorStatus(ENOMEM); - } - - return {std::move(producer_queue)}; -} - -Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue( - uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format, - uint64_t usage, size_t capacity, size_t metadata_size) { - ALOGD_IF(TRACE, - "Surface::CreateQueue: width=%u height=%u layer_count=%u format=%u " - "usage=%" PRIx64 " capacity=%zu", - width, height, layer_count, format, usage, capacity); - auto status = CreateQueue(width, height, format, metadata_size); - if (!status) - return status.error_status(); - - auto producer_queue = status.take(); - - ALOGD_IF(TRACE, "Surface::CreateQueue: Allocating %zu buffers...", capacity); - auto allocate_status = producer_queue->AllocateBuffers( - width, height, layer_count, format, usage, capacity); - if (!allocate_status) { - ALOGE("Surface::CreateQueue: Failed to allocate buffer on queue_id=%d: %s", - producer_queue->id(), allocate_status.GetErrorMessage().c_str()); - return allocate_status.error_status(); - } - - return {std::move(producer_queue)}; -} - -DisplayClient::DisplayClient(int* error) - : BASE(pdx::default_transport::ClientChannelFactory::Create( - DisplayProtocol::kClientPath), - kInfiniteTimeout) { - if (error) - *error = Client::error(); -} - -Status<Metrics> DisplayClient::GetDisplayMetrics() { - return InvokeRemoteMethod<DisplayProtocol::GetMetrics>(); -} - -Status<std::string> DisplayClient::GetConfigurationData( - ConfigFileType config_type) { - auto status = - InvokeRemoteMethod<DisplayProtocol::GetConfigurationData>(config_type); - if (!status && status.error() != ENOENT) { - ALOGE( - "DisplayClient::GetConfigurationData: Unable to get" - "configuration data. Error: %s", - status.GetErrorMessage().c_str()); - } - return status; -} - -Status<uint8_t> DisplayClient::GetDisplayIdentificationPort() { - return InvokeRemoteMethod<DisplayProtocol::GetDisplayIdentificationPort>(); -} - -Status<std::unique_ptr<Surface>> DisplayClient::CreateSurface( - const SurfaceAttributes& attributes) { - int error; - if (auto client = Surface::Create(attributes, &error)) - return {std::move(client)}; - else - return ErrorStatus(error); -} - -pdx::Status<std::unique_ptr<IonBuffer>> DisplayClient::SetupGlobalBuffer( - DvrGlobalBufferKey key, size_t size, uint64_t usage) { - auto status = - InvokeRemoteMethod<DisplayProtocol::SetupGlobalBuffer>(key, size, usage); - if (!status) { - ALOGE( - "DisplayClient::SetupGlobalBuffer: Failed to create the global buffer " - "%s", - status.GetErrorMessage().c_str()); - return status.error_status(); - } - - auto ion_buffer = std::make_unique<IonBuffer>(); - auto native_buffer_handle = status.take(); - const int ret = native_buffer_handle.Import(ion_buffer.get()); - if (ret < 0) { - ALOGE( - "DisplayClient::GetGlobalBuffer: Failed to import global buffer: " - "key=%d; error=%s", - key, strerror(-ret)); - return ErrorStatus(-ret); - } - - return {std::move(ion_buffer)}; -} - -pdx::Status<void> DisplayClient::DeleteGlobalBuffer(DvrGlobalBufferKey key) { - auto status = InvokeRemoteMethod<DisplayProtocol::DeleteGlobalBuffer>(key); - if (!status) { - ALOGE("DisplayClient::DeleteGlobalBuffer Failed: %s", - status.GetErrorMessage().c_str()); - } - - return status; -} - -Status<std::unique_ptr<IonBuffer>> DisplayClient::GetGlobalBuffer( - DvrGlobalBufferKey key) { - auto status = InvokeRemoteMethod<DisplayProtocol::GetGlobalBuffer>(key); - if (!status) { - ALOGE( - "DisplayClient::GetGlobalBuffer: Failed to get named buffer: key=%d; " - "error=%s", - key, status.GetErrorMessage().c_str()); - return status.error_status(); - } - - auto ion_buffer = std::make_unique<IonBuffer>(); - auto native_buffer_handle = status.take(); - const int ret = native_buffer_handle.Import(ion_buffer.get()); - if (ret < 0) { - ALOGE( - "DisplayClient::GetGlobalBuffer: Failed to import global buffer: " - "key=%d; error=%s", - key, strerror(-ret)); - return ErrorStatus(-ret); - } - - return {std::move(ion_buffer)}; -} - -Status<bool> DisplayClient::IsVrAppRunning() { - return InvokeRemoteMethod<DisplayProtocol::IsVrAppRunning>(); -} - -} // namespace display -} // namespace dvr -} // namespace android diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdisplay/display_manager_client.cpp deleted file mode 100644 index fdeeb70dfb..0000000000 --- a/libs/vr/libdisplay/display_manager_client.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "include/private/dvr/display_manager_client.h" - -#include <pdx/default_transport/client_channel_factory.h> -#include <private/dvr/buffer_hub_queue_client.h> -#include <private/dvr/display_protocol.h> -#include <utils/Log.h> - -using android::pdx::ErrorStatus; -using android::pdx::LocalChannelHandle; -using android::pdx::Transaction; - -namespace android { -namespace dvr { -namespace display { - -DisplayManagerClient::DisplayManagerClient() - : BASE(pdx::default_transport::ClientChannelFactory::Create( - DisplayManagerProtocol::kClientPath)) {} - -DisplayManagerClient::~DisplayManagerClient() {} - -pdx::Status<std::vector<display::SurfaceState>> -DisplayManagerClient::GetSurfaceState() { - auto status = InvokeRemoteMethod<DisplayManagerProtocol::GetSurfaceState>(); - if (!status) { - ALOGE( - "DisplayManagerClient::GetSurfaceState: Failed to get surface info: %s", - status.GetErrorMessage().c_str()); - } - - return status; -} - -pdx::Status<std::unique_ptr<ConsumerQueue>> -DisplayManagerClient::GetSurfaceQueue(int surface_id, int queue_id) { - auto status = InvokeRemoteMethod<DisplayManagerProtocol::GetSurfaceQueue>( - surface_id, queue_id); - if (!status) { - ALOGE( - "DisplayManagerClient::GetSurfaceQueue: Failed to get queue for " - "surface_id=%d queue_id=%d: %s", - surface_id, queue_id, status.GetErrorMessage().c_str()); - return status.error_status(); - } - - return {ConsumerQueue::Import(status.take())}; -} - -} // namespace display -} // namespace dvr -} // namespace android diff --git a/libs/vr/libdisplay/display_protocol.cpp b/libs/vr/libdisplay/display_protocol.cpp deleted file mode 100644 index 773f9a5aa3..0000000000 --- a/libs/vr/libdisplay/display_protocol.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "include/private/dvr/display_protocol.h" - -namespace android { -namespace dvr { -namespace display { - -constexpr char DisplayProtocol::kClientPath[]; -constexpr char DisplayManagerProtocol::kClientPath[]; -constexpr char VSyncProtocol::kClientPath[]; - -} // namespace display -} // namespace dvr -} // namespace android diff --git a/libs/vr/libdisplay/include/CPPLINT.cfg b/libs/vr/libdisplay/include/CPPLINT.cfg deleted file mode 100644 index 2f8a3c018c..0000000000 --- a/libs/vr/libdisplay/include/CPPLINT.cfg +++ /dev/null @@ -1 +0,0 @@ -filter=-build/header_guard diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h deleted file mode 100644 index 81546ac5c2..0000000000 --- a/libs/vr/libdisplay/include/private/dvr/display_client.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef ANDROID_DVR_DISPLAY_CLIENT_H_ -#define ANDROID_DVR_DISPLAY_CLIENT_H_ - -#include <dvr/dvr_api.h> -#include <hardware/hwcomposer.h> -#include <pdx/client.h> -#include <pdx/file_handle.h> -#include <private/dvr/buffer_hub_queue_client.h> -#include <private/dvr/display_protocol.h> - -namespace android { -namespace dvr { -namespace display { - -class Surface : public pdx::ClientBase<Surface> { - public: - // Utility named constructor. This can be removed once ClientBase::Create is - // refactored to return Status<T> types. - static pdx::Status<std::unique_ptr<Surface>> CreateSurface( - const SurfaceAttributes& attributes) { - int error; - pdx::Status<std::unique_ptr<Surface>> status; - if (auto surface = Create(attributes, &error)) - status.SetValue(std::move(surface)); - else - status.SetError(error); - return status; - } - - int surface_id() const { return surface_id_; } - int z_order() const { return z_order_; } - bool visible() const { return visible_; } - - pdx::Status<void> SetVisible(bool visible); - pdx::Status<void> SetZOrder(int z_order); - pdx::Status<void> SetAttributes(const SurfaceAttributes& attributes); - - // Creates an empty queue. - pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue(uint32_t width, - uint32_t height, - uint32_t format, - size_t metadata_size); - - // Creates a queue and populates it with |capacity| buffers of the specified - // parameters. - pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue(uint32_t width, - uint32_t height, - uint32_t layer_count, - uint32_t format, - uint64_t usage, - size_t capacity, - size_t metadata_size); - - private: - friend BASE; - - int surface_id_ = -1; - int z_order_ = 0; - bool visible_ = false; - - // TODO(eieio,avakulenko): Remove error param once pdx::ClientBase::Create() - // returns Status<T>. - explicit Surface(const SurfaceAttributes& attributes, int* error = nullptr); - explicit Surface(pdx::LocalChannelHandle channel_handle, - int* error = nullptr); - - Surface(const Surface&) = delete; - void operator=(const Surface&) = delete; -}; - -class DisplayClient : public pdx::ClientBase<DisplayClient> { - public: - pdx::Status<Metrics> GetDisplayMetrics(); - pdx::Status<std::string> GetConfigurationData(ConfigFileType config_type); - pdx::Status<uint8_t> GetDisplayIdentificationPort(); - pdx::Status<std::unique_ptr<IonBuffer>> SetupGlobalBuffer( - DvrGlobalBufferKey key, size_t size, uint64_t usage); - pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key); - pdx::Status<std::unique_ptr<IonBuffer>> GetGlobalBuffer( - DvrGlobalBufferKey key); - pdx::Status<std::unique_ptr<Surface>> CreateSurface( - const SurfaceAttributes& attributes); - - // Temporary query for current VR status. Will be removed later. - pdx::Status<bool> IsVrAppRunning(); - - private: - friend BASE; - - explicit DisplayClient(int* error = nullptr); - - DisplayClient(const DisplayClient&) = delete; - void operator=(const DisplayClient&) = delete; -}; - -} // namespace display -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_DISPLAY_CLIENT_H_ diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h deleted file mode 100644 index 45aef51baf..0000000000 --- a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef ANDROID_DVR_DISPLAY_MANAGER_CLIENT_H_ -#define ANDROID_DVR_DISPLAY_MANAGER_CLIENT_H_ - -#include <string> -#include <vector> - -#include <pdx/client.h> -#include <pdx/status.h> -#include <private/dvr/display_protocol.h> - -namespace android { -namespace dvr { - -class IonBuffer; -class ConsumerQueue; - -namespace display { - -class DisplayManagerClient : public pdx::ClientBase<DisplayManagerClient> { - public: - ~DisplayManagerClient() override; - - pdx::Status<std::vector<SurfaceState>> GetSurfaceState(); - pdx::Status<std::unique_ptr<ConsumerQueue>> GetSurfaceQueue(int surface_id, - int queue_id); - - using Client::event_fd; - - pdx::Status<int> GetEventMask(int events) { - if (auto* client_channel = GetChannel()) - return client_channel->GetEventMask(events); - else - return pdx::ErrorStatus(EINVAL); - } - - private: - friend BASE; - - DisplayManagerClient(); - - DisplayManagerClient(const DisplayManagerClient&) = delete; - void operator=(const DisplayManagerClient&) = delete; -}; - -} // namespace display -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_DISPLAY_MANAGER_CLIENT_H_ diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h deleted file mode 100644 index 9f4cc4afcc..0000000000 --- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h +++ /dev/null @@ -1,304 +0,0 @@ -#ifndef ANDROID_DVR_DISPLAY_PROTOCOL_H_ -#define ANDROID_DVR_DISPLAY_PROTOCOL_H_ - -#include <sys/types.h> - -#include <array> -#include <map> - -#include <dvr/dvr_display_types.h> - -#include <dvr/dvr_api.h> -#include <pdx/rpc/buffer_wrapper.h> -#include <pdx/rpc/remote_method.h> -#include <pdx/rpc/serializable.h> -#include <pdx/rpc/variant.h> -#include <private/dvr/bufferhub_rpc.h> - -// RPC protocol definitions for DVR display services (VrFlinger). - -namespace android { -namespace dvr { -namespace display { - -// Native display metrics. -struct Metrics { - // Basic display properties. - uint32_t display_width; - uint32_t display_height; - uint32_t display_x_dpi; - uint32_t display_y_dpi; - uint32_t vsync_period_ns; - - // HMD metrics. - // TODO(eieio): Determine how these fields should be populated. On phones - // these values are determined at runtime by VrCore based on which headset the - // phone is in. On dedicated hardware this needs to come from somewhere else. - // Perhaps these should be moved to a separate structure that is returned by a - // separate runtime call. - uint32_t distorted_width; - uint32_t distorted_height; - uint32_t hmd_ipd_mm; - float inter_lens_distance_m; - std::array<float, 4> left_fov_lrbt; - std::array<float, 4> right_fov_lrbt; - - private: - PDX_SERIALIZABLE_MEMBERS(Metrics, display_width, display_height, - display_x_dpi, display_y_dpi, vsync_period_ns, - distorted_width, distorted_height, hmd_ipd_mm, - inter_lens_distance_m, left_fov_lrbt, - right_fov_lrbt); -}; - -// Serializable base type for enum structs. Enum structs are easier to use than -// enum classes, especially for bitmasks. This base type provides common -// utilities for flags types. -template <typename Integer> -class Flags { - public: - using Base = Flags<Integer>; - using Type = Integer; - - // NOLINTNEXTLINE(google-explicit-constructor) - Flags(const Integer& value) : value_{value} {} - Flags(const Flags&) = default; - Flags& operator=(const Flags&) = default; - - Integer value() const { return value_; } - // NOLINTNEXTLINE(google-explicit-constructor) - operator Integer() const { return value_; } - - bool IsSet(Integer bits) const { return (value_ & bits) == bits; } - bool IsClear(Integer bits) const { return (value_ & bits) == 0; } - - void Set(Integer bits) { value_ |= bits; } - void Clear(Integer bits) { value_ &= ~bits; } - - Integer operator|(Integer bits) const { return value_ | bits; } - Integer operator&(Integer bits) const { return value_ & bits; } - - Flags& operator|=(Integer bits) { - value_ |= bits; - return *this; - } - Flags& operator&=(Integer bits) { - value_ &= bits; - return *this; - } - - private: - Integer value_; - - PDX_SERIALIZABLE_MEMBERS(Flags<Integer>, value_); -}; - -// Flags indicating what changed since last update. -struct SurfaceUpdateFlags : public Flags<uint32_t> { - enum : Type { - None = DVR_SURFACE_UPDATE_FLAGS_NONE, - NewSurface = DVR_SURFACE_UPDATE_FLAGS_NEW_SURFACE, - BuffersChanged = DVR_SURFACE_UPDATE_FLAGS_BUFFERS_CHANGED, - VisibilityChanged = DVR_SURFACE_UPDATE_FLAGS_VISIBILITY_CHANGED, - AttributesChanged = DVR_SURFACE_UPDATE_FLAGS_ATTRIBUTES_CHANGED, - }; - - SurfaceUpdateFlags() : Base{None} {} - using Base::Base; -}; - -// Surface attribute key/value types. -using SurfaceAttributeKey = int32_t; -using SurfaceAttributeValue = - pdx::rpc::Variant<int32_t, int64_t, bool, float, std::array<float, 2>, - std::array<float, 3>, std::array<float, 4>, - std::array<float, 8>, std::array<float, 16>>; - -// Defined surface attribute keys. -struct SurfaceAttribute : public Flags<SurfaceAttributeKey> { - enum : Type { - // Keys in the negative integer space are interpreted by VrFlinger for - // direct surfaces. - Direct = DVR_SURFACE_ATTRIBUTE_DIRECT, - ZOrder = DVR_SURFACE_ATTRIBUTE_Z_ORDER, - Visible = DVR_SURFACE_ATTRIBUTE_VISIBLE, - - // Invalid key. May be used to terminate C style lists in public API code. - Invalid = DVR_SURFACE_ATTRIBUTE_INVALID, - - // Positive keys are interpreted by the compositor only. - FirstUserKey = DVR_SURFACE_ATTRIBUTE_FIRST_USER_KEY, - }; - - SurfaceAttribute() : Base{Invalid} {} - using Base::Base; -}; - -// Collection of surface attribute key/value pairs. -using SurfaceAttributes = std::map<SurfaceAttributeKey, SurfaceAttributeValue>; - -struct SurfaceState { - int32_t surface_id; - int32_t process_id; - int32_t user_id; - - SurfaceAttributes surface_attributes; - SurfaceUpdateFlags update_flags; - std::vector<int32_t> queue_ids; - - // Convenience accessors. - bool GetVisible() const { - bool bool_value = false; - GetAttribute(SurfaceAttribute::Visible, &bool_value, - ValidTypes<int32_t, int64_t, bool, float>{}); - return bool_value; - } - - int GetZOrder() const { - int int_value = 0; - GetAttribute(SurfaceAttribute::ZOrder, &int_value, - ValidTypes<int32_t, int64_t, float>{}); - return int_value; - } - - private: - template <typename... Types> - struct ValidTypes {}; - - template <typename ReturnType, typename... Types> - bool GetAttribute(SurfaceAttributeKey key, ReturnType* out_value, - ValidTypes<Types...>) const { - auto search = surface_attributes.find(key); - if (search != surface_attributes.end()) - return pdx::rpc::IfAnyOf<Types...>::Get(&search->second, out_value); - else - return false; - } - - PDX_SERIALIZABLE_MEMBERS(SurfaceState, surface_id, process_id, - surface_attributes, update_flags, queue_ids); -}; - -struct SurfaceInfo { - int surface_id; - bool visible; - int z_order; - - private: - PDX_SERIALIZABLE_MEMBERS(SurfaceInfo, surface_id, visible, z_order); -}; - -enum class ConfigFileType : uint32_t { - kLensMetrics, - kDeviceMetrics, - kDeviceConfiguration, - kDeviceEdid -}; - -struct DisplayProtocol { - // Service path. - static constexpr char kClientPath[] = "system/vr/display/client"; - - // Op codes. - enum { - kOpGetMetrics = 0, - kOpGetConfigurationData, - kOpSetupGlobalBuffer, - kOpDeleteGlobalBuffer, - kOpGetGlobalBuffer, - kOpIsVrAppRunning, - kOpCreateSurface, - kOpGetSurfaceInfo, - kOpCreateQueue, - kOpSetAttributes, - kOpGetDisplayIdentificationPort, - }; - - // Aliases. - using LocalChannelHandle = pdx::LocalChannelHandle; - using Void = pdx::rpc::Void; - - // Methods. - PDX_REMOTE_METHOD(GetMetrics, kOpGetMetrics, Metrics(Void)); - PDX_REMOTE_METHOD(GetConfigurationData, kOpGetConfigurationData, - std::string(ConfigFileType config_type)); - PDX_REMOTE_METHOD(GetDisplayIdentificationPort, - kOpGetDisplayIdentificationPort, uint8_t(Void)); - PDX_REMOTE_METHOD(SetupGlobalBuffer, kOpSetupGlobalBuffer, - LocalNativeBufferHandle(DvrGlobalBufferKey key, size_t size, - uint64_t usage)); - PDX_REMOTE_METHOD(DeleteGlobalBuffer, kOpDeleteGlobalBuffer, - void(DvrGlobalBufferKey key)); - PDX_REMOTE_METHOD(GetGlobalBuffer, kOpGetGlobalBuffer, - LocalNativeBufferHandle(DvrGlobalBufferKey key)); - PDX_REMOTE_METHOD(IsVrAppRunning, kOpIsVrAppRunning, bool(Void)); - PDX_REMOTE_METHOD(CreateSurface, kOpCreateSurface, - SurfaceInfo(const SurfaceAttributes& attributes)); - PDX_REMOTE_METHOD(GetSurfaceInfo, kOpGetSurfaceInfo, SurfaceInfo(Void)); - PDX_REMOTE_METHOD( - CreateQueue, kOpCreateQueue, - LocalChannelHandle(const ProducerQueueConfig& producer_config)); - PDX_REMOTE_METHOD(SetAttributes, kOpSetAttributes, - void(const SurfaceAttributes& attributes)); -}; - -struct DisplayManagerProtocol { - // Service path. - static constexpr char kClientPath[] = "system/vr/display/manager"; - - // Op codes. - enum { - kOpGetSurfaceState = 0, - kOpGetSurfaceQueue, - }; - - // Aliases. - using LocalChannelHandle = pdx::LocalChannelHandle; - using Void = pdx::rpc::Void; - - // Methods. - PDX_REMOTE_METHOD(GetSurfaceState, kOpGetSurfaceState, - std::vector<SurfaceState>(Void)); - PDX_REMOTE_METHOD(GetSurfaceQueue, kOpGetSurfaceQueue, - LocalChannelHandle(int surface_id, int queue_id)); -}; - -struct VSyncSchedInfo { - int64_t vsync_period_ns; - int64_t timestamp_ns; - uint32_t next_vsync_count; - - private: - PDX_SERIALIZABLE_MEMBERS(VSyncSchedInfo, vsync_period_ns, timestamp_ns, - next_vsync_count); -}; - -struct VSyncProtocol { - // Service path. - static constexpr char kClientPath[] = "system/vr/display/vsync"; - - // Op codes. - enum { - kOpWait = 0, - kOpAck, - kOpGetLastTimestamp, - kOpGetSchedInfo, - kOpAcknowledge, - }; - - // Aliases. - using Void = pdx::rpc::Void; - using Timestamp = int64_t; - - // Methods. - PDX_REMOTE_METHOD(Wait, kOpWait, Timestamp(Void)); - PDX_REMOTE_METHOD(GetLastTimestamp, kOpGetLastTimestamp, Timestamp(Void)); - PDX_REMOTE_METHOD(GetSchedInfo, kOpGetSchedInfo, VSyncSchedInfo(Void)); - PDX_REMOTE_METHOD(Acknowledge, kOpAcknowledge, void(Void)); -}; - -} // namespace display -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_DISPLAY_PROTOCOL_H_ diff --git a/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h b/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h deleted file mode 100644 index 20541a69a5..0000000000 --- a/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef ANDROID_DVR_SHARED_BUFFER_HELPERS_H_ -#define ANDROID_DVR_SHARED_BUFFER_HELPERS_H_ - -#include <assert.h> -#include <tuple> - -#include <libbroadcastring/broadcast_ring.h> -#include <private/dvr/display_client.h> - -namespace android { -namespace dvr { - -// The buffer usage type for mapped shared buffers. -enum class CPUUsageMode { READ_OFTEN, READ_RARELY, WRITE_OFTEN, WRITE_RARELY }; - -// Holds the memory for the mapped shared buffer. Unlocks and releases the -// underlying IonBuffer in destructor. -class CPUMappedBuffer { - public: - // This constructor will create a display client and get the buffer from it. - CPUMappedBuffer(DvrGlobalBufferKey key, CPUUsageMode mode); - - // If you already have the IonBuffer, use this. It will take ownership. - CPUMappedBuffer(std::unique_ptr<IonBuffer> buffer, CPUUsageMode mode); - - // Use this if you do not want to take ownership. - CPUMappedBuffer(IonBuffer* buffer, CPUUsageMode mode); - - ~CPUMappedBuffer(); - - // Getters. - size_t Size() const { return size_; } - void* Address() const { return address_; } - bool IsMapped() const { return Address() != nullptr; } - - // Attempt mapping this buffer to the CPU addressable space. - // This will create a display client and see if the buffer exists. - // If the buffer has not been setup yet, you will need to try again later. - void TryMapping(); - - protected: - // The memory area if we managed to map it. - size_t size_ = 0; - void* address_ = nullptr; - - // If we are polling the display client, the buffer key here. - DvrGlobalBufferKey buffer_key_; - - // If we just own the IonBuffer outright, it's here. - std::unique_ptr<IonBuffer> owned_buffer_ = nullptr; - - // The last time we connected to the display service. - int64_t last_display_service_connection_ns_ = 0; - - // If we do not own the IonBuffer, it's here - IonBuffer* buffer_ = nullptr; - - // The usage mode. - CPUUsageMode usage_mode_ = CPUUsageMode::READ_OFTEN; -}; - -// Represents a broadcast ring inside a mapped shared memory buffer. -// If has the same set of constructors as CPUMappedBuffer. -// The template argument is the concrete BroadcastRing class that this buffer -// holds. -template <class RingType> -class CPUMappedBroadcastRing : public CPUMappedBuffer { - public: - CPUMappedBroadcastRing(DvrGlobalBufferKey key, CPUUsageMode mode) - : CPUMappedBuffer(key, mode) {} - - CPUMappedBroadcastRing(std::unique_ptr<IonBuffer> buffer, CPUUsageMode mode) - : CPUMappedBuffer(std::move(buffer), mode) {} - - CPUMappedBroadcastRing(IonBuffer* buffer, CPUUsageMode mode) - : CPUMappedBuffer(buffer, mode) {} - - // Helper function for publishing records in the ring. - void Publish(const typename RingType::Record& record) { - assert((usage_mode_ == CPUUsageMode::WRITE_OFTEN) || - (usage_mode_ == CPUUsageMode::WRITE_RARELY)); - - auto ring = Ring(); - if (ring) { - ring->Put(record); - } - } - - // Helper function for getting records from the ring. - // Returns true if we were able to retrieve the latest. - bool GetNewest(typename RingType::Record* record) { - assert((usage_mode_ == CPUUsageMode::READ_OFTEN) || - (usage_mode_ == CPUUsageMode::READ_RARELY)); - - auto ring = Ring(); - if (ring) { - return ring->GetNewest(&sequence_, record); - } - - return false; - } - - // Try obtaining the ring. If the named buffer has not been created yet, it - // will return nullptr. - RingType* Ring() { - // No ring created yet? - if (ring_ == nullptr) { - // Not mapped the memory yet? - if (IsMapped() == false) { - TryMapping(); - } - - // If have the memory mapped, allocate the ring. - if (IsMapped()) { - switch (usage_mode_) { - case CPUUsageMode::READ_OFTEN: - case CPUUsageMode::READ_RARELY: { - RingType ring; - bool import_ok; - std::tie(ring, import_ok) = RingType::Import(address_, size_); - if (import_ok) { - ring_ = std::make_unique<RingType>(ring); - } - } break; - case CPUUsageMode::WRITE_OFTEN: - case CPUUsageMode::WRITE_RARELY: - ring_ = - std::make_unique<RingType>(RingType::Create(address_, size_)); - break; - } - } - } - - return ring_.get(); - } - - protected: - std::unique_ptr<RingType> ring_ = nullptr; - - uint32_t sequence_ = 0; -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_SHARED_BUFFER_HELPERS_H_ diff --git a/libs/vr/libdisplay/include/private/dvr/vsync_service.h b/libs/vr/libdisplay/include/private/dvr/vsync_service.h deleted file mode 100644 index 152464abd1..0000000000 --- a/libs/vr/libdisplay/include/private/dvr/vsync_service.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef ANDROID_DVR_VSYNC_SERVICE_H_ -#define ANDROID_DVR_VSYNC_SERVICE_H_ - -#include <binder/IInterface.h> - -namespace android { -namespace dvr { - -class IVsyncCallback : public IInterface { - public: - DECLARE_META_INTERFACE(VsyncCallback) - - enum { - ON_VSYNC = IBinder::FIRST_CALL_TRANSACTION - }; - - virtual status_t onVsync(int64_t vsync_timestamp) = 0; -}; - -class BnVsyncCallback : public BnInterface<IVsyncCallback> { - public: - virtual status_t onTransact(uint32_t code, const Parcel& data, - Parcel* reply, uint32_t flags = 0); -}; - -// Register a callback with IVsyncService to be notified of vsync events and -// timestamps. There's also a shared memory vsync buffer defined in -// dvr_shared_buffers.h. IVsyncService has advantages over the vsync shared -// memory buffer that make it preferable in certain situations: -// -// 1. The shared memory buffer lifetime is controlled by VrCore. IVsyncService -// is always available as long as surface flinger is running. -// -// 2. IVsyncService will make a binder callback when a vsync event occurs. This -// allows the client to not write code to implement periodic "get the latest -// vsync" calls, which is necessary with the vsync shared memory buffer. -// -// 3. The IVsyncService provides the real vsync timestamp reported by hardware -// composer, whereas the vsync shared memory buffer only has predicted vsync -// times. -class IVsyncService : public IInterface { -public: - DECLARE_META_INTERFACE(VsyncService) - - static const char* GetServiceName() { return "vrflinger_vsync"; } - - enum { - REGISTER_CALLBACK = IBinder::FIRST_CALL_TRANSACTION, - UNREGISTER_CALLBACK - }; - - virtual status_t registerCallback(const sp<IVsyncCallback> callback) = 0; - virtual status_t unregisterCallback(const sp<IVsyncCallback> callback) = 0; -}; - -class BnVsyncService : public BnInterface<IVsyncService> { - public: - virtual status_t onTransact(uint32_t code, const Parcel& data, - Parcel* reply, uint32_t flags = 0); -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_VSYNC_SERVICE_H_ diff --git a/libs/vr/libdisplay/shared_buffer_helpers.cpp b/libs/vr/libdisplay/shared_buffer_helpers.cpp deleted file mode 100644 index 6ebf487d16..0000000000 --- a/libs/vr/libdisplay/shared_buffer_helpers.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include <private/dvr/clock_ns.h> -#include <private/dvr/shared_buffer_helpers.h> - -namespace android { -namespace dvr { -namespace { - -// We will not poll the display service for buffers more frequently than this. -constexpr size_t kDisplayServiceTriesPerSecond = 2; -} // namespace - -CPUMappedBuffer::CPUMappedBuffer(DvrGlobalBufferKey key, CPUUsageMode mode) - : buffer_key_(key), usage_mode_(mode) { - TryMapping(); -} - -CPUMappedBuffer::CPUMappedBuffer(std::unique_ptr<IonBuffer> buffer, - CPUUsageMode mode) - : owned_buffer_(std::move(buffer)), - buffer_(owned_buffer_.get()), - usage_mode_(mode) { - TryMapping(); -} - -CPUMappedBuffer::CPUMappedBuffer(IonBuffer* buffer, CPUUsageMode mode) - : buffer_(buffer), usage_mode_(mode) { - TryMapping(); -} - -CPUMappedBuffer::~CPUMappedBuffer() { - if (IsMapped()) { - buffer_->Unlock(); - } -} - -void CPUMappedBuffer::TryMapping() { - // Do we have an IonBuffer for this shared memory object? - if (buffer_ == nullptr) { - // Has it been too long since we last connected to the display service? - const auto current_time_ns = GetSystemClockNs(); - if ((current_time_ns - last_display_service_connection_ns_) < - (1e9 / kDisplayServiceTriesPerSecond)) { - // Early exit. - return; - } - last_display_service_connection_ns_ = current_time_ns; - - // Create a display client and get the buffer. - auto display_client = display::DisplayClient::Create(); - if (display_client) { - auto get_result = display_client->GetGlobalBuffer(buffer_key_); - if (get_result.ok()) { - owned_buffer_ = get_result.take(); - buffer_ = owned_buffer_.get(); - } else { - // The buffer has not been created yet. This is OK, we will keep - // retrying. - } - } else { - ALOGE("Unable to create display client for shared buffer access"); - } - } - - if (buffer_) { - auto usage = buffer_->usage() & ~GRALLOC_USAGE_SW_READ_MASK & - ~GRALLOC_USAGE_SW_WRITE_MASK; - - // Figure out the usage bits. - switch (usage_mode_) { - case CPUUsageMode::READ_OFTEN: - usage |= GRALLOC_USAGE_SW_READ_OFTEN; - break; - case CPUUsageMode::READ_RARELY: - usage |= GRALLOC_USAGE_SW_READ_RARELY; - break; - case CPUUsageMode::WRITE_OFTEN: - usage |= GRALLOC_USAGE_SW_WRITE_OFTEN; - break; - case CPUUsageMode::WRITE_RARELY: - usage |= GRALLOC_USAGE_SW_WRITE_RARELY; - break; - } - - int width = static_cast<int>(buffer_->width()); - int height = 1; - const auto ret = buffer_->Lock(usage, 0, 0, width, height, &address_); - - if (ret < 0 || !address_) { - ALOGE("Pose failed to map ring buffer: ret:%d, addr:%p", ret, address_); - buffer_->Unlock(); - } else { - size_ = width; - } - } -} - -} // namespace dvr -} // namespace android diff --git a/libs/vr/libdisplay/system/CPPLINT.cfg b/libs/vr/libdisplay/system/CPPLINT.cfg deleted file mode 100644 index 2f8a3c018c..0000000000 --- a/libs/vr/libdisplay/system/CPPLINT.cfg +++ /dev/null @@ -1 +0,0 @@ -filter=-build/header_guard diff --git a/libs/vr/libdisplay/vsync_service.cpp b/libs/vr/libdisplay/vsync_service.cpp deleted file mode 100644 index 04d4f30140..0000000000 --- a/libs/vr/libdisplay/vsync_service.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "include/private/dvr/vsync_service.h" - -#include <binder/Parcel.h> -#include <log/log.h> - -namespace android { -namespace dvr { - -status_t BnVsyncCallback::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { - switch (code) { - case ON_VSYNC: { - CHECK_INTERFACE(IVsyncCallback, data, reply); - int64_t vsync_timestamp = 0; - status_t result = data.readInt64(&vsync_timestamp); - if (result != OK) { - ALOGE("onVsync failed to readInt64: %d", result); - return result; - } - onVsync(vsync_timestamp); - return OK; - } - default: { - return BBinder::onTransact(code, data, reply, flags); - } - } -} - -class BpVsyncCallback : public BpInterface<IVsyncCallback> { -public: - explicit BpVsyncCallback(const sp<IBinder>& impl) - : BpInterface<IVsyncCallback>(impl) {} - virtual ~BpVsyncCallback() {} - - virtual status_t onVsync(int64_t vsync_timestamp) { - Parcel data, reply; - status_t result = data.writeInterfaceToken( - IVsyncCallback::getInterfaceDescriptor()); - if (result != OK) { - ALOGE("onVsync failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeInt64(vsync_timestamp); - if (result != OK) { - ALOGE("onVsync failed to writeInt64: %d", result); - return result; - } - result = remote()->transact(BnVsyncCallback::ON_VSYNC, data, &reply, - IBinder::FLAG_ONEWAY); - if (result != OK) { - ALOGE("onVsync failed to transact: %d", result); - return result; - } - return result; - } -}; - -IMPLEMENT_META_INTERFACE(VsyncCallback, "android.dvr.IVsyncCallback"); - - -status_t BnVsyncService::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { - switch (code) { - case REGISTER_CALLBACK: { - CHECK_INTERFACE(IVsyncService, data, reply); - sp<IBinder> callback; - status_t result = data.readStrongBinder(&callback); - if (result != OK) { - ALOGE("registerCallback failed to readStrongBinder: %d", result); - return result; - } - registerCallback(interface_cast<IVsyncCallback>(callback)); - return OK; - } - case UNREGISTER_CALLBACK: { - CHECK_INTERFACE(IVsyncService, data, reply); - sp<IBinder> callback; - status_t result = data.readStrongBinder(&callback); - if (result != OK) { - ALOGE("unregisterCallback failed to readStrongBinder: %d", result); - return result; - } - unregisterCallback(interface_cast<IVsyncCallback>(callback)); - return OK; - } - default: { - return BBinder::onTransact(code, data, reply, flags); - } - } -} - -class BpVsyncService : public BpInterface<IVsyncService> { -public: - explicit BpVsyncService(const sp<IBinder>& impl) - : BpInterface<IVsyncService>(impl) {} - virtual ~BpVsyncService() {} - - virtual status_t registerCallback(const sp<IVsyncCallback> callback) { - Parcel data, reply; - status_t result = data.writeInterfaceToken( - IVsyncService::getInterfaceDescriptor()); - if (result != OK) { - ALOGE("registerCallback failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(IInterface::asBinder(callback)); - if (result != OK) { - ALOGE("registerCallback failed to writeStrongBinder: %d", result); - return result; - } - result = remote()->transact( - BnVsyncService::REGISTER_CALLBACK, data, &reply); - if (result != OK) { - ALOGE("registerCallback failed to transact: %d", result); - return result; - } - return result; - } - - virtual status_t unregisterCallback(const sp<IVsyncCallback> callback) { - Parcel data, reply; - status_t result = data.writeInterfaceToken( - IVsyncService::getInterfaceDescriptor()); - if (result != OK) { - ALOGE("unregisterCallback failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(IInterface::asBinder(callback)); - if (result != OK) { - ALOGE("unregisterCallback failed to writeStrongBinder: %d", result); - return result; - } - result = remote()->transact( - BnVsyncService::UNREGISTER_CALLBACK, data, &reply); - if (result != OK) { - ALOGE("unregisterCallback failed to transact: %d", result); - return result; - } - return result; - } -}; - -IMPLEMENT_META_INTERFACE(VsyncService, "android.dvr.IVsyncService"); - -} // namespace dvr -} // namespace android diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp deleted file mode 100644 index 40a5099177..0000000000 --- a/libs/vr/libvrsensor/Android.bp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2015 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_native_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_native_license"], -} - -sourceFiles = [ - "pose_client.cpp", - "latency_model.cpp", -] - -includeFiles = [ - "include", -] - -staticLibraries = [ - "libdisplay", - "libdvrcommon", - "libbroadcastring", -] - -sharedLibraries = [ - "libbase", - "libbinder", - "libbufferhubqueue", - "libcutils", - "libhardware", - "liblog", - "libutils", - "libui", - "libpdx_default_transport", -] - -cc_library { - srcs: sourceFiles, - cflags: [ - "-Wall", - "-Werror", - "-Wno-macro-redefined", - ], - export_include_dirs: includeFiles, - static_libs: staticLibraries, - shared_libs: sharedLibraries, - header_libs: ["libdvr_headers"], - name: "libvrsensor", -} diff --git a/libs/vr/libvrsensor/include/CPPLINT.cfg b/libs/vr/libvrsensor/include/CPPLINT.cfg deleted file mode 100644 index 2f8a3c018c..0000000000 --- a/libs/vr/libvrsensor/include/CPPLINT.cfg +++ /dev/null @@ -1 +0,0 @@ -filter=-build/header_guard diff --git a/libs/vr/libvrsensor/include/dvr/pose_client.h b/libs/vr/libvrsensor/include/dvr/pose_client.h deleted file mode 100644 index b663a67cea..0000000000 --- a/libs/vr/libvrsensor/include/dvr/pose_client.h +++ /dev/null @@ -1,176 +0,0 @@ -#ifndef ANDROID_DVR_POSE_CLIENT_H_ -#define ANDROID_DVR_POSE_CLIENT_H_ - -#ifdef __ARM_NEON -#include <arm_neon.h> -#else -#ifndef __FLOAT32X4T_86 -#define __FLOAT32X4T_86 -typedef float float32x4_t __attribute__ ((__vector_size__ (16))); -typedef struct float32x4x4_t { float32x4_t val[4]; } float32x4x4_t; -#endif -#endif - -#include <stdbool.h> -#include <stdint.h> - -#include <dvr/dvr_pose.h> - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct DvrPoseClient DvrPoseClient; - -// Returned by the async pose ring buffer access API. -typedef struct DvrPoseRingBufferInfo { - // Read-only pointer to the pose ring buffer. The current pose is in this - // buffer at element buffer[current_frame & (buffer_size - 1)]. The next - // frame's forecasted pose is at element - // ((current_frame + 1) & (buffer_size - 1)). And so on. The poses are - // predicted for when 50% of the corresponding frame's pixel data is visible - // to the user. - // The last value returned by dvrPresent is the count for the next frame, - // which is the earliest that the application could display something if they - // were to render promptly. (TODO(jbates) move this comment to dvrPresent). - volatile const DvrPoseAsync* buffer; - // Minimum number of accurate forecasted poses including the current frame's - // pose. This is the number of poses that are udpated by the pose service. - // If the application reads past this count, they will get a stale prediction - // from a previous frame. Guaranteed to be at least 2. - uint32_t min_future_count; - // Number of elements in buffer. At least 8 and greater than min_future_count. - // Guaranteed to be a power of two. The total size of the buffer in bytes is: - // total_count * sizeof(DvrPoseAsync) - uint32_t total_count; -} DvrPoseRingBufferInfo; - -typedef enum DvrPoseMode { - DVR_POSE_MODE_6DOF = 0, - DVR_POSE_MODE_3DOF, - DVR_POSE_MODE_MOCK_FROZEN, - DVR_POSE_MODE_MOCK_HEAD_TURN_SLOW, - DVR_POSE_MODE_MOCK_HEAD_TURN_FAST, - DVR_POSE_MODE_MOCK_ROTATE_SLOW, - DVR_POSE_MODE_MOCK_ROTATE_MEDIUM, - DVR_POSE_MODE_MOCK_ROTATE_FAST, - DVR_POSE_MODE_MOCK_CIRCLE_STRAFE, - DVR_POSE_MODE_FLOAT, - DVR_POSE_MODE_MOCK_MOTION_SICKNESS, - - // Always last. - DVR_POSE_MODE_COUNT, -} DvrPoseMode; - -typedef enum DvrControllerId { - DVR_CONTROLLER_0 = 0, - DVR_CONTROLLER_1 = 1, -} DvrControllerId; - -// Creates a new pose client. -// -// @return Pointer to the created pose client, nullptr on failure. -DvrPoseClient* dvrPoseClientCreate(); - -// Destroys a pose client. -// -// @param client Pointer to the pose client to be destroyed. -void dvrPoseClientDestroy(DvrPoseClient* client); - -// Gets the pose for the given vsync count. -// -// @param client Pointer to the pose client. -// @param vsync_count Vsync that this pose should be forward-predicted to. -// Typically this is the count returned by dvrGetNextVsyncCount. -// @param out_pose Struct to store pose state. -// @return Zero on success, negative error code on failure. -int dvrPoseClientGet(DvrPoseClient* client, uint32_t vsync_count, - DvrPoseAsync* out_pose); - -// Gets the current vsync count. -uint32_t dvrPoseClientGetVsyncCount(DvrPoseClient* client); - -// Gets the pose for the given controller at the given vsync count. -// -// @param client Pointer to the pose client. -// @param controller_id The controller id. -// @param vsync_count Vsync that this pose should be forward-predicted to. -// Typically this is the count returned by dvrGetNextVsyncCount. -// @param out_pose Struct to store pose state. -// @return Zero on success, negative error code on failure. -int dvrPoseClientGetController(DvrPoseClient* client, int32_t controller_id, - uint32_t vsync_count, DvrPoseAsync* out_pose); - -// Enables/disables logging for the controller fusion. -// -// @param client Pointer to the pose client. -// @param enable True starts logging, False stops. -// @return Zero on success, negative error code on failure. -int dvrPoseClientLogController(DvrPoseClient* client, bool enable); - -// DEPRECATED -// Polls current pose state. -// -// @param client Pointer to the pose client. -// @param state Struct to store polled state. -// @return Zero on success, negative error code on failure. -int dvrPoseClientPoll(DvrPoseClient* client, DvrPose* state); - -// Freezes the pose to the provided state. -// -// Future poll operations will return this state until a different state is -// frozen or dvrPoseClientModeSet() is called with a different mode. The timestamp is -// not frozen. -// -// @param client Pointer to the pose client. -// @param frozen_state State pose to be frozen to. -// @return Zero on success, negative error code on failure. -int dvrPoseClientFreeze(DvrPoseClient* client, const DvrPose* frozen_state); - -// Sets the pose service mode. -// -// @param mode The requested pose mode. -// @return Zero on success, negative error code on failure. -int dvrPoseClientModeSet(DvrPoseClient* client, DvrPoseMode mode); - -// Gets the pose service mode. -// -// @param mode Return value for the current pose mode. -// @return Zero on success, negative error code on failure. -int dvrPoseClientModeGet(DvrPoseClient* client, DvrPoseMode* mode); - -// Get access to the shared memory pose ring buffer. -// A future pose at vsync <current> + <offset> is accessed at index: -// index = (<current> + <offset>) % out_buffer_size -// Where <current> was the last value returned by dvrPresent and -// <offset> is less than or equal to |out_min_future_count|. -// |out_buffer| will be set to a pointer to the buffer. -// |out_fd| will be set to the gralloc buffer file descriptor, which is -// required for binding this buffer for GPU use. -// Returns 0 on success. -int dvrPoseClientGetRingBuffer(DvrPoseClient* client, - DvrPoseRingBufferInfo* out_info); - -// Sets enabled state for sensors pose processing. -// -// @param enabled Whether sensors are enabled or disabled. -// @return Zero on success -int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled); - -// Requests a burst of data samples from pose service. The data samples are -// passed through a shared memory buffer obtained by calling -// dvrPoseClientGetDataReader(). -// -// @param DvrPoseDataCaptureRequest Parameters on how to capture data. -// @return Zero on success. -int dvrPoseClientDataCapture(DvrPoseClient* client, - const DvrPoseDataCaptureRequest* request); - -// Destroys the write buffer queue for the given |data_type|. -int dvrPoseClientDataReaderDestroy(DvrPoseClient* client, uint64_t data_type); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // ANDROID_DVR_POSE_CLIENT_H_ diff --git a/libs/vr/libvrsensor/include/private/dvr/latency_model.h b/libs/vr/libvrsensor/include/private/dvr/latency_model.h deleted file mode 100644 index bf0e687b7f..0000000000 --- a/libs/vr/libvrsensor/include/private/dvr/latency_model.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef ANDROID_DVR_LATENCY_MODEL_H_ -#define ANDROID_DVR_LATENCY_MODEL_H_ - -#include <vector> - -namespace android { -namespace dvr { - -// This class models the latency from sensors. It will look at the first -// window_size measurements and return their average after that. -class LatencyModel { - public: - explicit LatencyModel(size_t window_size); - ~LatencyModel() = default; - - void AddLatency(int64_t latency_ns); - int64_t CurrentLatencyEstimate() const { return latency_; } - - private: - size_t window_size_; - int64_t latency_sum_ = 0; - size_t num_summed_ = 0; - int64_t latency_ = 0; -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_LATENCY_MODEL_H_ diff --git a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h b/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h deleted file mode 100644 index 7bf1cd4d29..0000000000 --- a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef ANDROID_DVR_POSE_IPC_H_ -#define ANDROID_DVR_POSE_IPC_H_ - -#include <stdint.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#define DVR_POSE_SERVICE_BASE "system/vr/pose" -#define DVR_POSE_SERVICE_CLIENT (DVR_POSE_SERVICE_BASE "/client") - -enum { - DVR_POSE_FREEZE = 0, - DVR_POSE_SET_MODE, - DVR_POSE_GET_MODE, - DVR_POSE_GET_CONTROLLER_RING_BUFFER, - DVR_POSE_LOG_CONTROLLER, - DVR_POSE_SENSORS_ENABLE, - DVR_POSE_GET_TANGO_READER, - DVR_POSE_DATA_CAPTURE, - DVR_POSE_TANGO_READER_DESTROY, -}; - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // ANDROID_DVR_POSE_IPC_H_ diff --git a/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h b/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h deleted file mode 100644 index 39592bb15d..0000000000 --- a/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef ANDROID_DVR_POSE_CLIENT_INTERNAL_H_ -#define ANDROID_DVR_POSE_CLIENT_INTERNAL_H_ - -#include <private/dvr/buffer_hub_queue_client.h> - -using android::dvr::ConsumerQueue; - -typedef struct DvrPoseClient DvrPoseClient; - -namespace android { -namespace dvr { - -int dvrPoseClientGetDataReaderHandle(DvrPoseClient *client, uint64_t data_type, - ConsumerQueue **queue_out); - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_POSE_CLIENT_INTERNAL_H_ diff --git a/libs/vr/libvrsensor/latency_model.cpp b/libs/vr/libvrsensor/latency_model.cpp deleted file mode 100644 index d3a45210a7..0000000000 --- a/libs/vr/libvrsensor/latency_model.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include <private/dvr/latency_model.h> - -#include <cmath> - -namespace android { -namespace dvr { - -LatencyModel::LatencyModel(size_t window_size) : window_size_(window_size) {} - -void LatencyModel::AddLatency(int64_t latency_ns) { - // Not enough samples yet? - if (num_summed_ < window_size_) { - // Accumulate. - latency_sum_ += latency_ns; - - // Have enough samples for latency estimate? - if (++num_summed_ == window_size_) { - latency_ = latency_sum_ / window_size_; - } - } -} - -} // namespace dvr -} // namespace android diff --git a/libs/vr/libvrsensor/pose_client.cpp b/libs/vr/libvrsensor/pose_client.cpp deleted file mode 100644 index 4ff6a0912c..0000000000 --- a/libs/vr/libvrsensor/pose_client.cpp +++ /dev/null @@ -1,368 +0,0 @@ -#define LOG_TAG "PoseClient" -#include <dvr/dvr_shared_buffers.h> -#include <dvr/pose_client.h> - -#include <stdint.h> - -#include <log/log.h> -#include <pdx/client.h> -#include <pdx/default_transport/client_channel_factory.h> -#include <pdx/file_handle.h> -#include <private/dvr/buffer_hub_queue_client.h> -#include <private/dvr/consumer_buffer.h> -#include <private/dvr/display_client.h> -#include <private/dvr/pose-ipc.h> -#include <private/dvr/shared_buffer_helpers.h> - -using android::dvr::ConsumerQueue; -using android::pdx::LocalHandle; -using android::pdx::LocalChannelHandle; -using android::pdx::Status; -using android::pdx::Transaction; - -namespace android { -namespace dvr { -namespace { - -typedef CPUMappedBroadcastRing<DvrPoseRing> SensorPoseRing; - -constexpr static int32_t MAX_CONTROLLERS = 2; -} // namespace - -// PoseClient is a remote interface to the pose service in sensord. -class PoseClient : public pdx::ClientBase<PoseClient> { - public: - ~PoseClient() override {} - - // Casts C handle into an instance of this class. - static PoseClient* FromC(DvrPoseClient* client) { - return reinterpret_cast<PoseClient*>(client); - } - - // Polls the pose service for the current state and stores it in *state. - // Returns zero on success, a negative error code otherwise. - int Poll(DvrPose* state) { - // Allocate the helper class to access the sensor pose buffer. - if (sensor_pose_buffer_ == nullptr) { - sensor_pose_buffer_ = std::make_unique<SensorPoseRing>( - DvrGlobalBuffers::kSensorPoseBuffer, CPUUsageMode::READ_RARELY); - } - - if (state) { - if (sensor_pose_buffer_->GetNewest(state)) { - return 0; - } else { - return -EAGAIN; - } - } - - return -EINVAL; - } - - int GetPose(uint32_t vsync_count, DvrPoseAsync* out_pose) { - const auto vsync_buffer = GetVsyncBuffer(); - if (vsync_buffer) { - *out_pose = - vsync_buffer - ->vsync_poses[vsync_count & DvrVsyncPoseBuffer::kIndexMask]; - return 0; - } else { - return -EAGAIN; - } - } - - uint32_t GetVsyncCount() { - const auto vsync_buffer = GetVsyncBuffer(); - if (vsync_buffer) { - return vsync_buffer->vsync_count; - } - - return 0; - } - - int GetControllerPose(int32_t controller_id, uint32_t vsync_count, - DvrPoseAsync* out_pose) { - if (controller_id < 0 || controller_id >= MAX_CONTROLLERS) { - return -EINVAL; - } - if (!controllers_[controller_id].mapped_pose_buffer) { - int ret = GetControllerRingBuffer(controller_id); - if (ret < 0) - return ret; - } - *out_pose = - controllers_[controller_id] - .mapped_pose_buffer[vsync_count & DvrVsyncPoseBuffer::kIndexMask]; - return 0; - } - - int LogController(bool enable) { - Transaction trans{*this}; - Status<int> status = trans.Send<int>(DVR_POSE_LOG_CONTROLLER, &enable, - sizeof(enable), nullptr, 0); - ALOGE_IF(!status, "Pose LogController() failed because: %s", - status.GetErrorMessage().c_str()); - return ReturnStatusOrError(status); - } - - // Freezes the pose to the provided state. Future poll operations will return - // this state until a different state is frozen or SetMode() is called with a - // different mode. - // Returns zero on success, a negative error code otherwise. - int Freeze(const DvrPose& frozen_state) { - Transaction trans{*this}; - Status<int> status = trans.Send<int>(DVR_POSE_FREEZE, &frozen_state, - sizeof(frozen_state), nullptr, 0); - ALOGE_IF(!status, "Pose Freeze() failed because: %s\n", - status.GetErrorMessage().c_str()); - return ReturnStatusOrError(status); - } - - // Sets the data mode for the pose service. - int SetMode(DvrPoseMode mode) { - Transaction trans{*this}; - Status<int> status = - trans.Send<int>(DVR_POSE_SET_MODE, &mode, sizeof(mode), nullptr, 0); - ALOGE_IF(!status, "Pose SetPoseMode() failed because: %s", - status.GetErrorMessage().c_str()); - return ReturnStatusOrError(status); - } - - // Gets the data mode for the pose service. - int GetMode(DvrPoseMode* out_mode) { - int mode; - Transaction trans{*this}; - Status<int> status = - trans.Send<int>(DVR_POSE_GET_MODE, nullptr, 0, &mode, sizeof(mode)); - ALOGE_IF(!status, "Pose GetPoseMode() failed because: %s", - status.GetErrorMessage().c_str()); - if (status) - *out_mode = DvrPoseMode(mode); - return ReturnStatusOrError(status); - } - - int GetTangoReaderHandle(uint64_t data_type, ConsumerQueue** queue_out) { - // Get buffer. - Transaction trans{*this}; - Status<LocalChannelHandle> status = trans.Send<LocalChannelHandle>( - DVR_POSE_GET_TANGO_READER, &data_type, sizeof(data_type), nullptr, 0); - - if (!status) { - ALOGE("PoseClient GetTangoReaderHandle() failed because: %s", - status.GetErrorMessage().c_str()); - *queue_out = nullptr; - return -status.error(); - } - - std::unique_ptr<ConsumerQueue> consumer_queue = - ConsumerQueue::Import(status.take()); - *queue_out = consumer_queue.release(); - return 0; - } - - int DataCapture(const DvrPoseDataCaptureRequest* request) { - Transaction trans{*this}; - Status<int> status = trans.Send<int>(DVR_POSE_DATA_CAPTURE, request, - sizeof(*request), nullptr, 0); - ALOGE_IF(!status, "PoseClient DataCapture() failed because: %s\n", - status.GetErrorMessage().c_str()); - return ReturnStatusOrError(status); - } - - int DataReaderDestroy(uint64_t data_type) { - Transaction trans{*this}; - Status<int> status = trans.Send<int>(DVR_POSE_TANGO_READER_DESTROY, - &data_type, sizeof(data_type), nullptr, - 0); - ALOGE_IF(!status, "PoseClient DataReaderDestroy() failed because: %s\n", - status.GetErrorMessage().c_str()); - return ReturnStatusOrError(status); - } - - // Enables or disables all pose processing from sensors - int EnableSensors(bool enabled) { - Transaction trans{*this}; - Status<int> status = trans.Send<int>(DVR_POSE_SENSORS_ENABLE, &enabled, - sizeof(enabled), nullptr, 0); - ALOGE_IF(!status, "Pose EnableSensors() failed because: %s\n", - status.GetErrorMessage().c_str()); - return ReturnStatusOrError(status); - } - - int GetRingBuffer(DvrPoseRingBufferInfo* out_info) { - // First time mapping the buffer? - const auto vsync_buffer = GetVsyncBuffer(); - if (vsync_buffer) { - if (out_info) { - out_info->min_future_count = DvrVsyncPoseBuffer::kMinFutureCount; - out_info->total_count = DvrVsyncPoseBuffer::kSize; - out_info->buffer = vsync_buffer->vsync_poses; - } - return -EINVAL; - } - - return -EAGAIN; - } - - int GetControllerRingBuffer(int32_t controller_id) { - if (controller_id < 0 || controller_id >= MAX_CONTROLLERS) { - return -EINVAL; - } - ControllerClientState& client_state = controllers_[controller_id]; - if (client_state.pose_buffer.get()) { - return 0; - } - - Transaction trans{*this}; - Status<LocalChannelHandle> status = trans.Send<LocalChannelHandle>( - DVR_POSE_GET_CONTROLLER_RING_BUFFER, &controller_id, - sizeof(controller_id), nullptr, 0); - if (!status) { - return -status.error(); - } - - auto buffer = ConsumerBuffer::Import(status.take()); - if (!buffer) { - ALOGE("Pose failed to import ring buffer"); - return -EIO; - } - constexpr size_t size = DvrVsyncPoseBuffer::kSize * sizeof(DvrPoseAsync); - void* addr = nullptr; - int ret = buffer->GetBlobReadWritePointer(size, &addr); - if (ret < 0 || !addr) { - ALOGE("Pose failed to map ring buffer: ret:%d, addr:%p", ret, addr); - return -EIO; - } - client_state.pose_buffer.swap(buffer); - client_state.mapped_pose_buffer = static_cast<const DvrPoseAsync*>(addr); - ALOGI( - "Mapped controller %d pose data translation %f,%f,%f quat %f,%f,%f,%f", - controller_id, client_state.mapped_pose_buffer[0].position[0], - client_state.mapped_pose_buffer[0].position[1], - client_state.mapped_pose_buffer[0].position[2], - client_state.mapped_pose_buffer[0].orientation[0], - client_state.mapped_pose_buffer[0].orientation[1], - client_state.mapped_pose_buffer[0].orientation[2], - client_state.mapped_pose_buffer[0].orientation[3]); - return 0; - } - - private: - friend BASE; - - // Set up a channel to the pose service. - PoseClient() - : BASE(pdx::default_transport::ClientChannelFactory::Create( - DVR_POSE_SERVICE_CLIENT)) { - // TODO(eieio): Cache the pose and make timeout 0 so that the API doesn't - // block while waiting for the pose service to come back up. - EnableAutoReconnect(kInfiniteTimeout); - } - - PoseClient(const PoseClient&) = delete; - PoseClient& operator=(const PoseClient&) = delete; - - const DvrVsyncPoseBuffer* GetVsyncBuffer() { - if (mapped_vsync_pose_buffer_ == nullptr) { - if (vsync_pose_buffer_ == nullptr) { - // The constructor tries mapping it so we do not need TryMapping after. - vsync_pose_buffer_ = std::make_unique<CPUMappedBuffer>( - DvrGlobalBuffers::kVsyncPoseBuffer, CPUUsageMode::READ_OFTEN); - } else if (vsync_pose_buffer_->IsMapped() == false) { - vsync_pose_buffer_->TryMapping(); - } - - if (vsync_pose_buffer_->IsMapped()) { - mapped_vsync_pose_buffer_ = - static_cast<DvrVsyncPoseBuffer*>(vsync_pose_buffer_->Address()); - } - } - - return mapped_vsync_pose_buffer_; - } - - // The vsync pose buffer if already mapped. - std::unique_ptr<CPUMappedBuffer> vsync_pose_buffer_; - - // The direct sensor pose buffer. - std::unique_ptr<SensorPoseRing> sensor_pose_buffer_; - - const DvrVsyncPoseBuffer* mapped_vsync_pose_buffer_ = nullptr; - - struct ControllerClientState { - std::unique_ptr<ConsumerBuffer> pose_buffer; - const DvrPoseAsync* mapped_pose_buffer = nullptr; - }; - ControllerClientState controllers_[MAX_CONTROLLERS]; -}; - -int dvrPoseClientGetDataReaderHandle(DvrPoseClient* client, uint64_t type, - ConsumerQueue** queue_out) { - return PoseClient::FromC(client)->GetTangoReaderHandle(type, queue_out); -} - -} // namespace dvr -} // namespace android - -using android::dvr::PoseClient; - -extern "C" { - -DvrPoseClient* dvrPoseClientCreate() { - auto* client = PoseClient::Create().release(); - return reinterpret_cast<DvrPoseClient*>(client); -} - -void dvrPoseClientDestroy(DvrPoseClient* client) { - delete PoseClient::FromC(client); -} - -int dvrPoseClientGet(DvrPoseClient* client, uint32_t vsync_count, - DvrPoseAsync* out_pose) { - return PoseClient::FromC(client)->GetPose(vsync_count, out_pose); -} - -uint32_t dvrPoseClientGetVsyncCount(DvrPoseClient* client) { - return PoseClient::FromC(client)->GetVsyncCount(); -} - -int dvrPoseClientGetController(DvrPoseClient* client, int32_t controller_id, - uint32_t vsync_count, DvrPoseAsync* out_pose) { - return PoseClient::FromC(client)->GetControllerPose(controller_id, - vsync_count, out_pose); -} - -int dvrPoseClientLogController(DvrPoseClient* client, bool enable) { - return PoseClient::FromC(client)->LogController(enable); -} - -int dvrPoseClientPoll(DvrPoseClient* client, DvrPose* state) { - return PoseClient::FromC(client)->Poll(state); -} - -int dvrPoseClientFreeze(DvrPoseClient* client, const DvrPose* frozen_state) { - return PoseClient::FromC(client)->Freeze(*frozen_state); -} - -int dvrPoseClientModeSet(DvrPoseClient* client, DvrPoseMode mode) { - return PoseClient::FromC(client)->SetMode(mode); -} - -int dvrPoseClientModeGet(DvrPoseClient* client, DvrPoseMode* mode) { - return PoseClient::FromC(client)->GetMode(mode); -} - -int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled) { - return PoseClient::FromC(client)->EnableSensors(enabled); -} - -int dvrPoseClientDataCapture(DvrPoseClient* client, - const DvrPoseDataCaptureRequest* request) { - return PoseClient::FromC(client)->DataCapture(request); -} - -int dvrPoseClientDataReaderDestroy(DvrPoseClient* client, uint64_t data_type) { - return PoseClient::FromC(client)->DataReaderDestroy(data_type); -} - -} // extern "C" diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index 484b0d3b7f..76dce63aac 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -125,9 +125,12 @@ public: /** * Set the touch mode state. - * Touch mode is a global state that apps may enter / exit based on specific - * user interactions with input devices. - * If true, the device is in touch mode. + * Touch mode is a per display state that apps may enter / exit based on specific user + * interactions with input devices. If <code>inTouchMode</code> is set to true, the display + * identified by <code>displayId</code> will be changed to touch mode. Performs a permission + * check if hasPermission is set to false. + * + * This method also enqueues a a TouchModeEntry message for dispatching. * * Returns true when changing touch mode state. */ diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 3b0f2ac5a2..6d6cefb0c0 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -23,6 +23,7 @@ #include <input/VelocityControl.h> #include <input/VelocityTracker.h> #include <stddef.h> +#include <ui/Rotation.h> #include <unistd.h> #include <utils/Errors.h> #include <utils/RefBase.h> @@ -395,7 +396,7 @@ public: /* Gets the affine calibration associated with the specified device. */ virtual TouchAffineTransformation getTouchAffineTransformation( - const std::string& inputDeviceDescriptor, int32_t surfaceRotation) = 0; + const std::string& inputDeviceDescriptor, ui::Rotation surfaceRotation) = 0; /* Notifies the input reader policy that a stylus gesture has started. */ virtual void notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) = 0; }; diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp index 24168a12a6..46e86de84c 100644 --- a/services/inputflinger/reader/Android.bp +++ b/services/inputflinger/reader/Android.bp @@ -58,6 +58,7 @@ filegroup { "mapper/accumulator/MultiTouchMotionAccumulator.cpp", "mapper/accumulator/SingleTouchMotionAccumulator.cpp", "mapper/accumulator/TouchButtonAccumulator.cpp", + "mapper/gestures/GesturesLogging.cpp", ], } @@ -69,16 +70,19 @@ cc_defaults { "libcap", "libcrypto", "libcutils", + "libjsoncpp", "liblog", "libstatslog", "libutils", ], static_libs: [ "libc++fs", + "libchrome-gestures", "libui-types", ], header_libs: [ "libbatteryservice_headers", + "libchrome-gestures_headers", "libinputreader_headers", ], target: { @@ -97,6 +101,22 @@ cc_defaults { }, } +cc_library_static { + name: "libinputreader_static", + defaults: [ + "inputflinger_defaults", + "libinputreader_defaults", + ], + shared_libs: [ + "libinputflinger_base", + ], + export_header_lib_headers: [ + "libbatteryservice_headers", + "libchrome-gestures_headers", + "libinputreader_headers", + ], +} + cc_library_shared { name: "libinputreader", host_supported: true, diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index a1a2af9500..13e4d0cfbe 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -227,7 +227,7 @@ std::list<NotifyArgs> CursorInputMapper::configure(nsecs_t when, mDisplayId = mPointerController->getDisplayId(); } - mOrientation = DISPLAY_ORIENTATION_0; + mOrientation = ui::ROTATION_0; const bool isOrientedDevice = (mParameters.orientationAware && mParameters.hasAssociatedDisplay); // InputReader works in the un-rotated display coordinate space, so we don't need to do diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index 20746e5bb0..939cceb6b0 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -22,6 +22,7 @@ #include <PointerControllerInterface.h> #include <input/VelocityControl.h> +#include <ui/Rotation.h> namespace android { @@ -115,7 +116,7 @@ private: // ADISPLAY_ID_NONE to target the focused display. If there is no display target (i.e. // std::nullopt), all events will be ignored. std::optional<int32_t> mDisplayId; - int32_t mOrientation; + ui::Rotation mOrientation; std::shared_ptr<PointerControllerInterface> mPointerController; diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp index da9413e4ca..44f0dfe3b6 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp @@ -20,11 +20,13 @@ #include "KeyboardInputMapper.h" +#include <ui/Rotation.h> + namespace android { // --- Static Definitions --- -static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { +static int32_t rotateKeyCode(int32_t keyCode, ui::Rotation orientation) { static constexpr int32_t KEYCODE_ROTATION_MAP[][4] = { // key codes enumerated counter-clockwise with the original (unrotated) key first // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation @@ -42,11 +44,10 @@ static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { AKEYCODE_SYSTEM_NAVIGATION_RIGHT, AKEYCODE_SYSTEM_NAVIGATION_UP}, }; - LOG_ALWAYS_FATAL_IF(orientation < 0 || orientation > 3, "Invalid orientation: %d", orientation); - if (orientation != DISPLAY_ORIENTATION_0) { + if (orientation != ui::ROTATION_0) { for (const auto& rotation : KEYCODE_ROTATION_MAP) { - if (rotation[DISPLAY_ORIENTATION_0] == keyCode) { - return rotation[orientation]; + if (rotation[static_cast<size_t>(ui::ROTATION_0)] == keyCode) { + return rotation[static_cast<size_t>(orientation)]; } } } @@ -100,11 +101,11 @@ uint32_t KeyboardInputMapper::getSources() const { return mSource; } -int32_t KeyboardInputMapper::getOrientation() { +ui::Rotation KeyboardInputMapper::getOrientation() { if (mViewport) { return mViewport->orientation; } - return DISPLAY_ORIENTATION_0; + return ui::ROTATION_0; } int32_t KeyboardInputMapper::getDisplayId() { diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h index 11d5ad26e8..0526fd89de 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h @@ -82,7 +82,7 @@ private: void configureParameters(); void dumpParameters(std::string& dump) const; - int32_t getOrientation(); + ui::Rotation getOrientation(); int32_t getDisplayId(); [[nodiscard]] std::list<NotifyArgs> processKey(nsecs_t when, nsecs_t readTime, bool down, diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp index 06d4dc342d..19a79d7751 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp @@ -25,7 +25,7 @@ namespace android { RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDeviceContext& deviceContext) - : InputMapper(deviceContext), mOrientation(DISPLAY_ORIENTATION_0) { + : InputMapper(deviceContext), mOrientation(ui::ROTATION_0) { mSource = AINPUT_SOURCE_ROTARY_ENCODER; } @@ -73,7 +73,7 @@ std::list<NotifyArgs> RotaryEncoderInputMapper::configure(nsecs_t when, if (internalViewport) { mOrientation = internalViewport->orientation; } else { - mOrientation = DISPLAY_ORIENTATION_0; + mOrientation = ui::ROTATION_0; } } return out; @@ -107,7 +107,7 @@ std::list<NotifyArgs> RotaryEncoderInputMapper::sync(nsecs_t when, nsecs_t readT // This is not a pointer, so it's not associated with a display. int32_t displayId = ADISPLAY_ID_NONE; - if (mOrientation == DISPLAY_ORIENTATION_180) { + if (mOrientation == ui::ROTATION_180) { scroll = -scroll; } diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h index f4352e76a0..cb5fd88209 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h @@ -16,6 +16,8 @@ #pragma once +#include <ui/Rotation.h> + #include "CursorScrollAccumulator.h" #include "InputMapper.h" @@ -40,7 +42,7 @@ private: int32_t mSource; float mScalingFactor; - int32_t mOrientation; + ui::Rotation mOrientation; [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime); }; diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h index d8a4d34d20..1c3ca975ac 100644 --- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h +++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h @@ -18,6 +18,7 @@ #include <input/DisplayViewport.h> #include <stdint.h> +#include <ui/Rotation.h> #include "EventHub.h" #include "InputListener.h" @@ -27,32 +28,32 @@ namespace android { // --- Static Definitions --- -static int32_t getInverseRotation(int32_t orientation) { +static ui::Rotation getInverseRotation(ui::Rotation orientation) { switch (orientation) { - case DISPLAY_ORIENTATION_90: - return DISPLAY_ORIENTATION_270; - case DISPLAY_ORIENTATION_270: - return DISPLAY_ORIENTATION_90; + case ui::ROTATION_90: + return ui::ROTATION_270; + case ui::ROTATION_270: + return ui::ROTATION_90; default: return orientation; } } -static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { +static void rotateDelta(ui::Rotation orientation, float* deltaX, float* deltaY) { float temp; switch (orientation) { - case DISPLAY_ORIENTATION_90: + case ui::ROTATION_90: temp = *deltaX; *deltaX = *deltaY; *deltaY = -temp; break; - case DISPLAY_ORIENTATION_180: + case ui::ROTATION_180: *deltaX = -*deltaX; *deltaY = -*deltaY; break; - case DISPLAY_ORIENTATION_270: + case ui::ROTATION_270: temp = *deltaX; *deltaX = -*deltaY; *deltaY = temp; diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 5be694f35f..cefc44ef7a 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -27,6 +27,7 @@ #include "CursorScrollAccumulator.h" #include "TouchButtonAccumulator.h" #include "TouchCursorInputMapperCommon.h" +#include "ui/Rotation.h" namespace android { @@ -42,6 +43,19 @@ static const float MIN_FREEFORM_GESTURE_WIDTH_IN_MILLIMETER = 30; static const DisplayViewport kUninitializedViewport; +static std::string toString(const Rect& rect) { + return base::StringPrintf("Rect{%d, %d, %d, %d}", rect.left, rect.top, rect.right, rect.bottom); +} + +static std::string toString(const ui::Size& size) { + return base::StringPrintf("%dx%d", size.width, size.height); +} + +static bool isPointInRect(const Rect& rect, int32_t x, int32_t y) { + // Consider all four sides as "inclusive". + return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom; +} + template <typename T> inline static void swap(T& a, T& b) { T temp = a; @@ -67,6 +81,31 @@ inline static int32_t signExtendNybble(int32_t value) { return value >= 8 ? value - 16 : value; } +static std::tuple<ui::Size /*displayBounds*/, Rect /*physicalFrame*/> getNaturalDisplayInfo( + const DisplayViewport& viewport, ui::Rotation naturalOrientation) { + ui::Size rotatedDisplaySize{viewport.deviceWidth, viewport.deviceHeight}; + if (naturalOrientation == ui::ROTATION_90 || naturalOrientation == ui::ROTATION_270) { + std::swap(rotatedDisplaySize.width, rotatedDisplaySize.height); + } + + ui::Transform rotate(ui::Transform::toRotationFlags(naturalOrientation), + rotatedDisplaySize.width, rotatedDisplaySize.height); + + Rect physicalFrame{viewport.physicalLeft, viewport.physicalTop, viewport.physicalRight, + viewport.physicalBottom}; + physicalFrame = rotate.transform(physicalFrame); + + LOG_ALWAYS_FATAL_IF(!physicalFrame.isValid()); + if (physicalFrame.isEmpty()) { + ALOGE("Viewport is not set properly: %s", viewport.toString().c_str()); + physicalFrame.right = + physicalFrame.left + (physicalFrame.width() == 0 ? 1 : physicalFrame.width()); + physicalFrame.bottom = + physicalFrame.top + (physicalFrame.height() == 0 ? 1 : physicalFrame.height()); + } + return {rotatedDisplaySize, physicalFrame}; +} + // --- RawPointerData --- void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const { @@ -93,13 +132,7 @@ TouchInputMapper::TouchInputMapper(InputDeviceContext& deviceContext) mTouchButtonAccumulator(deviceContext), mSource(0), mDeviceMode(DeviceMode::DISABLED), - mDisplayWidth(-1), - mDisplayHeight(-1), - mPhysicalWidth(-1), - mPhysicalHeight(-1), - mPhysicalLeft(0), - mPhysicalTop(0), - mInputDeviceOrientation(DISPLAY_ORIENTATION_0) {} + mInputDeviceOrientation(ui::ROTATION_0) {} TouchInputMapper::~TouchInputMapper() {} @@ -390,18 +423,18 @@ void TouchInputMapper::configureParameters() { getDeviceContext().getConfiguration().tryGetProperty("touch.orientationAware", mParameters.orientationAware); - mParameters.orientation = Parameters::Orientation::ORIENTATION_0; + mParameters.orientation = ui::ROTATION_0; std::string orientationString; if (getDeviceContext().getConfiguration().tryGetProperty("touch.orientation", orientationString)) { if (mParameters.deviceType != Parameters::DeviceType::TOUCH_SCREEN) { ALOGW("The configuration 'touch.orientation' is only supported for touchscreens."); } else if (orientationString == "ORIENTATION_90") { - mParameters.orientation = Parameters::Orientation::ORIENTATION_90; + mParameters.orientation = ui::ROTATION_90; } else if (orientationString == "ORIENTATION_180") { - mParameters.orientation = Parameters::Orientation::ORIENTATION_180; + mParameters.orientation = ui::ROTATION_180; } else if (orientationString == "ORIENTATION_270") { - mParameters.orientation = Parameters::Orientation::ORIENTATION_270; + mParameters.orientation = ui::ROTATION_270; } else if (orientationString != "ORIENTATION_0") { ALOGW("Invalid value for touch.orientation: '%s'", orientationString.c_str()); } @@ -564,7 +597,7 @@ void TouchInputMapper::initializeSizeRanges() { } // Size of diagonal axis. - const float diagonalSize = hypotf(mDisplayWidth, mDisplayHeight); + const float diagonalSize = hypotf(mDisplayBounds.width, mDisplayBounds.height); // Size factors. if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.touchMajor.maxValue != 0) { @@ -647,8 +680,8 @@ void TouchInputMapper::initializeSizeRanges() { void TouchInputMapper::initializeOrientedRanges() { // Configure X and Y factors. - mXScale = float(mDisplayWidth) / mRawPointerAxes.getRawWidth(); - mYScale = float(mDisplayHeight) / mRawPointerAxes.getRawHeight(); + mXScale = float(mDisplayBounds.width) / mRawPointerAxes.getRawWidth(); + mYScale = float(mDisplayBounds.height) / mRawPointerAxes.getRawHeight(); mXPrecision = 1.0f / mXScale; mYPrecision = 1.0f / mYScale; @@ -778,19 +811,19 @@ void TouchInputMapper::initializeOrientedRanges() { // Note that the maximum value reported is an inclusive maximum value so it is one // unit less than the total width or height of the display. switch (mInputDeviceOrientation) { - case DISPLAY_ORIENTATION_90: - case DISPLAY_ORIENTATION_270: + case ui::ROTATION_90: + case ui::ROTATION_270: mOrientedXPrecision = mYPrecision; mOrientedYPrecision = mXPrecision; mOrientedRanges.x.min = 0; - mOrientedRanges.x.max = mDisplayHeight - 1; + mOrientedRanges.x.max = mDisplayBounds.height - 1; mOrientedRanges.x.flat = 0; mOrientedRanges.x.fuzz = 0; mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale; mOrientedRanges.y.min = 0; - mOrientedRanges.y.max = mDisplayWidth - 1; + mOrientedRanges.y.max = mDisplayBounds.width - 1; mOrientedRanges.y.flat = 0; mOrientedRanges.y.fuzz = 0; mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale; @@ -801,13 +834,13 @@ void TouchInputMapper::initializeOrientedRanges() { mOrientedYPrecision = mYPrecision; mOrientedRanges.x.min = 0; - mOrientedRanges.x.max = mDisplayWidth - 1; + mOrientedRanges.x.max = mDisplayBounds.width - 1; mOrientedRanges.x.flat = 0; mOrientedRanges.x.fuzz = 0; mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale; mOrientedRanges.y.min = 0; - mOrientedRanges.y.max = mDisplayHeight - 1; + mOrientedRanges.y.max = mDisplayBounds.height - 1; mOrientedRanges.y.flat = 0; mOrientedRanges.y.fuzz = 0; mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale; @@ -868,8 +901,7 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) } // Raw width and height in the natural orientation. - const int32_t rawWidth = mRawPointerAxes.getRawWidth(); - const int32_t rawHeight = mRawPointerAxes.getRawHeight(); + const ui::Size rawSize{mRawPointerAxes.getRawWidth(), mRawPointerAxes.getRawHeight()}; const int32_t rawXResolution = mRawPointerAxes.x.resolution; const int32_t rawYResolution = mRawPointerAxes.y.resolution; // Calculate the mean resolution when both x and y resolution are set, otherwise set it to 0. @@ -885,67 +917,16 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) mViewport = newViewport; if (mDeviceMode == DeviceMode::DIRECT || mDeviceMode == DeviceMode::POINTER) { - // Convert rotated viewport to the natural orientation. - int32_t naturalPhysicalWidth, naturalPhysicalHeight; - int32_t naturalPhysicalLeft, naturalPhysicalTop; - int32_t naturalDeviceWidth, naturalDeviceHeight; + const auto oldDisplayBounds = mDisplayBounds; // Apply the inverse of the input device orientation so that the input device is // configured in the same orientation as the viewport. The input device orientation will // be re-applied by mInputDeviceOrientation. - const int32_t naturalDeviceOrientation = - (mViewport.orientation - static_cast<int32_t>(mParameters.orientation) + 4) % 4; - switch (naturalDeviceOrientation) { - case DISPLAY_ORIENTATION_90: - naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom; - naturalPhysicalTop = mViewport.physicalLeft; - naturalDeviceWidth = mViewport.deviceHeight; - naturalDeviceHeight = mViewport.deviceWidth; - break; - case DISPLAY_ORIENTATION_180: - naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight; - naturalPhysicalTop = mViewport.deviceHeight - mViewport.physicalBottom; - naturalDeviceWidth = mViewport.deviceWidth; - naturalDeviceHeight = mViewport.deviceHeight; - break; - case DISPLAY_ORIENTATION_270: - naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalLeft = mViewport.physicalTop; - naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight; - naturalDeviceWidth = mViewport.deviceHeight; - naturalDeviceHeight = mViewport.deviceWidth; - break; - case DISPLAY_ORIENTATION_0: - default: - naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalLeft = mViewport.physicalLeft; - naturalPhysicalTop = mViewport.physicalTop; - naturalDeviceWidth = mViewport.deviceWidth; - naturalDeviceHeight = mViewport.deviceHeight; - break; - } - - if (naturalPhysicalHeight == 0 || naturalPhysicalWidth == 0) { - ALOGE("Viewport is not set properly: %s", mViewport.toString().c_str()); - naturalPhysicalHeight = naturalPhysicalHeight == 0 ? 1 : naturalPhysicalHeight; - naturalPhysicalWidth = naturalPhysicalWidth == 0 ? 1 : naturalPhysicalWidth; - } - - mPhysicalWidth = naturalPhysicalWidth; - mPhysicalHeight = naturalPhysicalHeight; - mPhysicalLeft = naturalPhysicalLeft; - mPhysicalTop = naturalPhysicalTop; + const ui::Rotation naturalDeviceOrientation = + mViewport.orientation - mParameters.orientation; - const int32_t oldDisplayWidth = mDisplayWidth; - const int32_t oldDisplayHeight = mDisplayHeight; - mDisplayWidth = naturalDeviceWidth; - mDisplayHeight = naturalDeviceHeight; + std::tie(mDisplayBounds, mPhysicalFrameInDisplay) = + getNaturalDisplayInfo(mViewport, naturalDeviceOrientation); // InputReader works in the un-rotated display coordinate space, so we don't need to do // anything if the device is already orientation-aware. If the device is not @@ -953,26 +934,19 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) // when the display rotation is applied later as a part of the per-window transform, we // get the expected screen coordinates. mInputDeviceOrientation = mParameters.orientationAware - ? DISPLAY_ORIENTATION_0 + ? ui::ROTATION_0 : getInverseRotation(mViewport.orientation); // For orientation-aware devices that work in the un-rotated coordinate space, the // viewport update should be skipped if it is only a change in the orientation. skipViewportUpdate = !viewportDisplayIdChanged && mParameters.orientationAware && - mDisplayWidth == oldDisplayWidth && mDisplayHeight == oldDisplayHeight && - viewportOrientationChanged; + mDisplayBounds == oldDisplayBounds && viewportOrientationChanged; // Apply the input device orientation for the device. - mInputDeviceOrientation = - (mInputDeviceOrientation + static_cast<int32_t>(mParameters.orientation)) % 4; + mInputDeviceOrientation = mInputDeviceOrientation + mParameters.orientation; } else { - mPhysicalWidth = rawWidth; - mPhysicalHeight = rawHeight; - mPhysicalLeft = 0; - mPhysicalTop = 0; - - mDisplayWidth = rawWidth; - mDisplayHeight = rawHeight; - mInputDeviceOrientation = DISPLAY_ORIENTATION_0; + mDisplayBounds = rawSize; + mPhysicalFrameInDisplay = Rect{mDisplayBounds}; + mInputDeviceOrientation = ui::ROTATION_0; } } @@ -1003,9 +977,9 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) } if ((viewportChanged && !skipViewportUpdate) || deviceModeChanged) { - ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, " + ALOGI("Device reconfigured: id=%d, name='%s', size %s, orientation %d, mode %d, " "display id %d", - getDeviceId(), getDeviceName().c_str(), mDisplayWidth, mDisplayHeight, + getDeviceId(), getDeviceName().c_str(), toString(mDisplayBounds).c_str(), mInputDeviceOrientation, mDeviceMode, mViewport.displayId); configureVirtualKeys(); @@ -1017,8 +991,8 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) if (mDeviceMode == DeviceMode::POINTER) { // Compute pointer gesture detection parameters. - float rawDiagonal = hypotf(rawWidth, rawHeight); - float displayDiagonal = hypotf(mDisplayWidth, mDisplayHeight); + float rawDiagonal = hypotf(rawSize.width, rawSize.height); + float displayDiagonal = hypotf(mDisplayBounds.width, mDisplayBounds.height); // Scale movements such that one whole swipe of the touch pad covers a // given area relative to the diagonal size of the display when no acceleration @@ -1054,12 +1028,8 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) void TouchInputMapper::dumpDisplay(std::string& dump) { dump += StringPrintf(INDENT3 "%s\n", mViewport.toString().c_str()); - dump += StringPrintf(INDENT3 "DisplayWidth: %dpx\n", mDisplayWidth); - dump += StringPrintf(INDENT3 "DisplayHeight: %dpx\n", mDisplayHeight); - dump += StringPrintf(INDENT3 "PhysicalWidth: %dpx\n", mPhysicalWidth); - dump += StringPrintf(INDENT3 "PhysicalHeight: %dpx\n", mPhysicalHeight); - dump += StringPrintf(INDENT3 "PhysicalLeft: %d\n", mPhysicalLeft); - dump += StringPrintf(INDENT3 "PhysicalTop: %d\n", mPhysicalTop); + dump += StringPrintf(INDENT3 "DisplayBounds: %s\n", toString(mDisplayBounds).c_str()); + dump += StringPrintf(INDENT3 "PhysicalFrame: %s\n", toString(mPhysicalFrameInDisplay).c_str()); dump += StringPrintf(INDENT3 "InputDeviceOrientation: %d\n", mInputDeviceOrientation); } @@ -1098,17 +1068,17 @@ void TouchInputMapper::configureVirtualKeys() { int32_t halfWidth = virtualKeyDefinition.width / 2; int32_t halfHeight = virtualKeyDefinition.height / 2; - virtualKey.hitLeft = - (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mDisplayWidth + + virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / + mDisplayBounds.width + touchScreenLeft; - virtualKey.hitRight = - (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mDisplayWidth + + virtualKey.hitRight = (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / + mDisplayBounds.width + touchScreenLeft; - virtualKey.hitTop = - (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight / mDisplayHeight + + virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight / + mDisplayBounds.height + touchScreenTop; - virtualKey.hitBottom = - (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mDisplayHeight + + virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / + mDisplayBounds.height + touchScreenTop; mVirtualKeys.push_back(virtualKey); } @@ -2377,7 +2347,7 @@ void TouchInputMapper::cookPointerData() { float left, top, right, bottom; switch (mInputDeviceOrientation) { - case DISPLAY_ORIENTATION_90: + case ui::ROTATION_90: left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale; right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale; bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale; @@ -2388,7 +2358,7 @@ void TouchInputMapper::cookPointerData() { (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min); } break; - case DISPLAY_ORIENTATION_180: + case ui::ROTATION_180: left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale; right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale; bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale; @@ -2399,7 +2369,7 @@ void TouchInputMapper::cookPointerData() { (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min); } break; - case DISPLAY_ORIENTATION_270: + case ui::ROTATION_270: left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale; right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale; bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale; @@ -3833,19 +3803,19 @@ void TouchInputMapper::rotateAndScale(float& x, float& y) const { // 180 - reverse x, y. // 270 - swap x/y and reverse x. switch (mInputDeviceOrientation) { - case DISPLAY_ORIENTATION_0: + case ui::ROTATION_0: x = xScaled; y = yScaled; break; - case DISPLAY_ORIENTATION_90: + case ui::ROTATION_90: y = xScaledMax; x = yScaled; break; - case DISPLAY_ORIENTATION_180: + case ui::ROTATION_180: x = xScaledMax; y = yScaledMax; break; - case DISPLAY_ORIENTATION_270: + case ui::ROTATION_270: y = xScaled; x = yScaledMax; break; @@ -3859,9 +3829,8 @@ bool TouchInputMapper::isPointInsidePhysicalFrame(int32_t x, int32_t y) const { const float yScaled = (y - mRawPointerAxes.y.minValue) * mYScale; return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue && - xScaled >= mPhysicalLeft && xScaled <= (mPhysicalLeft + mPhysicalWidth) && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue && - yScaled >= mPhysicalTop && yScaled <= (mPhysicalTop + mPhysicalHeight); + isPointInRect(mPhysicalFrameInDisplay, xScaled, yScaled); } const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) { diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index 788ec586e2..34ba62515f 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -17,6 +17,7 @@ #pragma once #include <stdint.h> +#include <ui/Rotation.h> #include "CursorButtonAccumulator.h" #include "CursorScrollAccumulator.h" @@ -218,15 +219,7 @@ protected: bool associatedDisplayIsExternal; bool orientationAware; - enum class Orientation : int32_t { - ORIENTATION_0 = DISPLAY_ORIENTATION_0, - ORIENTATION_90 = DISPLAY_ORIENTATION_90, - ORIENTATION_180 = DISPLAY_ORIENTATION_180, - ORIENTATION_270 = DISPLAY_ORIENTATION_270, - - ftl_last = ORIENTATION_270 - }; - Orientation orientation; + ui::Rotation orientation; bool hasButtonUnderPad; std::string uniqueDisplayId; @@ -412,22 +405,19 @@ private: // The components of the viewport are specified in the display's rotated orientation. DisplayViewport mViewport; - // The width and height are obtained from the viewport and are specified - // in the natural orientation. - int32_t mDisplayWidth; - int32_t mDisplayHeight; + // We refer to the display as being in the "natural orientation" when there is no rotation + // applied. The display size obtained from the viewport in the natural orientation. + // Always starts at (0, 0). + ui::Size mDisplayBounds{ui::kInvalidSize}; - // The physical frame is the rectangle in the display's coordinate space that maps to the + // The physical frame is the rectangle in the natural display's coordinate space that maps to // the logical display frame. - int32_t mPhysicalWidth; - int32_t mPhysicalHeight; - int32_t mPhysicalLeft; - int32_t mPhysicalTop; + Rect mPhysicalFrameInDisplay{Rect::INVALID_RECT}; // The orientation of the input device relative to that of the display panel. It specifies // the rotation of the input device coordinates required to produce the display panel // orientation, so it will depend on whether the device is orientation aware. - int32_t mInputDeviceOrientation; + ui::Rotation mInputDeviceOrientation; // Translation and scaling factors, orientation-independent. float mXScale; diff --git a/services/inputflinger/reader/mapper/gestures/GesturesLogging.cpp b/services/inputflinger/reader/mapper/gestures/GesturesLogging.cpp new file mode 100644 index 0000000000..81b4968df8 --- /dev/null +++ b/services/inputflinger/reader/mapper/gestures/GesturesLogging.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2022 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 LOG_TAG +#define LOG_TAG "Gestures" +#endif + +#include <stdio.h> + +#include <log/log.h> + +#include "include/gestures.h" + +extern "C" { + +void gestures_log(int verb, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + if (verb == GESTURES_LOG_ERROR) { + LOG_PRI_VA(ANDROID_LOG_ERROR, LOG_TAG, fmt, args); + } else if (verb == GESTURES_LOG_INFO) { + LOG_PRI_VA(ANDROID_LOG_INFO, LOG_TAG, fmt, args); + } else { + LOG_PRI_VA(ANDROID_LOG_DEBUG, LOG_TAG, fmt, args); + } + va_end(args); +} +} diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index cf2a96a876..2e5bec9999 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -40,6 +40,9 @@ cc_test { "AnrTracker_test.cpp", "BlockingQueue_test.cpp", "EventHub_test.cpp", + "FakeEventHub.cpp", + "FakeInputReaderPolicy.cpp", + "FakePointerController.cpp", "FocusResolver_test.cpp", "InputProcessor_test.cpp", "InputProcessorConverter_test.cpp", diff --git a/services/inputflinger/tests/FakeEventHub.cpp b/services/inputflinger/tests/FakeEventHub.cpp new file mode 100644 index 0000000000..f6cf1cc304 --- /dev/null +++ b/services/inputflinger/tests/FakeEventHub.cpp @@ -0,0 +1,590 @@ +/* + * Copyright 2022 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 "FakeEventHub.h" + +#include <android-base/thread_annotations.h> +#include <gtest/gtest.h> +#include <linux/input-event-codes.h> + +#include "TestConstants.h" + +namespace android { + +const std::string FakeEventHub::BATTERY_DEVPATH = "/sys/devices/mydevice/power_supply/mybattery"; + +FakeEventHub::~FakeEventHub() { + for (size_t i = 0; i < mDevices.size(); i++) { + delete mDevices.valueAt(i); + } +} + +void FakeEventHub::addDevice(int32_t deviceId, const std::string& name, + ftl::Flags<InputDeviceClass> classes, int bus) { + Device* device = new Device(classes); + device->identifier.name = name; + device->identifier.bus = bus; + mDevices.add(deviceId, device); + + enqueueEvent(ARBITRARY_TIME, READ_TIME, deviceId, EventHubInterface::DEVICE_ADDED, 0, 0); +} + +void FakeEventHub::removeDevice(int32_t deviceId) { + delete mDevices.valueFor(deviceId); + mDevices.removeItem(deviceId); + + enqueueEvent(ARBITRARY_TIME, READ_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0); +} + +bool FakeEventHub::isDeviceEnabled(int32_t deviceId) const { + Device* device = getDevice(deviceId); + if (device == nullptr) { + ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); + return false; + } + return device->enabled; +} + +status_t FakeEventHub::enableDevice(int32_t deviceId) { + status_t result; + Device* device = getDevice(deviceId); + if (device == nullptr) { + ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); + return BAD_VALUE; + } + if (device->enabled) { + ALOGW("Duplicate call to %s, device %" PRId32 " already enabled", __func__, deviceId); + return OK; + } + result = device->enable(); + return result; +} + +status_t FakeEventHub::disableDevice(int32_t deviceId) { + Device* device = getDevice(deviceId); + if (device == nullptr) { + ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); + return BAD_VALUE; + } + if (!device->enabled) { + ALOGW("Duplicate call to %s, device %" PRId32 " already disabled", __func__, deviceId); + return OK; + } + return device->disable(); +} + +void FakeEventHub::finishDeviceScan() { + enqueueEvent(ARBITRARY_TIME, READ_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0); +} + +void FakeEventHub::addConfigurationProperty(int32_t deviceId, const char* key, const char* value) { + getDevice(deviceId)->configuration.addProperty(key, value); +} + +void FakeEventHub::addConfigurationMap(int32_t deviceId, const PropertyMap* configuration) { + getDevice(deviceId)->configuration.addAll(configuration); +} + +void FakeEventHub::addAbsoluteAxis(int32_t deviceId, int axis, int32_t minValue, int32_t maxValue, + int flat, int fuzz, int resolution) { + Device* device = getDevice(deviceId); + + RawAbsoluteAxisInfo info; + info.valid = true; + info.minValue = minValue; + info.maxValue = maxValue; + info.flat = flat; + info.fuzz = fuzz; + info.resolution = resolution; + device->absoluteAxes.add(axis, info); +} + +void FakeEventHub::addRelativeAxis(int32_t deviceId, int32_t axis) { + getDevice(deviceId)->relativeAxes.add(axis, true); +} + +void FakeEventHub::setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state) { + getDevice(deviceId)->keyCodeStates.replaceValueFor(keyCode, state); +} + +void FakeEventHub::setCountryCode(int32_t deviceId, InputDeviceCountryCode countryCode) { + getDevice(deviceId)->countryCode = countryCode; +} + +void FakeEventHub::setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state) { + getDevice(deviceId)->scanCodeStates.replaceValueFor(scanCode, state); +} + +void FakeEventHub::setSwitchState(int32_t deviceId, int32_t switchCode, int32_t state) { + getDevice(deviceId)->switchStates.replaceValueFor(switchCode, state); +} + +void FakeEventHub::setAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t value) { + getDevice(deviceId)->absoluteAxisValue.replaceValueFor(axis, value); +} + +void FakeEventHub::addKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t keyCode, + uint32_t flags) { + Device* device = getDevice(deviceId); + KeyInfo info; + info.keyCode = keyCode; + info.flags = flags; + if (scanCode) { + device->keysByScanCode.add(scanCode, info); + } + if (usageCode) { + device->keysByUsageCode.add(usageCode, info); + } +} + +void FakeEventHub::addKeyCodeMapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) { + getDevice(deviceId)->keyCodeMapping.insert_or_assign(fromKeyCode, toKeyCode); +} + +void FakeEventHub::addLed(int32_t deviceId, int32_t led, bool initialState) { + getDevice(deviceId)->leds.add(led, initialState); +} + +void FakeEventHub::addSensorAxis(int32_t deviceId, int32_t absCode, + InputDeviceSensorType sensorType, int32_t sensorDataIndex) { + SensorInfo info; + info.sensorType = sensorType; + info.sensorDataIndex = sensorDataIndex; + getDevice(deviceId)->sensorsByAbsCode.emplace(absCode, info); +} + +void FakeEventHub::setMscEvent(int32_t deviceId, int32_t mscEvent) { + typename BitArray<MSC_MAX>::Buffer buffer; + buffer[mscEvent / 32] = 1 << mscEvent % 32; + getDevice(deviceId)->mscBitmask.loadFromBuffer(buffer); +} + +void FakeEventHub::addRawLightInfo(int32_t rawId, RawLightInfo&& info) { + mRawLightInfos.emplace(rawId, std::move(info)); +} + +void FakeEventHub::fakeLightBrightness(int32_t rawId, int32_t brightness) { + mLightBrightness.emplace(rawId, brightness); +} + +void FakeEventHub::fakeLightIntensities(int32_t rawId, + const std::unordered_map<LightColor, int32_t> intensities) { + mLightIntensities.emplace(rawId, std::move(intensities)); +} + +bool FakeEventHub::getLedState(int32_t deviceId, int32_t led) { + return getDevice(deviceId)->leds.valueFor(led); +} + +std::vector<std::string>& FakeEventHub::getExcludedDevices() { + return mExcludedDevices; +} + +void FakeEventHub::addVirtualKeyDefinition(int32_t deviceId, + const VirtualKeyDefinition& definition) { + getDevice(deviceId)->virtualKeys.push_back(definition); +} + +void FakeEventHub::enqueueEvent(nsecs_t when, nsecs_t readTime, int32_t deviceId, int32_t type, + int32_t code, int32_t value) { + std::scoped_lock<std::mutex> lock(mLock); + RawEvent event; + event.when = when; + event.readTime = readTime; + event.deviceId = deviceId; + event.type = type; + event.code = code; + event.value = value; + mEvents.push_back(event); + + if (type == EV_ABS) { + setAbsoluteAxisValue(deviceId, code, value); + } +} + +void FakeEventHub::setVideoFrames( + std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> videoFrames) { + mVideoFrames = std::move(videoFrames); +} + +void FakeEventHub::assertQueueIsEmpty() { + std::unique_lock<std::mutex> lock(mLock); + base::ScopedLockAssertion assumeLocked(mLock); + const bool queueIsEmpty = + mEventsCondition.wait_for(lock, WAIT_TIMEOUT, + [this]() REQUIRES(mLock) { return mEvents.size() == 0; }); + if (!queueIsEmpty) { + FAIL() << "Timed out waiting for EventHub queue to be emptied."; + } +} + +FakeEventHub::Device* FakeEventHub::getDevice(int32_t deviceId) const { + ssize_t index = mDevices.indexOfKey(deviceId); + return index >= 0 ? mDevices.valueAt(index) : nullptr; +} + +ftl::Flags<InputDeviceClass> FakeEventHub::getDeviceClasses(int32_t deviceId) const { + Device* device = getDevice(deviceId); + return device ? device->classes : ftl::Flags<InputDeviceClass>(0); +} + +InputDeviceIdentifier FakeEventHub::getDeviceIdentifier(int32_t deviceId) const { + Device* device = getDevice(deviceId); + return device ? device->identifier : InputDeviceIdentifier(); +} + +int32_t FakeEventHub::getDeviceControllerNumber(int32_t) const { + return 0; +} + +void FakeEventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const { + Device* device = getDevice(deviceId); + if (device) { + *outConfiguration = device->configuration; + } +} + +status_t FakeEventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, + RawAbsoluteAxisInfo* outAxisInfo) const { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->absoluteAxes.indexOfKey(axis); + if (index >= 0) { + *outAxisInfo = device->absoluteAxes.valueAt(index); + return OK; + } + } + outAxisInfo->clear(); + return -1; +} + +bool FakeEventHub::hasRelativeAxis(int32_t deviceId, int axis) const { + Device* device = getDevice(deviceId); + if (device) { + return device->relativeAxes.indexOfKey(axis) >= 0; + } + return false; +} + +bool FakeEventHub::hasInputProperty(int32_t, int) const { + return false; +} + +bool FakeEventHub::hasMscEvent(int32_t deviceId, int mscEvent) const { + Device* device = getDevice(deviceId); + if (device) { + return mscEvent >= 0 && mscEvent <= MSC_MAX ? device->mscBitmask.test(mscEvent) : false; + } + return false; +} + +status_t FakeEventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, + int32_t metaState, int32_t* outKeycode, int32_t* outMetaState, + uint32_t* outFlags) const { + Device* device = getDevice(deviceId); + if (device) { + const KeyInfo* key = getKey(device, scanCode, usageCode); + if (key) { + if (outKeycode) { + *outKeycode = key->keyCode; + } + if (outFlags) { + *outFlags = key->flags; + } + if (outMetaState) { + *outMetaState = metaState; + } + return OK; + } + } + return NAME_NOT_FOUND; +} + +const FakeEventHub::KeyInfo* FakeEventHub::getKey(Device* device, int32_t scanCode, + int32_t usageCode) const { + if (usageCode) { + ssize_t index = device->keysByUsageCode.indexOfKey(usageCode); + if (index >= 0) { + return &device->keysByUsageCode.valueAt(index); + } + } + if (scanCode) { + ssize_t index = device->keysByScanCode.indexOfKey(scanCode); + if (index >= 0) { + return &device->keysByScanCode.valueAt(index); + } + } + return nullptr; +} + +status_t FakeEventHub::mapAxis(int32_t, int32_t, AxisInfo*) const { + return NAME_NOT_FOUND; +} + +base::Result<std::pair<InputDeviceSensorType, int32_t>> FakeEventHub::mapSensor( + int32_t deviceId, int32_t absCode) const { + Device* device = getDevice(deviceId); + if (!device) { + return Errorf("Sensor device not found."); + } + auto it = device->sensorsByAbsCode.find(absCode); + if (it == device->sensorsByAbsCode.end()) { + return Errorf("Sensor map not found."); + } + const SensorInfo& info = it->second; + return std::make_pair(info.sensorType, info.sensorDataIndex); +} + +void FakeEventHub::setExcludedDevices(const std::vector<std::string>& devices) { + mExcludedDevices = devices; +} + +std::vector<RawEvent> FakeEventHub::getEvents(int) { + std::scoped_lock lock(mLock); + + std::vector<RawEvent> buffer; + std::swap(buffer, mEvents); + + mEventsCondition.notify_all(); + return buffer; +} + +std::vector<TouchVideoFrame> FakeEventHub::getVideoFrames(int32_t deviceId) { + auto it = mVideoFrames.find(deviceId); + if (it != mVideoFrames.end()) { + std::vector<TouchVideoFrame> frames = std::move(it->second); + mVideoFrames.erase(deviceId); + return frames; + } + return {}; +} + +int32_t FakeEventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->scanCodeStates.indexOfKey(scanCode); + if (index >= 0) { + return device->scanCodeStates.valueAt(index); + } + } + return AKEY_STATE_UNKNOWN; +} + +InputDeviceCountryCode FakeEventHub::getCountryCode(int32_t deviceId) const { + Device* device = getDevice(deviceId); + return device ? device->countryCode : InputDeviceCountryCode::INVALID; +} + +int32_t FakeEventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->keyCodeStates.indexOfKey(keyCode); + if (index >= 0) { + return device->keyCodeStates.valueAt(index); + } + } + return AKEY_STATE_UNKNOWN; +} + +int32_t FakeEventHub::getSwitchState(int32_t deviceId, int32_t sw) const { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->switchStates.indexOfKey(sw); + if (index >= 0) { + return device->switchStates.valueAt(index); + } + } + return AKEY_STATE_UNKNOWN; +} + +status_t FakeEventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, + int32_t* outValue) const { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->absoluteAxisValue.indexOfKey(axis); + if (index >= 0) { + *outValue = device->absoluteAxisValue.valueAt(index); + return OK; + } + } + *outValue = 0; + return -1; +} + +int32_t FakeEventHub::getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const { + Device* device = getDevice(deviceId); + if (!device) { + return AKEYCODE_UNKNOWN; + } + auto it = device->keyCodeMapping.find(locationKeyCode); + return it != device->keyCodeMapping.end() ? it->second : locationKeyCode; +} + +// Return true if the device has non-empty key layout. +bool FakeEventHub::markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes, + uint8_t* outFlags) const { + Device* device = getDevice(deviceId); + if (!device) return false; + + bool result = device->keysByScanCode.size() > 0 || device->keysByUsageCode.size() > 0; + for (size_t i = 0; i < keyCodes.size(); i++) { + for (size_t j = 0; j < device->keysByScanCode.size(); j++) { + if (keyCodes[i] == device->keysByScanCode.valueAt(j).keyCode) { + outFlags[i] = 1; + } + } + for (size_t j = 0; j < device->keysByUsageCode.size(); j++) { + if (keyCodes[i] == device->keysByUsageCode.valueAt(j).keyCode) { + outFlags[i] = 1; + } + } + } + return result; +} + +bool FakeEventHub::hasScanCode(int32_t deviceId, int32_t scanCode) const { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->keysByScanCode.indexOfKey(scanCode); + return index >= 0; + } + return false; +} + +bool FakeEventHub::hasKeyCode(int32_t deviceId, int32_t keyCode) const { + Device* device = getDevice(deviceId); + if (!device) { + return false; + } + for (size_t i = 0; i < device->keysByScanCode.size(); i++) { + if (keyCode == device->keysByScanCode.valueAt(i).keyCode) { + return true; + } + } + for (size_t j = 0; j < device->keysByUsageCode.size(); j++) { + if (keyCode == device->keysByUsageCode.valueAt(j).keyCode) { + return true; + } + } + return false; +} + +bool FakeEventHub::hasLed(int32_t deviceId, int32_t led) const { + Device* device = getDevice(deviceId); + return device && device->leds.indexOfKey(led) >= 0; +} + +void FakeEventHub::setLedState(int32_t deviceId, int32_t led, bool on) { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->leds.indexOfKey(led); + if (index >= 0) { + device->leds.replaceValueAt(led, on); + } else { + ADD_FAILURE() << "Attempted to set the state of an LED that the EventHub declared " + "was not present. led=" + << led; + } + } +} + +void FakeEventHub::getVirtualKeyDefinitions( + int32_t deviceId, std::vector<VirtualKeyDefinition>& outVirtualKeys) const { + outVirtualKeys.clear(); + + Device* device = getDevice(deviceId); + if (device) { + outVirtualKeys = device->virtualKeys; + } +} + +const std::shared_ptr<KeyCharacterMap> FakeEventHub::getKeyCharacterMap(int32_t) const { + return nullptr; +} + +bool FakeEventHub::setKeyboardLayoutOverlay(int32_t, std::shared_ptr<KeyCharacterMap>) { + return false; +} + +std::vector<int32_t> FakeEventHub::getVibratorIds(int32_t deviceId) const { + return mVibrators; +} + +std::optional<int32_t> FakeEventHub::getBatteryCapacity(int32_t, int32_t) const { + return BATTERY_CAPACITY; +} + +std::optional<int32_t> FakeEventHub::getBatteryStatus(int32_t, int32_t) const { + return BATTERY_STATUS; +} + +std::vector<int32_t> FakeEventHub::getRawBatteryIds(int32_t deviceId) const { + return {DEFAULT_BATTERY}; +} + +std::optional<RawBatteryInfo> FakeEventHub::getRawBatteryInfo(int32_t deviceId, + int32_t batteryId) const { + if (batteryId != DEFAULT_BATTERY) return {}; + static const auto BATTERY_INFO = RawBatteryInfo{.id = DEFAULT_BATTERY, + .name = "default battery", + .flags = InputBatteryClass::CAPACITY, + .path = BATTERY_DEVPATH}; + return BATTERY_INFO; +} + +std::vector<int32_t> FakeEventHub::getRawLightIds(int32_t deviceId) const { + std::vector<int32_t> ids; + for (const auto& [rawId, info] : mRawLightInfos) { + ids.push_back(rawId); + } + return ids; +} + +std::optional<RawLightInfo> FakeEventHub::getRawLightInfo(int32_t deviceId, int32_t lightId) const { + auto it = mRawLightInfos.find(lightId); + if (it == mRawLightInfos.end()) { + return std::nullopt; + } + return it->second; +} + +void FakeEventHub::setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) { + mLightBrightness.emplace(lightId, brightness); +} + +void FakeEventHub::setLightIntensities(int32_t deviceId, int32_t lightId, + std::unordered_map<LightColor, int32_t> intensities) { + mLightIntensities.emplace(lightId, intensities); +}; + +std::optional<int32_t> FakeEventHub::getLightBrightness(int32_t deviceId, int32_t lightId) const { + auto lightIt = mLightBrightness.find(lightId); + if (lightIt == mLightBrightness.end()) { + return std::nullopt; + } + return lightIt->second; +} + +std::optional<std::unordered_map<LightColor, int32_t>> FakeEventHub::getLightIntensities( + int32_t deviceId, int32_t lightId) const { + auto lightIt = mLightIntensities.find(lightId); + if (lightIt == mLightIntensities.end()) { + return std::nullopt; + } + return lightIt->second; +}; + +} // namespace android diff --git a/services/inputflinger/tests/FakeEventHub.h b/services/inputflinger/tests/FakeEventHub.h new file mode 100644 index 0000000000..21cb2f1963 --- /dev/null +++ b/services/inputflinger/tests/FakeEventHub.h @@ -0,0 +1,224 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <condition_variable> +#include <mutex> +#include <optional> +#include <unordered_map> +#include <vector> + +#include <EventHub.h> +#include <InputDevice.h> +#include <ftl/flags.h> +#include <input/PropertyMap.h> +#include <input/VirtualKeyMap.h> +#include <utils/Errors.h> +#include <utils/KeyedVector.h> + +#include "android/hardware/input/InputDeviceCountryCode.h" + +using android::hardware::input::InputDeviceCountryCode; + +namespace android { + +class FakeEventHub : public EventHubInterface { + struct KeyInfo { + int32_t keyCode; + uint32_t flags; + }; + + struct SensorInfo { + InputDeviceSensorType sensorType; + int32_t sensorDataIndex; + }; + + struct Device { + InputDeviceIdentifier identifier; + ftl::Flags<InputDeviceClass> classes; + PropertyMap configuration; + KeyedVector<int, RawAbsoluteAxisInfo> absoluteAxes; + KeyedVector<int, bool> relativeAxes; + KeyedVector<int32_t, int32_t> keyCodeStates; + KeyedVector<int32_t, int32_t> scanCodeStates; + KeyedVector<int32_t, int32_t> switchStates; + KeyedVector<int32_t, int32_t> absoluteAxisValue; + KeyedVector<int32_t, KeyInfo> keysByScanCode; + KeyedVector<int32_t, KeyInfo> keysByUsageCode; + KeyedVector<int32_t, bool> leds; + // fake mapping which would normally come from keyCharacterMap + std::unordered_map<int32_t, int32_t> keyCodeMapping; + std::unordered_map<int32_t, SensorInfo> sensorsByAbsCode; + BitArray<MSC_MAX> mscBitmask; + std::vector<VirtualKeyDefinition> virtualKeys; + bool enabled; + InputDeviceCountryCode countryCode; + + status_t enable() { + enabled = true; + return OK; + } + + status_t disable() { + enabled = false; + return OK; + } + + explicit Device(ftl::Flags<InputDeviceClass> classes) : classes(classes), enabled(true) {} + }; + + std::mutex mLock; + std::condition_variable mEventsCondition; + + KeyedVector<int32_t, Device*> mDevices; + std::vector<std::string> mExcludedDevices; + std::vector<RawEvent> mEvents GUARDED_BY(mLock); + std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames; + std::vector<int32_t> mVibrators = {0, 1}; + std::unordered_map<int32_t, RawLightInfo> mRawLightInfos; + // Simulates a device light brightness, from light id to light brightness. + std::unordered_map<int32_t /* lightId */, int32_t /* brightness*/> mLightBrightness; + // Simulates a device light intensities, from light id to light intensities map. + std::unordered_map<int32_t /* lightId */, std::unordered_map<LightColor, int32_t>> + mLightIntensities; + +public: + static constexpr int32_t DEFAULT_BATTERY = 1; + static constexpr int32_t BATTERY_STATUS = 4; + static constexpr int32_t BATTERY_CAPACITY = 66; + static const std::string BATTERY_DEVPATH; + + virtual ~FakeEventHub(); + FakeEventHub() {} + + void addDevice(int32_t deviceId, const std::string& name, ftl::Flags<InputDeviceClass> classes, + int bus = 0); + void removeDevice(int32_t deviceId); + + bool isDeviceEnabled(int32_t deviceId) const override; + status_t enableDevice(int32_t deviceId) override; + status_t disableDevice(int32_t deviceId) override; + + void finishDeviceScan(); + + void addConfigurationProperty(int32_t deviceId, const char* key, const char* value); + void addConfigurationMap(int32_t deviceId, const PropertyMap* configuration); + + void addAbsoluteAxis(int32_t deviceId, int axis, int32_t minValue, int32_t maxValue, int flat, + int fuzz, int resolution = 0); + void addRelativeAxis(int32_t deviceId, int32_t axis); + void setAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t value); + + void setCountryCode(int32_t deviceId, InputDeviceCountryCode countryCode); + + void setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state); + void setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state); + void setSwitchState(int32_t deviceId, int32_t switchCode, int32_t state); + + void addKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t keyCode, + uint32_t flags); + void addKeyCodeMapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode); + void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition); + + void addSensorAxis(int32_t deviceId, int32_t absCode, InputDeviceSensorType sensorType, + int32_t sensorDataIndex); + + void setMscEvent(int32_t deviceId, int32_t mscEvent); + + void addLed(int32_t deviceId, int32_t led, bool initialState); + void addRawLightInfo(int32_t rawId, RawLightInfo&& info); + void fakeLightBrightness(int32_t rawId, int32_t brightness); + void fakeLightIntensities(int32_t rawId, + const std::unordered_map<LightColor, int32_t> intensities); + bool getLedState(int32_t deviceId, int32_t led); + + std::vector<std::string>& getExcludedDevices(); + + void setVideoFrames( + std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> videoFrames); + + void enqueueEvent(nsecs_t when, nsecs_t readTime, int32_t deviceId, int32_t type, int32_t code, + int32_t value); + void assertQueueIsEmpty(); + +private: + Device* getDevice(int32_t deviceId) const; + + ftl::Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override; + InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override; + int32_t getDeviceControllerNumber(int32_t) const override; + void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const override; + status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, + RawAbsoluteAxisInfo* outAxisInfo) const override; + bool hasRelativeAxis(int32_t deviceId, int axis) const override; + bool hasInputProperty(int32_t, int) const override; + bool hasMscEvent(int32_t deviceId, int mscEvent) const override final; + status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, + int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const override; + const KeyInfo* getKey(Device* device, int32_t scanCode, int32_t usageCode) const; + + status_t mapAxis(int32_t, int32_t, AxisInfo*) const override; + base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor( + int32_t deviceId, int32_t absCode) const override; + void setExcludedDevices(const std::vector<std::string>& devices) override; + std::vector<RawEvent> getEvents(int) override; + std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override; + int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override; + InputDeviceCountryCode getCountryCode(int32_t deviceId) const override; + int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override; + int32_t getSwitchState(int32_t deviceId, int32_t sw) const override; + status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const override; + int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const override; + + // Return true if the device has non-empty key layout. + bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes, + uint8_t* outFlags) const override; + bool hasScanCode(int32_t deviceId, int32_t scanCode) const override; + bool hasKeyCode(int32_t deviceId, int32_t keyCode) const override; + bool hasLed(int32_t deviceId, int32_t led) const override; + void setLedState(int32_t deviceId, int32_t led, bool on) override; + void getVirtualKeyDefinitions(int32_t deviceId, + std::vector<VirtualKeyDefinition>& outVirtualKeys) const override; + const std::shared_ptr<KeyCharacterMap> getKeyCharacterMap(int32_t) const override; + bool setKeyboardLayoutOverlay(int32_t, std::shared_ptr<KeyCharacterMap>) override; + + void vibrate(int32_t, const VibrationElement&) override {} + void cancelVibrate(int32_t) override {} + std::vector<int32_t> getVibratorIds(int32_t deviceId) const override; + + std::optional<int32_t> getBatteryCapacity(int32_t, int32_t) const override; + std::optional<int32_t> getBatteryStatus(int32_t, int32_t) const override; + std::vector<int32_t> getRawBatteryIds(int32_t deviceId) const override; + std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId, + int32_t batteryId) const override; + + std::vector<int32_t> getRawLightIds(int32_t deviceId) const override; + std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) const override; + void setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) override; + void setLightIntensities(int32_t deviceId, int32_t lightId, + std::unordered_map<LightColor, int32_t> intensities) override; + std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) const override; + std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities( + int32_t deviceId, int32_t lightId) const override; + + void dump(std::string&) const override {} + void monitor() const override {} + void requestReopenDevices() override {} + void wake() override {} +}; + +} // namespace android diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp new file mode 100644 index 0000000000..3af4298434 --- /dev/null +++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp @@ -0,0 +1,237 @@ +/* + * Copyright 2022 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 "FakeInputReaderPolicy.h" + +#include <android-base/thread_annotations.h> +#include <gtest/gtest.h> + +#include "TestConstants.h" +#include "ui/Rotation.h" + +namespace android { + +void FakeInputReaderPolicy::assertInputDevicesChanged() { + waitForInputDevices([](bool devicesChanged) { + if (!devicesChanged) { + FAIL() << "Timed out waiting for notifyInputDevicesChanged() to be called."; + } + }); +} + +void FakeInputReaderPolicy::assertInputDevicesNotChanged() { + waitForInputDevices([](bool devicesChanged) { + if (devicesChanged) { + FAIL() << "Expected notifyInputDevicesChanged() to not be called."; + } + }); +} + +void FakeInputReaderPolicy::assertStylusGestureNotified(int32_t deviceId) { + std::scoped_lock lock(mLock); + ASSERT_TRUE(mStylusGestureNotified); + ASSERT_EQ(deviceId, *mStylusGestureNotified); + mStylusGestureNotified.reset(); +} + +void FakeInputReaderPolicy::assertStylusGestureNotNotified() { + std::scoped_lock lock(mLock); + ASSERT_FALSE(mStylusGestureNotified); +} + +void FakeInputReaderPolicy::clearViewports() { + mViewports.clear(); + mConfig.setDisplayViewports(mViewports); +} + +std::optional<DisplayViewport> FakeInputReaderPolicy::getDisplayViewportByUniqueId( + const std::string& uniqueId) const { + return mConfig.getDisplayViewportByUniqueId(uniqueId); +} +std::optional<DisplayViewport> FakeInputReaderPolicy::getDisplayViewportByType( + ViewportType type) const { + return mConfig.getDisplayViewportByType(type); +} + +std::optional<DisplayViewport> FakeInputReaderPolicy::getDisplayViewportByPort( + uint8_t displayPort) const { + return mConfig.getDisplayViewportByPort(displayPort); +} + +void FakeInputReaderPolicy::addDisplayViewport(DisplayViewport viewport) { + mViewports.push_back(std::move(viewport)); + mConfig.setDisplayViewports(mViewports); +} + +void FakeInputReaderPolicy::addDisplayViewport(int32_t displayId, int32_t width, int32_t height, + ui::Rotation orientation, bool isActive, + const std::string& uniqueId, + std::optional<uint8_t> physicalPort, + ViewportType type) { + const bool isRotated = orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270; + DisplayViewport v; + v.displayId = displayId; + v.orientation = orientation; + v.logicalLeft = 0; + v.logicalTop = 0; + v.logicalRight = isRotated ? height : width; + v.logicalBottom = isRotated ? width : height; + v.physicalLeft = 0; + v.physicalTop = 0; + v.physicalRight = isRotated ? height : width; + v.physicalBottom = isRotated ? width : height; + v.deviceWidth = isRotated ? height : width; + v.deviceHeight = isRotated ? width : height; + v.isActive = isActive; + v.uniqueId = uniqueId; + v.physicalPort = physicalPort; + v.type = type; + + addDisplayViewport(v); +} + +bool FakeInputReaderPolicy::updateViewport(const DisplayViewport& viewport) { + size_t count = mViewports.size(); + for (size_t i = 0; i < count; i++) { + const DisplayViewport& currentViewport = mViewports[i]; + if (currentViewport.displayId == viewport.displayId) { + mViewports[i] = viewport; + mConfig.setDisplayViewports(mViewports); + return true; + } + } + // no viewport found. + return false; +} + +void FakeInputReaderPolicy::addExcludedDeviceName(const std::string& deviceName) { + mConfig.excludedDeviceNames.push_back(deviceName); +} + +void FakeInputReaderPolicy::addInputPortAssociation(const std::string& inputPort, + uint8_t displayPort) { + mConfig.portAssociations.insert({inputPort, displayPort}); +} + +void FakeInputReaderPolicy::addInputUniqueIdAssociation(const std::string& inputUniqueId, + const std::string& displayUniqueId) { + mConfig.uniqueIdAssociations.insert({inputUniqueId, displayUniqueId}); +} + +void FakeInputReaderPolicy::addDisabledDevice(int32_t deviceId) { + mConfig.disabledDevices.insert(deviceId); +} + +void FakeInputReaderPolicy::removeDisabledDevice(int32_t deviceId) { + mConfig.disabledDevices.erase(deviceId); +} + +void FakeInputReaderPolicy::setPointerController( + std::shared_ptr<FakePointerController> controller) { + mPointerController = std::move(controller); +} + +const InputReaderConfiguration* FakeInputReaderPolicy::getReaderConfiguration() const { + return &mConfig; +} + +const std::vector<InputDeviceInfo>& FakeInputReaderPolicy::getInputDevices() const { + return mInputDevices; +} + +TouchAffineTransformation FakeInputReaderPolicy::getTouchAffineTransformation( + const std::string& inputDeviceDescriptor, ui::Rotation surfaceRotation) { + return transform; +} + +void FakeInputReaderPolicy::setTouchAffineTransformation(const TouchAffineTransformation t) { + transform = t; +} + +PointerCaptureRequest FakeInputReaderPolicy::setPointerCapture(bool enabled) { + mConfig.pointerCaptureRequest = {enabled, mNextPointerCaptureSequenceNumber++}; + return mConfig.pointerCaptureRequest; +} + +void FakeInputReaderPolicy::setShowTouches(bool enabled) { + mConfig.showTouches = enabled; +} + +void FakeInputReaderPolicy::setDefaultPointerDisplayId(int32_t pointerDisplayId) { + mConfig.defaultPointerDisplayId = pointerDisplayId; +} + +void FakeInputReaderPolicy::setPointerGestureEnabled(bool enabled) { + mConfig.pointerGesturesEnabled = enabled; +} + +float FakeInputReaderPolicy::getPointerGestureMovementSpeedRatio() { + return mConfig.pointerGestureMovementSpeedRatio; +} + +float FakeInputReaderPolicy::getPointerGestureZoomSpeedRatio() { + return mConfig.pointerGestureZoomSpeedRatio; +} + +void FakeInputReaderPolicy::setVelocityControlParams(const VelocityControlParameters& params) { + mConfig.pointerVelocityControlParameters = params; + mConfig.wheelVelocityControlParameters = params; +} + +void FakeInputReaderPolicy::getReaderConfiguration(InputReaderConfiguration* outConfig) { + *outConfig = mConfig; +} + +std::shared_ptr<PointerControllerInterface> FakeInputReaderPolicy::obtainPointerController( + int32_t /*deviceId*/) { + return mPointerController; +} + +void FakeInputReaderPolicy::notifyInputDevicesChanged( + const std::vector<InputDeviceInfo>& inputDevices) { + std::scoped_lock<std::mutex> lock(mLock); + mInputDevices = inputDevices; + mInputDevicesChanged = true; + mDevicesChangedCondition.notify_all(); +} + +std::shared_ptr<KeyCharacterMap> FakeInputReaderPolicy::getKeyboardLayoutOverlay( + const InputDeviceIdentifier&) { + return nullptr; +} + +std::string FakeInputReaderPolicy::getDeviceAlias(const InputDeviceIdentifier&) { + return ""; +} + +void FakeInputReaderPolicy::waitForInputDevices(std::function<void(bool)> processDevicesChanged) { + std::unique_lock<std::mutex> lock(mLock); + base::ScopedLockAssertion assumeLocked(mLock); + + const bool devicesChanged = + mDevicesChangedCondition.wait_for(lock, WAIT_TIMEOUT, [this]() REQUIRES(mLock) { + return mInputDevicesChanged; + }); + ASSERT_NO_FATAL_FAILURE(processDevicesChanged(devicesChanged)); + mInputDevicesChanged = false; +} + +void FakeInputReaderPolicy::notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) { + std::scoped_lock<std::mutex> lock(mLock); + mStylusGestureNotified = deviceId; +} + +} // namespace android diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.h b/services/inputflinger/tests/FakeInputReaderPolicy.h new file mode 100644 index 0000000000..c16cda404e --- /dev/null +++ b/services/inputflinger/tests/FakeInputReaderPolicy.h @@ -0,0 +1,101 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <condition_variable> +#include <memory> +#include <mutex> +#include <optional> +#include <string> +#include <vector> + +#include <InputDevice.h> +#include <InputReaderBase.h> + +#include "FakePointerController.h" +#include "input/DisplayViewport.h" +#include "input/InputDevice.h" + +namespace android { + +class FakeInputReaderPolicy : public InputReaderPolicyInterface { +protected: + virtual ~FakeInputReaderPolicy() {} + +public: + FakeInputReaderPolicy() {} + + void assertInputDevicesChanged(); + void assertInputDevicesNotChanged(); + void assertStylusGestureNotified(int32_t deviceId); + void assertStylusGestureNotNotified(); + + virtual void clearViewports(); + std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueId) const; + std::optional<DisplayViewport> getDisplayViewportByType(ViewportType type) const; + std::optional<DisplayViewport> getDisplayViewportByPort(uint8_t displayPort) const; + void addDisplayViewport(DisplayViewport viewport); + void addDisplayViewport(int32_t displayId, int32_t width, int32_t height, + ui::Rotation orientation, bool isActive, const std::string& uniqueId, + std::optional<uint8_t> physicalPort, ViewportType type); + bool updateViewport(const DisplayViewport& viewport); + void addExcludedDeviceName(const std::string& deviceName); + void addInputPortAssociation(const std::string& inputPort, uint8_t displayPort); + void addInputUniqueIdAssociation(const std::string& inputUniqueId, + const std::string& displayUniqueId); + void addDisabledDevice(int32_t deviceId); + void removeDisabledDevice(int32_t deviceId); + void setPointerController(std::shared_ptr<FakePointerController> controller); + const InputReaderConfiguration* getReaderConfiguration() const; + const std::vector<InputDeviceInfo>& getInputDevices() const; + TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor, + ui::Rotation surfaceRotation); + void setTouchAffineTransformation(const TouchAffineTransformation t); + PointerCaptureRequest setPointerCapture(bool enabled); + void setShowTouches(bool enabled); + void setDefaultPointerDisplayId(int32_t pointerDisplayId); + void setPointerGestureEnabled(bool enabled); + float getPointerGestureMovementSpeedRatio(); + float getPointerGestureZoomSpeedRatio(); + void setVelocityControlParams(const VelocityControlParameters& params); + +private: + void getReaderConfiguration(InputReaderConfiguration* outConfig) override; + std::shared_ptr<PointerControllerInterface> obtainPointerController( + int32_t /*deviceId*/) override; + void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override; + std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( + const InputDeviceIdentifier&) override; + std::string getDeviceAlias(const InputDeviceIdentifier&) override; + void waitForInputDevices(std::function<void(bool)> processDevicesChanged); + void notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) override; + + std::mutex mLock; + std::condition_variable mDevicesChangedCondition; + + InputReaderConfiguration mConfig; + std::shared_ptr<FakePointerController> mPointerController; + std::vector<InputDeviceInfo> mInputDevices GUARDED_BY(mLock); + bool mInputDevicesChanged GUARDED_BY(mLock){false}; + std::vector<DisplayViewport> mViewports; + TouchAffineTransformation transform; + std::optional<int32_t /*deviceId*/> mStylusGestureNotified GUARDED_BY(mLock){}; + + uint32_t mNextPointerCaptureSequenceNumber{0}; +}; + +} // namespace android diff --git a/services/inputflinger/tests/FakePointerController.cpp b/services/inputflinger/tests/FakePointerController.cpp new file mode 100644 index 0000000000..635366bff2 --- /dev/null +++ b/services/inputflinger/tests/FakePointerController.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 2022 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 "FakePointerController.h" + +namespace android { + +void FakePointerController::setBounds(float minX, float minY, float maxX, float maxY) { + mHaveBounds = true; + mMinX = minX; + mMinY = minY; + mMaxX = maxX; + mMaxY = maxY; +} + +const std::map<int32_t, std::vector<int32_t>>& FakePointerController::getSpots() { + return mSpotsByDisplay; +} + +void FakePointerController::setPosition(float x, float y) { + mX = x; + mY = y; +} + +void FakePointerController::setButtonState(int32_t buttonState) { + mButtonState = buttonState; +} + +int32_t FakePointerController::getButtonState() const { + return mButtonState; +} + +void FakePointerController::getPosition(float* outX, float* outY) const { + *outX = mX; + *outY = mY; +} + +int32_t FakePointerController::getDisplayId() const { + return mDisplayId; +} + +void FakePointerController::setDisplayViewport(const DisplayViewport& viewport) { + mDisplayId = viewport.displayId; +} + +bool FakePointerController::getBounds(float* outMinX, float* outMinY, float* outMaxX, + float* outMaxY) const { + *outMinX = mMinX; + *outMinY = mMinY; + *outMaxX = mMaxX; + *outMaxY = mMaxY; + return mHaveBounds; +} + +void FakePointerController::move(float deltaX, float deltaY) { + mX += deltaX; + if (mX < mMinX) mX = mMinX; + if (mX > mMaxX) mX = mMaxX; + mY += deltaY; + if (mY < mMinY) mY = mMinY; + if (mY > mMaxY) mY = mMaxY; +} + +void FakePointerController::setSpots(const PointerCoords*, const uint32_t*, BitSet32 spotIdBits, + int32_t displayId) { + std::vector<int32_t> newSpots; + // Add spots for fingers that are down. + for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) { + uint32_t id = idBits.clearFirstMarkedBit(); + newSpots.push_back(id); + } + + mSpotsByDisplay[displayId] = newSpots; +} + +void FakePointerController::clearSpots() { + mSpotsByDisplay.clear(); +} + +} // namespace android diff --git a/services/inputflinger/tests/FakePointerController.h b/services/inputflinger/tests/FakePointerController.h new file mode 100644 index 0000000000..f00870f13c --- /dev/null +++ b/services/inputflinger/tests/FakePointerController.h @@ -0,0 +1,60 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <PointerControllerInterface.h> +#include <gui/constants.h> +#include <input/DisplayViewport.h> +#include <input/Input.h> +#include <utils/BitSet.h> + +namespace android { + +class FakePointerController : public PointerControllerInterface { +public: + virtual ~FakePointerController() {} + + void setBounds(float minX, float minY, float maxX, float maxY); + const std::map<int32_t, std::vector<int32_t>>& getSpots(); + + void setPosition(float x, float y) override; + void setButtonState(int32_t buttonState) override; + int32_t getButtonState() const override; + void getPosition(float* outX, float* outY) const override; + int32_t getDisplayId() const override; + void setDisplayViewport(const DisplayViewport& viewport) override; + +private: + bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const override; + void move(float deltaX, float deltaY) override; + void fade(Transition) override {} + void unfade(Transition) override {} + void setPresentation(Presentation) override {} + void setSpots(const PointerCoords*, const uint32_t*, BitSet32 spotIdBits, + int32_t displayId) override; + void clearSpots() override; + + bool mHaveBounds{false}; + float mMinX{0}, mMinY{0}, mMaxX{0}, mMaxY{0}; + float mX{0}, mY{0}; + int32_t mButtonState{0}; + int32_t mDisplayId{ADISPLAY_ID_DEFAULT}; + + std::map<int32_t, std::vector<int32_t>> mSpotsByDisplay; +}; + +} // namespace android diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 6b6d0bbfaa..01539671d8 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -36,10 +36,16 @@ #include <UinputDevice.h> #include <VibratorInputMapper.h> #include <android-base/thread_annotations.h> +#include <ftl/enum.h> #include <gtest/gtest.h> #include <gui/constants.h> +#include <ui/Rotation.h> #include <thread> +#include "FakeEventHub.h" +#include "FakeInputReaderPolicy.h" +#include "FakePointerController.h" +#include "TestConstants.h" #include "android/hardware/input/InputDeviceCountryCode.h" #include "input/DisplayViewport.h" #include "input/Input.h" @@ -52,13 +58,6 @@ using namespace ftl::flag_operators; using testing::AllOf; using std::chrono_literals::operator""ms; -// Timeout for waiting for an expected event -static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms; - -// An arbitrary time value. -static constexpr nsecs_t ARBITRARY_TIME = 1234; -static constexpr nsecs_t READ_TIME = 4321; - // Arbitrary display properties. static constexpr int32_t DISPLAY_ID = 0; static const std::string DISPLAY_UNIQUE_ID = "local:1"; @@ -79,10 +78,6 @@ static constexpr int32_t INVALID_TRACKING_ID = -1; static constexpr int32_t FIRST_TRACKING_ID = 0; static constexpr int32_t SECOND_TRACKING_ID = 1; static constexpr int32_t THIRD_TRACKING_ID = 2; -static constexpr int32_t DEFAULT_BATTERY = 1; -static constexpr int32_t BATTERY_STATUS = 4; -static constexpr int32_t BATTERY_CAPACITY = 66; -static const std::string BATTERY_DEVPATH = "/sys/devices/mydevice/power_supply/mybattery"; static constexpr int32_t LIGHT_BRIGHTNESS = 0x55000000; static constexpr int32_t LIGHT_COLOR = 0x7F448866; static constexpr int32_t LIGHT_PLAYER_ID = 2; @@ -118,12 +113,12 @@ const std::unordered_map<std::string, LightColor> LIGHT_COLORS = {{"red", LightC {"green", LightColor::GREEN}, {"blue", LightColor::BLUE}}; -static int32_t getInverseRotation(int32_t orientation) { +static ui::Rotation getInverseRotation(ui::Rotation orientation) { switch (orientation) { - case DISPLAY_ORIENTATION_90: - return DISPLAY_ORIENTATION_270; - case DISPLAY_ORIENTATION_270: - return DISPLAY_ORIENTATION_90; + case ui::ROTATION_90: + return ui::ROTATION_270; + case ui::ROTATION_270: + return ui::ROTATION_90; default: return orientation; } @@ -157,960 +152,6 @@ static void assertAxisNotPresent(MultiTouchInputMapper& mapper, int axis) { } } -// --- FakePointerController --- - -class FakePointerController : public PointerControllerInterface { - bool mHaveBounds; - float mMinX, mMinY, mMaxX, mMaxY; - float mX, mY; - int32_t mButtonState; - int32_t mDisplayId; - -public: - FakePointerController() : - mHaveBounds(false), mMinX(0), mMinY(0), mMaxX(0), mMaxY(0), mX(0), mY(0), - mButtonState(0), mDisplayId(ADISPLAY_ID_DEFAULT) { - } - - virtual ~FakePointerController() {} - - void setBounds(float minX, float minY, float maxX, float maxY) { - mHaveBounds = true; - mMinX = minX; - mMinY = minY; - mMaxX = maxX; - mMaxY = maxY; - } - - void setPosition(float x, float y) override { - mX = x; - mY = y; - } - - void setButtonState(int32_t buttonState) override { mButtonState = buttonState; } - - int32_t getButtonState() const override { return mButtonState; } - - void getPosition(float* outX, float* outY) const override { - *outX = mX; - *outY = mY; - } - - int32_t getDisplayId() const override { return mDisplayId; } - - void setDisplayViewport(const DisplayViewport& viewport) override { - mDisplayId = viewport.displayId; - } - - const std::map<int32_t, std::vector<int32_t>>& getSpots() { - return mSpotsByDisplay; - } - -private: - bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const override { - *outMinX = mMinX; - *outMinY = mMinY; - *outMaxX = mMaxX; - *outMaxY = mMaxY; - return mHaveBounds; - } - - void move(float deltaX, float deltaY) override { - mX += deltaX; - if (mX < mMinX) mX = mMinX; - if (mX > mMaxX) mX = mMaxX; - mY += deltaY; - if (mY < mMinY) mY = mMinY; - if (mY > mMaxY) mY = mMaxY; - } - - void fade(Transition) override {} - - void unfade(Transition) override {} - - void setPresentation(Presentation) override {} - - void setSpots(const PointerCoords*, const uint32_t*, BitSet32 spotIdBits, - int32_t displayId) override { - std::vector<int32_t> newSpots; - // Add spots for fingers that are down. - for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - newSpots.push_back(id); - } - - mSpotsByDisplay[displayId] = newSpots; - } - - void clearSpots() override { mSpotsByDisplay.clear(); } - - std::map<int32_t, std::vector<int32_t>> mSpotsByDisplay; -}; - - -// --- FakeInputReaderPolicy --- - -class FakeInputReaderPolicy : public InputReaderPolicyInterface { - std::mutex mLock; - std::condition_variable mDevicesChangedCondition; - - InputReaderConfiguration mConfig; - std::shared_ptr<FakePointerController> mPointerController; - std::vector<InputDeviceInfo> mInputDevices GUARDED_BY(mLock); - bool mInputDevicesChanged GUARDED_BY(mLock){false}; - std::vector<DisplayViewport> mViewports; - TouchAffineTransformation transform; - std::optional<int32_t /*deviceId*/> mStylusGestureNotified GUARDED_BY(mLock){}; - -protected: - virtual ~FakeInputReaderPolicy() {} - -public: - FakeInputReaderPolicy() { - } - - void assertInputDevicesChanged() { - waitForInputDevices([](bool devicesChanged) { - if (!devicesChanged) { - FAIL() << "Timed out waiting for notifyInputDevicesChanged() to be called."; - } - }); - } - - void assertInputDevicesNotChanged() { - waitForInputDevices([](bool devicesChanged) { - if (devicesChanged) { - FAIL() << "Expected notifyInputDevicesChanged() to not be called."; - } - }); - } - - void assertStylusGestureNotified(int32_t deviceId) { - std::scoped_lock lock(mLock); - ASSERT_TRUE(mStylusGestureNotified); - ASSERT_EQ(deviceId, *mStylusGestureNotified); - mStylusGestureNotified.reset(); - } - - void assertStylusGestureNotNotified() { - std::scoped_lock lock(mLock); - ASSERT_FALSE(mStylusGestureNotified); - } - - virtual void clearViewports() { - mViewports.clear(); - mConfig.setDisplayViewports(mViewports); - } - - std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueId) const { - return mConfig.getDisplayViewportByUniqueId(uniqueId); - } - std::optional<DisplayViewport> getDisplayViewportByType(ViewportType type) const { - return mConfig.getDisplayViewportByType(type); - } - - std::optional<DisplayViewport> getDisplayViewportByPort(uint8_t displayPort) const { - return mConfig.getDisplayViewportByPort(displayPort); - } - - void addDisplayViewport(DisplayViewport viewport) { - mViewports.push_back(std::move(viewport)); - mConfig.setDisplayViewports(mViewports); - } - - void addDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation, - bool isActive, const std::string& uniqueId, - std::optional<uint8_t> physicalPort, ViewportType type) { - const bool isRotated = - (orientation == DISPLAY_ORIENTATION_90 || orientation == DISPLAY_ORIENTATION_270); - DisplayViewport v; - v.displayId = displayId; - v.orientation = orientation; - v.logicalLeft = 0; - v.logicalTop = 0; - v.logicalRight = isRotated ? height : width; - v.logicalBottom = isRotated ? width : height; - v.physicalLeft = 0; - v.physicalTop = 0; - v.physicalRight = isRotated ? height : width; - v.physicalBottom = isRotated ? width : height; - v.deviceWidth = isRotated ? height : width; - v.deviceHeight = isRotated ? width : height; - v.isActive = isActive; - v.uniqueId = uniqueId; - v.physicalPort = physicalPort; - v.type = type; - - addDisplayViewport(v); - } - - bool updateViewport(const DisplayViewport& viewport) { - size_t count = mViewports.size(); - for (size_t i = 0; i < count; i++) { - const DisplayViewport& currentViewport = mViewports[i]; - if (currentViewport.displayId == viewport.displayId) { - mViewports[i] = viewport; - mConfig.setDisplayViewports(mViewports); - return true; - } - } - // no viewport found. - return false; - } - - void addExcludedDeviceName(const std::string& deviceName) { - mConfig.excludedDeviceNames.push_back(deviceName); - } - - void addInputPortAssociation(const std::string& inputPort, uint8_t displayPort) { - mConfig.portAssociations.insert({inputPort, displayPort}); - } - - void addInputUniqueIdAssociation(const std::string& inputUniqueId, - const std::string& displayUniqueId) { - mConfig.uniqueIdAssociations.insert({inputUniqueId, displayUniqueId}); - } - - void addDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.insert(deviceId); } - - void removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); } - - void setPointerController(std::shared_ptr<FakePointerController> controller) { - mPointerController = std::move(controller); - } - - const InputReaderConfiguration* getReaderConfiguration() const { - return &mConfig; - } - - const std::vector<InputDeviceInfo>& getInputDevices() const { - return mInputDevices; - } - - TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor, - int32_t surfaceRotation) { - return transform; - } - - void setTouchAffineTransformation(const TouchAffineTransformation t) { - transform = t; - } - - PointerCaptureRequest setPointerCapture(bool enabled) { - mConfig.pointerCaptureRequest = {enabled, mNextPointerCaptureSequenceNumber++}; - return mConfig.pointerCaptureRequest; - } - - void setShowTouches(bool enabled) { - mConfig.showTouches = enabled; - } - - void setDefaultPointerDisplayId(int32_t pointerDisplayId) { - mConfig.defaultPointerDisplayId = pointerDisplayId; - } - - void setPointerGestureEnabled(bool enabled) { mConfig.pointerGesturesEnabled = enabled; } - - float getPointerGestureMovementSpeedRatio() { return mConfig.pointerGestureMovementSpeedRatio; } - - float getPointerGestureZoomSpeedRatio() { return mConfig.pointerGestureZoomSpeedRatio; } - - void setVelocityControlParams(const VelocityControlParameters& params) { - mConfig.pointerVelocityControlParameters = params; - mConfig.wheelVelocityControlParameters = params; - } - -private: - uint32_t mNextPointerCaptureSequenceNumber = 0; - - void getReaderConfiguration(InputReaderConfiguration* outConfig) override { - *outConfig = mConfig; - } - - std::shared_ptr<PointerControllerInterface> obtainPointerController( - int32_t /*deviceId*/) override { - return mPointerController; - } - - void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override { - std::scoped_lock<std::mutex> lock(mLock); - mInputDevices = inputDevices; - mInputDevicesChanged = true; - mDevicesChangedCondition.notify_all(); - } - - std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( - const InputDeviceIdentifier&) override { - return nullptr; - } - - std::string getDeviceAlias(const InputDeviceIdentifier&) override { return ""; } - - void waitForInputDevices(std::function<void(bool)> processDevicesChanged) { - std::unique_lock<std::mutex> lock(mLock); - base::ScopedLockAssertion assumeLocked(mLock); - - const bool devicesChanged = - mDevicesChangedCondition.wait_for(lock, WAIT_TIMEOUT, [this]() REQUIRES(mLock) { - return mInputDevicesChanged; - }); - ASSERT_NO_FATAL_FAILURE(processDevicesChanged(devicesChanged)); - mInputDevicesChanged = false; - } - - void notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) override { - std::scoped_lock<std::mutex> lock(mLock); - mStylusGestureNotified = deviceId; - } -}; - -// --- FakeEventHub --- - -class FakeEventHub : public EventHubInterface { - struct KeyInfo { - int32_t keyCode; - uint32_t flags; - }; - - struct SensorInfo { - InputDeviceSensorType sensorType; - int32_t sensorDataIndex; - }; - - struct Device { - InputDeviceIdentifier identifier; - ftl::Flags<InputDeviceClass> classes; - PropertyMap configuration; - KeyedVector<int, RawAbsoluteAxisInfo> absoluteAxes; - KeyedVector<int, bool> relativeAxes; - KeyedVector<int32_t, int32_t> keyCodeStates; - KeyedVector<int32_t, int32_t> scanCodeStates; - KeyedVector<int32_t, int32_t> switchStates; - KeyedVector<int32_t, int32_t> absoluteAxisValue; - KeyedVector<int32_t, KeyInfo> keysByScanCode; - KeyedVector<int32_t, KeyInfo> keysByUsageCode; - KeyedVector<int32_t, bool> leds; - // fake mapping which would normally come from keyCharacterMap - std::unordered_map<int32_t, int32_t> keyCodeMapping; - std::unordered_map<int32_t, SensorInfo> sensorsByAbsCode; - BitArray<MSC_MAX> mscBitmask; - std::vector<VirtualKeyDefinition> virtualKeys; - bool enabled; - InputDeviceCountryCode countryCode; - - status_t enable() { - enabled = true; - return OK; - } - - status_t disable() { - enabled = false; - return OK; - } - - explicit Device(ftl::Flags<InputDeviceClass> classes) : classes(classes), enabled(true) {} - }; - - std::mutex mLock; - std::condition_variable mEventsCondition; - - KeyedVector<int32_t, Device*> mDevices; - std::vector<std::string> mExcludedDevices; - std::vector<RawEvent> mEvents GUARDED_BY(mLock); - std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames; - std::vector<int32_t> mVibrators = {0, 1}; - std::unordered_map<int32_t, RawLightInfo> mRawLightInfos; - // Simulates a device light brightness, from light id to light brightness. - std::unordered_map<int32_t /* lightId */, int32_t /* brightness*/> mLightBrightness; - // Simulates a device light intensities, from light id to light intensities map. - std::unordered_map<int32_t /* lightId */, std::unordered_map<LightColor, int32_t>> - mLightIntensities; - -public: - virtual ~FakeEventHub() { - for (size_t i = 0; i < mDevices.size(); i++) { - delete mDevices.valueAt(i); - } - } - - FakeEventHub() { } - - void addDevice(int32_t deviceId, const std::string& name, ftl::Flags<InputDeviceClass> classes, - int bus = 0) { - Device* device = new Device(classes); - device->identifier.name = name; - device->identifier.bus = bus; - mDevices.add(deviceId, device); - - enqueueEvent(ARBITRARY_TIME, READ_TIME, deviceId, EventHubInterface::DEVICE_ADDED, 0, 0); - } - - void removeDevice(int32_t deviceId) { - delete mDevices.valueFor(deviceId); - mDevices.removeItem(deviceId); - - enqueueEvent(ARBITRARY_TIME, READ_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0); - } - - bool isDeviceEnabled(int32_t deviceId) const override { - Device* device = getDevice(deviceId); - if (device == nullptr) { - ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); - return false; - } - return device->enabled; - } - - status_t enableDevice(int32_t deviceId) override { - status_t result; - Device* device = getDevice(deviceId); - if (device == nullptr) { - ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); - return BAD_VALUE; - } - if (device->enabled) { - ALOGW("Duplicate call to %s, device %" PRId32 " already enabled", __func__, deviceId); - return OK; - } - result = device->enable(); - return result; - } - - status_t disableDevice(int32_t deviceId) override { - Device* device = getDevice(deviceId); - if (device == nullptr) { - ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); - return BAD_VALUE; - } - if (!device->enabled) { - ALOGW("Duplicate call to %s, device %" PRId32 " already disabled", __func__, deviceId); - return OK; - } - return device->disable(); - } - - void finishDeviceScan() { - enqueueEvent(ARBITRARY_TIME, READ_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0); - } - - void addConfigurationProperty(int32_t deviceId, const char* key, const char* value) { - Device* device = getDevice(deviceId); - device->configuration.addProperty(key, value); - } - - void addConfigurationMap(int32_t deviceId, const PropertyMap* configuration) { - Device* device = getDevice(deviceId); - device->configuration.addAll(configuration); - } - - void addAbsoluteAxis(int32_t deviceId, int axis, - int32_t minValue, int32_t maxValue, int flat, int fuzz, int resolution = 0) { - Device* device = getDevice(deviceId); - - RawAbsoluteAxisInfo info; - info.valid = true; - info.minValue = minValue; - info.maxValue = maxValue; - info.flat = flat; - info.fuzz = fuzz; - info.resolution = resolution; - device->absoluteAxes.add(axis, info); - } - - void addRelativeAxis(int32_t deviceId, int32_t axis) { - Device* device = getDevice(deviceId); - device->relativeAxes.add(axis, true); - } - - void setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state) { - Device* device = getDevice(deviceId); - device->keyCodeStates.replaceValueFor(keyCode, state); - } - - void setCountryCode(int32_t deviceId, InputDeviceCountryCode countryCode) { - Device* device = getDevice(deviceId); - device->countryCode = countryCode; - } - - void setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state) { - Device* device = getDevice(deviceId); - device->scanCodeStates.replaceValueFor(scanCode, state); - } - - void setSwitchState(int32_t deviceId, int32_t switchCode, int32_t state) { - Device* device = getDevice(deviceId); - device->switchStates.replaceValueFor(switchCode, state); - } - - void setAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t value) { - Device* device = getDevice(deviceId); - device->absoluteAxisValue.replaceValueFor(axis, value); - } - - void addKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, - int32_t keyCode, uint32_t flags) { - Device* device = getDevice(deviceId); - KeyInfo info; - info.keyCode = keyCode; - info.flags = flags; - if (scanCode) { - device->keysByScanCode.add(scanCode, info); - } - if (usageCode) { - device->keysByUsageCode.add(usageCode, info); - } - } - - void addKeyCodeMapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) { - Device* device = getDevice(deviceId); - device->keyCodeMapping.insert_or_assign(fromKeyCode, toKeyCode); - } - - void addLed(int32_t deviceId, int32_t led, bool initialState) { - Device* device = getDevice(deviceId); - device->leds.add(led, initialState); - } - - void addSensorAxis(int32_t deviceId, int32_t absCode, InputDeviceSensorType sensorType, - int32_t sensorDataIndex) { - Device* device = getDevice(deviceId); - SensorInfo info; - info.sensorType = sensorType; - info.sensorDataIndex = sensorDataIndex; - device->sensorsByAbsCode.emplace(absCode, info); - } - - void setMscEvent(int32_t deviceId, int32_t mscEvent) { - Device* device = getDevice(deviceId); - typename BitArray<MSC_MAX>::Buffer buffer; - buffer[mscEvent / 32] = 1 << mscEvent % 32; - device->mscBitmask.loadFromBuffer(buffer); - } - - void addRawLightInfo(int32_t rawId, RawLightInfo&& info) { - mRawLightInfos.emplace(rawId, std::move(info)); - } - - void fakeLightBrightness(int32_t rawId, int32_t brightness) { - mLightBrightness.emplace(rawId, brightness); - } - - void fakeLightIntensities(int32_t rawId, - const std::unordered_map<LightColor, int32_t> intensities) { - mLightIntensities.emplace(rawId, std::move(intensities)); - } - - bool getLedState(int32_t deviceId, int32_t led) { - Device* device = getDevice(deviceId); - return device->leds.valueFor(led); - } - - std::vector<std::string>& getExcludedDevices() { - return mExcludedDevices; - } - - void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) { - Device* device = getDevice(deviceId); - device->virtualKeys.push_back(definition); - } - - void enqueueEvent(nsecs_t when, nsecs_t readTime, int32_t deviceId, int32_t type, int32_t code, - int32_t value) { - std::scoped_lock<std::mutex> lock(mLock); - RawEvent event; - event.when = when; - event.readTime = readTime; - event.deviceId = deviceId; - event.type = type; - event.code = code; - event.value = value; - mEvents.push_back(event); - - if (type == EV_ABS) { - setAbsoluteAxisValue(deviceId, code, value); - } - } - - void setVideoFrames(std::unordered_map<int32_t /*deviceId*/, - std::vector<TouchVideoFrame>> videoFrames) { - mVideoFrames = std::move(videoFrames); - } - - void assertQueueIsEmpty() { - std::unique_lock<std::mutex> lock(mLock); - base::ScopedLockAssertion assumeLocked(mLock); - const bool queueIsEmpty = - mEventsCondition.wait_for(lock, WAIT_TIMEOUT, - [this]() REQUIRES(mLock) { return mEvents.size() == 0; }); - if (!queueIsEmpty) { - FAIL() << "Timed out waiting for EventHub queue to be emptied."; - } - } - -private: - Device* getDevice(int32_t deviceId) const { - ssize_t index = mDevices.indexOfKey(deviceId); - return index >= 0 ? mDevices.valueAt(index) : nullptr; - } - - ftl::Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override { - Device* device = getDevice(deviceId); - return device ? device->classes : ftl::Flags<InputDeviceClass>(0); - } - - InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override { - Device* device = getDevice(deviceId); - return device ? device->identifier : InputDeviceIdentifier(); - } - - int32_t getDeviceControllerNumber(int32_t) const override { return 0; } - - void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const override { - Device* device = getDevice(deviceId); - if (device) { - *outConfiguration = device->configuration; - } - } - - status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const override { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->absoluteAxes.indexOfKey(axis); - if (index >= 0) { - *outAxisInfo = device->absoluteAxes.valueAt(index); - return OK; - } - } - outAxisInfo->clear(); - return -1; - } - - bool hasRelativeAxis(int32_t deviceId, int axis) const override { - Device* device = getDevice(deviceId); - if (device) { - return device->relativeAxes.indexOfKey(axis) >= 0; - } - return false; - } - - bool hasInputProperty(int32_t, int) const override { return false; } - - bool hasMscEvent(int32_t deviceId, int mscEvent) const override final { - Device* device = getDevice(deviceId); - if (device) { - return mscEvent >= 0 && mscEvent <= MSC_MAX ? device->mscBitmask.test(mscEvent) : false; - } - return false; - } - - status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, - int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const override { - Device* device = getDevice(deviceId); - if (device) { - const KeyInfo* key = getKey(device, scanCode, usageCode); - if (key) { - if (outKeycode) { - *outKeycode = key->keyCode; - } - if (outFlags) { - *outFlags = key->flags; - } - if (outMetaState) { - *outMetaState = metaState; - } - return OK; - } - } - return NAME_NOT_FOUND; - } - - const KeyInfo* getKey(Device* device, int32_t scanCode, int32_t usageCode) const { - if (usageCode) { - ssize_t index = device->keysByUsageCode.indexOfKey(usageCode); - if (index >= 0) { - return &device->keysByUsageCode.valueAt(index); - } - } - if (scanCode) { - ssize_t index = device->keysByScanCode.indexOfKey(scanCode); - if (index >= 0) { - return &device->keysByScanCode.valueAt(index); - } - } - return nullptr; - } - - status_t mapAxis(int32_t, int32_t, AxisInfo*) const override { return NAME_NOT_FOUND; } - - base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor( - int32_t deviceId, int32_t absCode) const override { - Device* device = getDevice(deviceId); - if (!device) { - return Errorf("Sensor device not found."); - } - auto it = device->sensorsByAbsCode.find(absCode); - if (it == device->sensorsByAbsCode.end()) { - return Errorf("Sensor map not found."); - } - const SensorInfo& info = it->second; - return std::make_pair(info.sensorType, info.sensorDataIndex); - } - - void setExcludedDevices(const std::vector<std::string>& devices) override { - mExcludedDevices = devices; - } - - std::vector<RawEvent> getEvents(int) override { - std::scoped_lock lock(mLock); - - std::vector<RawEvent> buffer; - std::swap(buffer, mEvents); - - mEventsCondition.notify_all(); - return buffer; - } - - std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override { - auto it = mVideoFrames.find(deviceId); - if (it != mVideoFrames.end()) { - std::vector<TouchVideoFrame> frames = std::move(it->second); - mVideoFrames.erase(deviceId); - return frames; - } - return {}; - } - - int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->scanCodeStates.indexOfKey(scanCode); - if (index >= 0) { - return device->scanCodeStates.valueAt(index); - } - } - return AKEY_STATE_UNKNOWN; - } - - InputDeviceCountryCode getCountryCode(int32_t deviceId) const override { - Device* device = getDevice(deviceId); - if (device) { - return device->countryCode; - } - return InputDeviceCountryCode::INVALID; - } - - int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->keyCodeStates.indexOfKey(keyCode); - if (index >= 0) { - return device->keyCodeStates.valueAt(index); - } - } - return AKEY_STATE_UNKNOWN; - } - - int32_t getSwitchState(int32_t deviceId, int32_t sw) const override { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->switchStates.indexOfKey(sw); - if (index >= 0) { - return device->switchStates.valueAt(index); - } - } - return AKEY_STATE_UNKNOWN; - } - - status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, - int32_t* outValue) const override { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->absoluteAxisValue.indexOfKey(axis); - if (index >= 0) { - *outValue = device->absoluteAxisValue.valueAt(index); - return OK; - } - } - *outValue = 0; - return -1; - } - - int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const override { - Device* device = getDevice(deviceId); - if (!device) { - return AKEYCODE_UNKNOWN; - } - auto it = device->keyCodeMapping.find(locationKeyCode); - return it != device->keyCodeMapping.end() ? it->second : locationKeyCode; - } - - // Return true if the device has non-empty key layout. - bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes, - uint8_t* outFlags) const override { - bool result = false; - Device* device = getDevice(deviceId); - if (device) { - result = device->keysByScanCode.size() > 0 || device->keysByUsageCode.size() > 0; - for (size_t i = 0; i < keyCodes.size(); i++) { - for (size_t j = 0; j < device->keysByScanCode.size(); j++) { - if (keyCodes[i] == device->keysByScanCode.valueAt(j).keyCode) { - outFlags[i] = 1; - } - } - for (size_t j = 0; j < device->keysByUsageCode.size(); j++) { - if (keyCodes[i] == device->keysByUsageCode.valueAt(j).keyCode) { - outFlags[i] = 1; - } - } - } - } - return result; - } - - bool hasScanCode(int32_t deviceId, int32_t scanCode) const override { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->keysByScanCode.indexOfKey(scanCode); - return index >= 0; - } - return false; - } - - bool hasKeyCode(int32_t deviceId, int32_t keyCode) const override { - Device* device = getDevice(deviceId); - if (!device) { - return false; - } - for (size_t i = 0; i < device->keysByScanCode.size(); i++) { - if (keyCode == device->keysByScanCode.valueAt(i).keyCode) { - return true; - } - } - for (size_t j = 0; j < device->keysByUsageCode.size(); j++) { - if (keyCode == device->keysByUsageCode.valueAt(j).keyCode) { - return true; - } - } - return false; - } - - bool hasLed(int32_t deviceId, int32_t led) const override { - Device* device = getDevice(deviceId); - return device && device->leds.indexOfKey(led) >= 0; - } - - void setLedState(int32_t deviceId, int32_t led, bool on) override { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->leds.indexOfKey(led); - if (index >= 0) { - device->leds.replaceValueAt(led, on); - } else { - ADD_FAILURE() - << "Attempted to set the state of an LED that the EventHub declared " - "was not present. led=" << led; - } - } - } - - void getVirtualKeyDefinitions( - int32_t deviceId, std::vector<VirtualKeyDefinition>& outVirtualKeys) const override { - outVirtualKeys.clear(); - - Device* device = getDevice(deviceId); - if (device) { - outVirtualKeys = device->virtualKeys; - } - } - - const std::shared_ptr<KeyCharacterMap> getKeyCharacterMap(int32_t) const override { - return nullptr; - } - - bool setKeyboardLayoutOverlay(int32_t, std::shared_ptr<KeyCharacterMap>) override { - return false; - } - - void vibrate(int32_t, const VibrationElement&) override {} - - void cancelVibrate(int32_t) override {} - - std::vector<int32_t> getVibratorIds(int32_t deviceId) const override { return mVibrators; }; - - std::optional<int32_t> getBatteryCapacity(int32_t, int32_t) const override { - return BATTERY_CAPACITY; - } - - std::optional<int32_t> getBatteryStatus(int32_t, int32_t) const override { - return BATTERY_STATUS; - } - - std::vector<int32_t> getRawBatteryIds(int32_t deviceId) const override { - return {DEFAULT_BATTERY}; - } - - std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId, - int32_t batteryId) const override { - if (batteryId != DEFAULT_BATTERY) return {}; - static const auto BATTERY_INFO = RawBatteryInfo{.id = DEFAULT_BATTERY, - .name = "default battery", - .flags = InputBatteryClass::CAPACITY, - .path = BATTERY_DEVPATH}; - return BATTERY_INFO; - } - - std::vector<int32_t> getRawLightIds(int32_t deviceId) const override { - std::vector<int32_t> ids; - for (const auto& [rawId, info] : mRawLightInfos) { - ids.push_back(rawId); - } - return ids; - } - - std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) const override { - auto it = mRawLightInfos.find(lightId); - if (it == mRawLightInfos.end()) { - return std::nullopt; - } - return it->second; - } - - void setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) override { - mLightBrightness.emplace(lightId, brightness); - } - - void setLightIntensities(int32_t deviceId, int32_t lightId, - std::unordered_map<LightColor, int32_t> intensities) override { - mLightIntensities.emplace(lightId, intensities); - }; - - std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) const override { - auto lightIt = mLightBrightness.find(lightId); - if (lightIt == mLightBrightness.end()) { - return std::nullopt; - } - return lightIt->second; - } - - std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities( - int32_t deviceId, int32_t lightId) const override { - auto lightIt = mLightIntensities.find(lightId); - if (lightIt == mLightIntensities.end()) { - return std::nullopt; - } - return lightIt->second; - }; - - void dump(std::string&) const override {} - - void monitor() const override {} - - void requestReopenDevices() override {} - - void wake() override {} -}; - // --- FakeInputMapper --- class FakeInputMapper : public InputMapper { @@ -1440,9 +481,8 @@ TEST_F(InputReaderPolicyTest, Viewports_GetCleared) { ASSERT_FALSE(internalViewport); // Add an internal viewport, then clear it - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId, NO_PORT, - ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + true /*isActive*/, uniqueId, NO_PORT, ViewportType::INTERNAL); // Check matching by uniqueId internalViewport = mFakePolicy->getDisplayViewportByUniqueId(uniqueId); @@ -1471,21 +511,21 @@ TEST_F(InputReaderPolicyTest, Viewports_GetByType) { constexpr int32_t virtualDisplayId2 = 3; // Add an internal viewport - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, internalUniqueId, - NO_PORT, ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + true /*isActive*/, internalUniqueId, NO_PORT, + ViewportType::INTERNAL); // Add an external viewport - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, externalUniqueId, - NO_PORT, ViewportType::EXTERNAL); + mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + true /*isActive*/, externalUniqueId, NO_PORT, + ViewportType::EXTERNAL); // Add an virtual viewport mFakePolicy->addDisplayViewport(virtualDisplayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, virtualUniqueId1, - NO_PORT, ViewportType::VIRTUAL); + ui::ROTATION_0, true /*isActive*/, virtualUniqueId1, NO_PORT, + ViewportType::VIRTUAL); // Add another virtual viewport mFakePolicy->addDisplayViewport(virtualDisplayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, virtualUniqueId2, - NO_PORT, ViewportType::VIRTUAL); + ui::ROTATION_0, true /*isActive*/, virtualUniqueId2, NO_PORT, + ViewportType::VIRTUAL); // Check matching by type for internal std::optional<DisplayViewport> internalViewport = @@ -1533,13 +573,11 @@ TEST_F(InputReaderPolicyTest, Viewports_TwoOfSameType) { for (const ViewportType& type : types) { mFakePolicy->clearViewports(); // Add a viewport - mFakePolicy->addDisplayViewport(displayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId1, - NO_PORT, type); + mFakePolicy->addDisplayViewport(displayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + true /*isActive*/, uniqueId1, NO_PORT, type); // Add another viewport - mFakePolicy->addDisplayViewport(displayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId2, - NO_PORT, type); + mFakePolicy->addDisplayViewport(displayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + true /*isActive*/, uniqueId2, NO_PORT, type); // Check that correct display viewport was returned by comparing the display IDs. std::optional<DisplayViewport> viewport1 = @@ -1579,10 +617,10 @@ TEST_F(InputReaderPolicyTest, Viewports_ByTypeReturnsDefaultForInternal) { // Add the default display first and ensure it gets returned. mFakePolicy->clearViewports(); mFakePolicy->addDisplayViewport(ADISPLAY_ID_DEFAULT, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId1, NO_PORT, + ui::ROTATION_0, true /*isActive*/, uniqueId1, NO_PORT, ViewportType::INTERNAL); mFakePolicy->addDisplayViewport(nonDefaultDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId2, NO_PORT, + ui::ROTATION_0, true /*isActive*/, uniqueId2, NO_PORT, ViewportType::INTERNAL); std::optional<DisplayViewport> viewport = @@ -1594,10 +632,10 @@ TEST_F(InputReaderPolicyTest, Viewports_ByTypeReturnsDefaultForInternal) { // Add the default display second to make sure order doesn't matter. mFakePolicy->clearViewports(); mFakePolicy->addDisplayViewport(nonDefaultDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId2, NO_PORT, + ui::ROTATION_0, true /*isActive*/, uniqueId2, NO_PORT, ViewportType::INTERNAL); mFakePolicy->addDisplayViewport(ADISPLAY_ID_DEFAULT, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId1, NO_PORT, + ui::ROTATION_0, true /*isActive*/, uniqueId1, NO_PORT, ViewportType::INTERNAL); viewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL); @@ -1621,13 +659,11 @@ TEST_F(InputReaderPolicyTest, Viewports_GetByPort) { mFakePolicy->clearViewports(); // Add a viewport that's associated with some display port that's not of interest. - mFakePolicy->addDisplayViewport(displayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId1, hdmi3, - type); + mFakePolicy->addDisplayViewport(displayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + true /*isActive*/, uniqueId1, hdmi3, type); // Add another viewport, connected to HDMI1 port - mFakePolicy->addDisplayViewport(displayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId2, hdmi1, - type); + mFakePolicy->addDisplayViewport(displayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + true /*isActive*/, uniqueId2, hdmi1, type); // Check that correct display viewport was returned by comparing the display ports. std::optional<DisplayViewport> hdmi1Viewport = mFakePolicy->getDisplayViewportByPort(hdmi1); @@ -2080,11 +1116,10 @@ TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { // Add default and second display. mFakePolicy->clearViewports(); - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, "local:0", NO_PORT, - ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + true /*isActive*/, "local:0", NO_PORT, ViewportType::INTERNAL); mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, "local:1", hdmi1, + ui::ROTATION_0, true /*isActive*/, "local:1", hdmi1, ViewportType::EXTERNAL); mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO); mReader->loopOnce(); @@ -2283,8 +1318,9 @@ TEST_F(InputReaderTest, BatteryGetCapacity) { ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr)); - ASSERT_EQ(controller.getBatteryCapacity(DEFAULT_BATTERY), BATTERY_CAPACITY); - ASSERT_EQ(mReader->getBatteryCapacity(deviceId), BATTERY_CAPACITY); + ASSERT_EQ(controller.getBatteryCapacity(FakeEventHub::DEFAULT_BATTERY), + FakeEventHub::BATTERY_CAPACITY); + ASSERT_EQ(mReader->getBatteryCapacity(deviceId), FakeEventHub::BATTERY_CAPACITY); } TEST_F(InputReaderTest, BatteryGetStatus) { @@ -2300,8 +1336,9 @@ TEST_F(InputReaderTest, BatteryGetStatus) { ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr)); - ASSERT_EQ(controller.getBatteryStatus(DEFAULT_BATTERY), BATTERY_STATUS); - ASSERT_EQ(mReader->getBatteryStatus(deviceId), BATTERY_STATUS); + ASSERT_EQ(controller.getBatteryStatus(FakeEventHub::DEFAULT_BATTERY), + FakeEventHub::BATTERY_STATUS); + ASSERT_EQ(mReader->getBatteryStatus(deviceId), FakeEventHub::BATTERY_STATUS); } TEST_F(InputReaderTest, BatteryGetDevicePath) { @@ -2316,7 +1353,7 @@ TEST_F(InputReaderTest, BatteryGetDevicePath) { ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr)); - ASSERT_EQ(mReader->getBatteryDevicePath(deviceId), BATTERY_DEVPATH); + ASSERT_EQ(mReader->getBatteryDevicePath(deviceId), FakeEventHub::BATTERY_DEVPATH); } TEST_F(InputReaderTest, LightGetColor) { @@ -2541,9 +1578,8 @@ protected: #endif InputReaderIntegrationTest::SetUp(); // At least add an internal display. - setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, UNIQUE_ID, NO_PORT, - ViewportType::INTERNAL); + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); mDevice = createUinputDevice<UinputTouchScreen>(Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT)); ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); @@ -2554,7 +1590,7 @@ protected: } void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height, - int32_t orientation, const std::string& uniqueId, + ui::Rotation orientation, const std::string& uniqueId, std::optional<uint8_t> physicalPort, ViewportType viewportType) { mFakePolicy->addDisplayViewport(displayId, width, height, orientation, true /*isActive*/, @@ -3492,7 +2528,7 @@ TEST_F(InputDeviceTest, Configure_AssignsDisplayPort) { // Prepare displays. mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, UNIQUE_ID, hdmi, + ui::ROTATION_0, true /*isActive*/, UNIQUE_ID, hdmi, ViewportType::INTERNAL); unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), InputReaderConfiguration::CHANGE_DISPLAY_INFO); @@ -3527,7 +2563,7 @@ TEST_F(InputDeviceTest, Configure_AssignsDisplayUniqueId) { // Device should be enabled when a display is found. mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID, + ui::ROTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), InputReaderConfiguration::CHANGE_DISPLAY_INFO); @@ -3553,7 +2589,7 @@ TEST_F(InputDeviceTest, Configure_UniqueId_CorrectlyMatches) { mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID); mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID, + ui::ROTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), InputReaderConfiguration::CHANGE_DISPLAY_INFO); @@ -3672,8 +2708,9 @@ protected: } void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height, - int32_t orientation, const std::string& uniqueId, - std::optional<uint8_t> physicalPort, ViewportType viewportType) { + ui::Rotation orientation, const std::string& uniqueId, + std::optional<uint8_t> physicalPort, + ViewportType viewportType) { mFakePolicy->addDisplayViewport(displayId, width, height, orientation, true /*isActive*/, uniqueId, physicalPort, viewportType); configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO); @@ -3703,7 +2740,7 @@ protected: void resetMapper(InputMapper& mapper, nsecs_t when) { const auto resetArgs = mapper.reset(when); - for (const auto args : resetArgs) { + for (const auto& args : resetArgs) { mFakeListener->notify(args); } // Loop the reader to flush the input listener queue. @@ -4028,7 +3065,7 @@ class KeyboardInputMapperTest : public InputMapperTest { protected: const std::string UNIQUE_ID = "local:0"; - void prepareDisplay(int32_t orientation); + void prepareDisplay(ui::Rotation orientation); void testDPadKeyRotation(KeyboardInputMapper& mapper, int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode, @@ -4038,7 +3075,7 @@ protected: /* Similar to setDisplayInfoAndReconfigure, but pre-populates all parameters except for the * orientation. */ -void KeyboardInputMapperTest::prepareDisplay(int32_t orientation) { +void KeyboardInputMapperTest::prepareDisplay(ui::Rotation orientation) { setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); } @@ -4250,7 +3287,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateD addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - prepareDisplay(DISPLAY_ORIENTATION_90); + prepareDisplay(ui::ROTATION_90); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, @@ -4272,7 +3309,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); ASSERT_NO_FATAL_FAILURE( testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP, DISPLAY_ID)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, @@ -4283,7 +3320,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { AKEYCODE_DPAD_LEFT, DISPLAY_ID)); clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_90); + prepareDisplay(ui::ROTATION_90); ASSERT_NO_FATAL_FAILURE( testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, DISPLAY_ID)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, @@ -4294,7 +3331,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { AKEYCODE_DPAD_DOWN, DISPLAY_ID)); clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_180); + prepareDisplay(ui::ROTATION_180); ASSERT_NO_FATAL_FAILURE( testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN, DISPLAY_ID)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, @@ -4305,7 +3342,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { AKEYCODE_DPAD_RIGHT, DISPLAY_ID)); clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_270); + prepareDisplay(ui::ROTATION_270); ASSERT_NO_FATAL_FAILURE( testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT, DISPLAY_ID)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, @@ -4319,7 +3356,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { // in the key up as we did in the key down. NotifyKeyArgs args; clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_270); + prepareDisplay(ui::ROTATION_270); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 1); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); @@ -4327,7 +3364,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode); clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_180); + prepareDisplay(ui::ROTATION_180); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); @@ -4352,7 +3389,7 @@ TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_NotOrientationAware ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(ADISPLAY_ID_NONE, args.displayId); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 1); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 0); @@ -4374,7 +3411,7 @@ TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_OrientationAware) { // Display id should be ADISPLAY_ID_NONE without any display configuration. // ^--- already checked by the previous test - setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0, + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 1); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); @@ -4384,7 +3421,7 @@ TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_OrientationAware) { constexpr int32_t newDisplayId = 2; clearViewports(); - setDisplayInfoAndReconfigure(newDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0, + setDisplayInfoAndReconfigure(newDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_UP, 1); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); @@ -4594,9 +3631,9 @@ TEST_F(KeyboardInputMapperTest, Configure_AssignsDisplayPort) { // Prepare second display. constexpr int32_t newDisplayId = 2; - setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0, + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, UNIQUE_ID, hdmi1, ViewportType::INTERNAL); - setDisplayInfoAndReconfigure(newDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0, + setDisplayInfoAndReconfigure(newDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, SECONDARY_UNIQUE_ID, hdmi2, ViewportType::EXTERNAL); // Default device will reconfigure above, need additional reconfiguration for another device. unused += device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), @@ -4927,14 +3964,14 @@ protected: void testMotionRotation(CursorInputMapper& mapper, int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY); - void prepareDisplay(int32_t orientation) { + void prepareDisplay(ui::Rotation orientation) { setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation, DISPLAY_UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); } void prepareSecondaryDisplay() { setDisplayInfoAndReconfigure(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, SECONDARY_DISPLAY_UNIQUE_ID, NO_PORT, + ui::ROTATION_0, SECONDARY_DISPLAY_UNIQUE_ID, NO_PORT, ViewportType::EXTERNAL); } @@ -5219,7 +4256,7 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldNotRotateMotion addConfigurationProperty("cursor.orientationAware", "1"); CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>(); - prepareDisplay(DISPLAY_ORIENTATION_90); + prepareDisplay(ui::ROTATION_90); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0)); @@ -5238,7 +4275,7 @@ TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotion CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>(); clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0)); @@ -5249,7 +4286,7 @@ TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotion ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_90); + prepareDisplay(ui::ROTATION_90); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, 1)); @@ -5260,7 +4297,7 @@ TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotion ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, -1)); clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_180); + prepareDisplay(ui::ROTATION_180); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, -1, 0)); @@ -5271,7 +4308,7 @@ TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotion ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, -1)); clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_270); + prepareDisplay(ui::ROTATION_270); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, -1)); @@ -5735,7 +4772,7 @@ TEST_F(CursorInputMapperTest, PointerCaptureDisablesOrientationChanges) { ASSERT_EQ(DEVICE_ID, resetArgs.deviceId); // Ensure the display is rotated. - prepareDisplay(DISPLAY_ORIENTATION_90); + prepareDisplay(ui::ROTATION_90); NotifyMotionArgs args; @@ -5771,7 +4808,7 @@ TEST_F(CursorInputMapperTest, ConfigureDisplayId_NoAssociatedViewport) { CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>(); // Set up the default display. - prepareDisplay(DISPLAY_ORIENTATION_90); + prepareDisplay(ui::ROTATION_90); // Set up the secondary display as the display on which the pointer should be shown. // The InputDevice is not associated with any display. @@ -5798,7 +4835,7 @@ TEST_F(CursorInputMapperTest, ConfigureDisplayId_WithAssociatedViewport) { CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>(); // Set up the default display. - prepareDisplay(DISPLAY_ORIENTATION_90); + prepareDisplay(ui::ROTATION_90); // Set up the secondary display as the display on which the pointer should be shown, // and associate the InputDevice with the secondary display. @@ -5825,7 +4862,7 @@ TEST_F(CursorInputMapperTest, ConfigureDisplayId_IgnoresEventsForMismatchedPoint CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>(); // Set up the default display as the display on which the pointer should be shown. - prepareDisplay(DISPLAY_ORIENTATION_90); + prepareDisplay(ui::ROTATION_90); mFakePolicy->setDefaultPointerDisplayId(DISPLAY_ID); // Associate the InputDevice with the secondary display. @@ -5992,9 +5029,9 @@ protected: TOOL_TYPE = 1 << 10, }; - void prepareDisplay(int32_t orientation, std::optional<uint8_t> port = NO_PORT); + void prepareDisplay(ui::Rotation orientation, std::optional<uint8_t> port = NO_PORT); void prepareSecondaryDisplay(ViewportType type, std::optional<uint8_t> port = NO_PORT); - void prepareVirtualDisplay(int32_t orientation); + void prepareVirtualDisplay(ui::Rotation orientation); void prepareVirtualKeys(); void prepareLocationCalibration(); int32_t toRawX(float displayX); @@ -6048,17 +5085,17 @@ const VirtualKeyDefinition TouchInputMapperTest::VIRTUAL_KEYS[2] = { { KEY_MENU, DISPLAY_HEIGHT - 60, DISPLAY_WIDTH + 15, 20, 20 }, }; -void TouchInputMapperTest::prepareDisplay(int32_t orientation, std::optional<uint8_t> port) { +void TouchInputMapperTest::prepareDisplay(ui::Rotation orientation, std::optional<uint8_t> port) { setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation, UNIQUE_ID, port, ViewportType::INTERNAL); } void TouchInputMapperTest::prepareSecondaryDisplay(ViewportType type, std::optional<uint8_t> port) { setDisplayInfoAndReconfigure(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, SECONDARY_UNIQUE_ID, port, type); + ui::ROTATION_0, SECONDARY_UNIQUE_ID, port, type); } -void TouchInputMapperTest::prepareVirtualDisplay(int32_t orientation) { +void TouchInputMapperTest::prepareVirtualDisplay(ui::Rotation orientation) { setDisplayInfoAndReconfigure(VIRTUAL_DISPLAY_ID, VIRTUAL_DISPLAY_WIDTH, VIRTUAL_DISPLAY_HEIGHT, orientation, VIRTUAL_DISPLAY_UNIQUE_ID, NO_PORT, ViewportType::VIRTUAL); @@ -6225,7 +5262,7 @@ TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_Return TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); @@ -6253,7 +5290,7 @@ TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) { TEST_F(SingleTouchInputMapperTest, GetScanCodeState) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); @@ -6281,7 +5318,7 @@ TEST_F(SingleTouchInputMapperTest, GetScanCodeState) { TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); @@ -6296,7 +5333,7 @@ TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) { TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); @@ -6346,7 +5383,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNor TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfBounds_SendsKeyDownAndKeyCancel) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); @@ -6467,7 +5504,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfB TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMovesIn_SendsDownAsTouchEntersDisplay) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); @@ -6542,7 +5579,7 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture_VirtualDispl addConfigurationProperty("touch.deviceType", "touchScreen"); addConfigurationProperty("touch.displayId", VIRTUAL_DISPLAY_UNIQUE_ID); - prepareVirtualDisplay(DISPLAY_ORIENTATION_0); + prepareVirtualDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); @@ -6638,7 +5675,7 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture_VirtualDispl TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); @@ -6737,7 +5774,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_DoesNotRotateMot NotifyMotionArgs args; // Rotation 90. - prepareDisplay(DISPLAY_ORIENTATION_90); + prepareDisplay(ui::ROTATION_90); processDown(mapper, toRawX(50), toRawY(75)); processSync(mapper); @@ -6763,7 +5800,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_RotatesMotion // Rotation 0. clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); processDown(mapper, toRawX(50), toRawY(75)); processSync(mapper); @@ -6777,7 +5814,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_RotatesMotion // Rotation 90. clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_90); + prepareDisplay(ui::ROTATION_90); processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN); processSync(mapper); @@ -6791,7 +5828,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_RotatesMotion // Rotation 180. clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_180); + prepareDisplay(ui::ROTATION_180); processDown(mapper, RAW_X_MAX - toRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRawY(75) + RAW_Y_MIN); processSync(mapper); @@ -6805,7 +5842,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_RotatesMotion // Rotation 270. clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_270); + prepareDisplay(ui::ROTATION_270); processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50)); processSync(mapper); @@ -6825,7 +5862,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation0_RotatesMotions) { addConfigurationProperty("touch.orientationAware", "1"); addConfigurationProperty("touch.orientation", "ORIENTATION_0"); clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); NotifyMotionArgs args; @@ -6849,7 +5886,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation90_RotatesMotions) { addConfigurationProperty("touch.orientationAware", "1"); addConfigurationProperty("touch.orientation", "ORIENTATION_90"); clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); NotifyMotionArgs args; @@ -6873,7 +5910,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation180_RotatesMotions) { addConfigurationProperty("touch.orientationAware", "1"); addConfigurationProperty("touch.orientation", "ORIENTATION_180"); clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); NotifyMotionArgs args; @@ -6897,7 +5934,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation270_RotatesMotions) { addConfigurationProperty("touch.orientationAware", "1"); addConfigurationProperty("touch.orientation", "ORIENTATION_270"); clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); NotifyMotionArgs args; @@ -6928,7 +5965,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationSpecified_RotatesMotio // Orientation 90, Rotation 0. clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); processDown(mapper, RAW_X_MAX - toRotatedRawX(75) + RAW_X_MIN, toRotatedRawY(50)); processSync(mapper); @@ -6942,7 +5979,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationSpecified_RotatesMotio // Orientation 90, Rotation 90. clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_90); + prepareDisplay(ui::ROTATION_90); processDown(mapper, toRotatedRawX(50), toRotatedRawY(75)); processSync(mapper); @@ -6956,7 +5993,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationSpecified_RotatesMotio // Orientation 90, Rotation 180. clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_180); + prepareDisplay(ui::ROTATION_180); processDown(mapper, toRotatedRawX(75), RAW_Y_MAX - toRotatedRawY(50) + RAW_Y_MIN); processSync(mapper); @@ -6970,7 +6007,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationSpecified_RotatesMotio // Orientation 90, Rotation 270. clearViewports(); - prepareDisplay(DISPLAY_ORIENTATION_270); + prepareDisplay(ui::ROTATION_270); processDown(mapper, RAW_X_MAX - toRotatedRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRotatedRawY(75) + RAW_Y_MIN); processSync(mapper); @@ -6986,7 +6023,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationSpecified_RotatesMotio TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION | PRESSURE | TOOL | DISTANCE | TILT); SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); @@ -7030,7 +6067,7 @@ TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) { TEST_F(SingleTouchInputMapperTest, Process_XYAxes_AffineCalibration) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareLocationCalibration(); prepareButtons(); prepareAxes(POSITION); @@ -7053,7 +6090,7 @@ TEST_F(SingleTouchInputMapperTest, Process_XYAxes_AffineCalibration) { TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllButtons) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); @@ -7296,7 +6333,7 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllButtons) { TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); @@ -7431,7 +6468,7 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { TEST_F(SingleTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOOL_FINGER, 0, AKEYCODE_UNKNOWN, 0); @@ -7503,7 +6540,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueI TEST_F(SingleTouchInputMapperTest, Process_WhenAbsPressureIsPresent_HoversIfItsValueIsZero) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION | PRESSURE); SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); @@ -7574,7 +6611,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenAbsPressureIsPresent_HoversIfItsV TEST_F(SingleTouchInputMapperTest, Reset_CancelsOngoingGesture) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION | PRESSURE); SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); @@ -7596,7 +6633,7 @@ TEST_F(SingleTouchInputMapperTest, Reset_CancelsOngoingGesture) { TEST_F(SingleTouchInputMapperTest, Reset_RecreatesTouchState) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION | PRESSURE); SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); @@ -7624,7 +6661,7 @@ TEST_F(SingleTouchInputMapperTest, Reset_RecreatesTouchState) { TEST_F(SingleTouchInputMapperTest, Process_WhenViewportDisplayIdChanged_TouchIsCanceledAndDeviceIsReset) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); @@ -7652,7 +6689,7 @@ TEST_F(SingleTouchInputMapperTest, TEST_F(SingleTouchInputMapperTest, Process_WhenViewportActiveStatusChanged_TouchIsCanceledAndDeviceIsReset) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); @@ -7712,7 +6749,7 @@ TEST_F(SingleTouchInputMapperTest, TEST_F(SingleTouchInputMapperTest, ButtonIsReleasedOnTouchUp) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); @@ -7755,27 +6792,25 @@ public: // The values inside DisplayViewport are expected to be pre-rotated. This updates the current // DisplayViewport to pre-rotate the values. The viewport's physical display will be set to the // rotated equivalent of the given un-rotated physical display bounds. - void configurePhysicalDisplay(int32_t orientation, Rect naturalPhysicalDisplay) { + void configurePhysicalDisplay(ui::Rotation orientation, Rect naturalPhysicalDisplay) { uint32_t inverseRotationFlags; auto width = DISPLAY_WIDTH; auto height = DISPLAY_HEIGHT; switch (orientation) { - case DISPLAY_ORIENTATION_90: + case ui::ROTATION_90: inverseRotationFlags = ui::Transform::ROT_270; std::swap(width, height); break; - case DISPLAY_ORIENTATION_180: + case ui::ROTATION_180: inverseRotationFlags = ui::Transform::ROT_180; break; - case DISPLAY_ORIENTATION_270: + case ui::ROTATION_270: inverseRotationFlags = ui::Transform::ROT_90; std::swap(width, height); break; - case DISPLAY_ORIENTATION_0: + case ui::ROTATION_0: inverseRotationFlags = ui::Transform::ROT_0; break; - default: - FAIL() << "Invalid orientation: " << orientation; } const ui::Transform rotation(inverseRotationFlags, width, height); @@ -7819,7 +6854,7 @@ public: TEST_F(TouchDisplayProjectionTest, IgnoresTouchesOutsidePhysicalDisplay) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); @@ -7834,8 +6869,7 @@ TEST_F(TouchDisplayProjectionTest, IgnoresTouchesOutsidePhysicalDisplay) { static const std::array<Point, 6> kPointsOutsidePhysicalDisplay{ {{-10, -10}, {0, 0}, {5, 100}, {50, 15}, {75, 100}, {50, 165}}}; - for (auto orientation : {DISPLAY_ORIENTATION_0, DISPLAY_ORIENTATION_90, DISPLAY_ORIENTATION_180, - DISPLAY_ORIENTATION_270}) { + for (auto orientation : {ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180, ui::ROTATION_270}) { configurePhysicalDisplay(orientation, kPhysicalDisplay); // Touches outside the physical display should be ignored, and should not generate any @@ -7855,7 +6889,7 @@ TEST_F(TouchDisplayProjectionTest, IgnoresTouchesOutsidePhysicalDisplay) { TEST_F(TouchDisplayProjectionTest, EmitsTouchDownAfterEnteringPhysicalDisplay) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); @@ -7868,8 +6902,7 @@ TEST_F(TouchDisplayProjectionTest, EmitsTouchDownAfterEnteringPhysicalDisplay) { // points (10, 20) and (70, 160) inside the display space, which is of the size 400 x 800. static const Rect kPhysicalDisplay{10, 20, 70, 160}; - for (auto orientation : {DISPLAY_ORIENTATION_0, DISPLAY_ORIENTATION_90, DISPLAY_ORIENTATION_180, - DISPLAY_ORIENTATION_270}) { + for (auto orientation : {ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180, ui::ROTATION_270}) { configurePhysicalDisplay(orientation, kPhysicalDisplay); // Touches that start outside the physical display should be ignored until it enters the @@ -7920,7 +6953,7 @@ class ExternalStylusFusionTest : public SingleTouchInputMapperTest { public: SingleTouchInputMapper& initializeInputMapperWithExternalStylus() { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); @@ -8409,7 +7442,7 @@ void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper& mapper, nsecs TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackingIds) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION); prepareVirtualKeys(); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -8681,7 +7714,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin TEST_F(MultiTouchInputMapperTest, AxisResolution_IsPopulated) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, /*flat*/ 0, /*fuzz*/ 0, /*resolution*/ 10); @@ -8711,7 +7744,7 @@ TEST_F(MultiTouchInputMapperTest, AxisResolution_IsPopulated) { TEST_F(MultiTouchInputMapperTest, TouchMajorAndMinorAxes_DoNotAppearIfNotSupported) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, /*flat*/ 0, /*fuzz*/ 0, /*resolution*/ 10); @@ -8732,7 +7765,7 @@ TEST_F(MultiTouchInputMapperTest, TouchMajorAndMinorAxes_DoNotAppearIfNotSupport TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID); prepareVirtualKeys(); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -8903,7 +7936,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT); prepareVirtualKeys(); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -9069,7 +8102,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | TOUCH | TOOL | PRESSURE | ORIENTATION | ID | MINOR | DISTANCE); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -9118,7 +8151,7 @@ TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) { TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | TOUCH | TOOL | MINOR); addConfigurationProperty("touch.size.calibration", "geometric"); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -9155,7 +8188,7 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_SummedLinearCalibration) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | TOUCH | TOOL); addConfigurationProperty("touch.size.calibration", "diameter"); addConfigurationProperty("touch.size.scale", "10"); @@ -9206,7 +8239,7 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_SummedLinearCalibrati TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_AreaCalibration) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | TOUCH | TOOL); addConfigurationProperty("touch.size.calibration", "area"); addConfigurationProperty("touch.size.scale", "43"); @@ -9239,7 +8272,7 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_AreaCalibration) { TEST_F(MultiTouchInputMapperTest, Process_PressureAxis_AmplitudeCalibration) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | PRESSURE); addConfigurationProperty("touch.pressure.calibration", "amplitude"); addConfigurationProperty("touch.pressure.scale", "0.01"); @@ -9273,7 +8306,7 @@ TEST_F(MultiTouchInputMapperTest, Process_PressureAxis_AmplitudeCalibration) { TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllButtons) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -9516,7 +8549,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllButtons) { TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleMappedStylusButtons) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -9573,7 +8606,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleMappedStylusButtons) { TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -9723,7 +8756,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { TEST_F(MultiTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT); mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -9794,7 +8827,7 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIs TEST_F(MultiTouchInputMapperTest, Process_WhenAbsMTPressureIsPresent_HoversIfItsValueIsZero) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -9894,7 +8927,7 @@ TEST_F(MultiTouchInputMapperTest, Configure_AssignsDisplayPort) { ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); // Add viewport for display 1 on hdmi1 - prepareDisplay(DISPLAY_ORIENTATION_0, hdmi1); + prepareDisplay(ui::ROTATION_0, hdmi1); // Send a touch event again processPosition(mapper, 100, 100); processSync(mapper); @@ -9911,8 +8944,8 @@ TEST_F(MultiTouchInputMapperTest, Configure_AssignsDisplayUniqueId) { mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, VIRTUAL_DISPLAY_UNIQUE_ID); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareVirtualDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); + prepareVirtualDisplay(ui::ROTATION_0); // Send a touch event processPosition(mapper, 100, 100); @@ -9935,7 +8968,7 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) { mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID); prepareSecondaryDisplay(ViewportType::EXTERNAL); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -9959,7 +8992,7 @@ TEST_F(MultiTouchInputMapperTest, Process_SendsReadTime) { prepareAxes(POSITION); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); process(mapper, 10, 11 /*readTime*/, EV_ABS, ABS_MT_TRACKING_ID, 1); process(mapper, 15, 16 /*readTime*/, EV_ABS, ABS_MT_POSITION_X, 100); process(mapper, 20, 21 /*readTime*/, EV_ABS, ABS_MT_POSITION_Y, 100); @@ -9984,9 +9017,8 @@ TEST_F(MultiTouchInputMapperTest, Process_SendsReadTime) { TEST_F(MultiTouchInputMapperTest, WhenViewportIsNotActive_TouchesAreDropped) { addConfigurationProperty("touch.deviceType", "touchScreen"); // Don't set touch.enableForInactiveViewport to verify the default behavior. - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, false /*isActive*/, UNIQUE_ID, NO_PORT, - ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + false /*isActive*/, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO); prepareAxes(POSITION); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -10005,9 +9037,8 @@ TEST_F(MultiTouchInputMapperTest, WhenViewportIsNotActive_TouchesAreDropped) { TEST_F(MultiTouchInputMapperTest, WhenViewportIsNotActive_TouchesAreProcessed) { addConfigurationProperty("touch.deviceType", "touchScreen"); addConfigurationProperty("touch.enableForInactiveViewport", "1"); - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, false /*isActive*/, UNIQUE_ID, NO_PORT, - ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + false /*isActive*/, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO); prepareAxes(POSITION); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -10023,9 +9054,8 @@ TEST_F(MultiTouchInputMapperTest, WhenViewportIsNotActive_TouchesAreProcessed) { TEST_F(MultiTouchInputMapperTest, Process_DeactivateViewport_AbortTouches) { addConfigurationProperty("touch.deviceType", "touchScreen"); addConfigurationProperty("touch.enableForInactiveViewport", "0"); - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0, true /*isActive*/, UNIQUE_ID, NO_PORT, - ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + true /*isActive*/, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); std::optional<DisplayViewport> optionalDisplayViewport = mFakePolicy->getDisplayViewportByUniqueId(UNIQUE_ID); ASSERT_TRUE(optionalDisplayViewport.has_value()); @@ -10119,7 +9149,7 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) { mFakePolicy->setShowTouches(true); // Create displays. - prepareDisplay(DISPLAY_ORIENTATION_0, hdmi1); + prepareDisplay(ui::ROTATION_0, hdmi1); prepareSecondaryDisplay(ViewportType::EXTERNAL, hdmi2); // Default device will reconfigure above, need additional reconfiguration for another device. @@ -10164,7 +9194,7 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) { TEST_F(MultiTouchInputMapperTest, VideoFrames_ReceivedByListener) { prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); NotifyMotionArgs motionArgs; @@ -10195,8 +9225,7 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_AreNotRotated) { NotifyMotionArgs motionArgs; // Test all 4 orientations - for (int32_t orientation : {DISPLAY_ORIENTATION_0, DISPLAY_ORIENTATION_90, - DISPLAY_ORIENTATION_180, DISPLAY_ORIENTATION_270}) { + for (ui::Rotation orientation : ftl::enum_range<ui::Rotation>()) { SCOPED_TRACE("Orientation " + StringPrintf("%i", orientation)); clearViewports(); prepareDisplay(orientation); @@ -10221,8 +9250,7 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_WhenNotOrientationAware_AreRotated NotifyMotionArgs motionArgs; // Test all 4 orientations - for (int32_t orientation : {DISPLAY_ORIENTATION_0, DISPLAY_ORIENTATION_90, - DISPLAY_ORIENTATION_180, DISPLAY_ORIENTATION_270}) { + for (ui::Rotation orientation : ftl::enum_range<ui::Rotation>()) { SCOPED_TRACE("Orientation " + StringPrintf("%i", orientation)); clearViewports(); prepareDisplay(orientation); @@ -10256,7 +9284,7 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreNotRotated) { std::vector<TouchVideoFrame> frames{frame1, frame2, frame3}; NotifyMotionArgs motionArgs; - prepareDisplay(DISPLAY_ORIENTATION_90); + prepareDisplay(ui::ROTATION_90); mFakeEventHub->setVideoFrames({{EVENTHUB_ID, frames}}); processPosition(mapper, 100, 200); processSync(mapper); @@ -10279,7 +9307,7 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_WhenNotOrientationAware_MultipleFr std::vector<TouchVideoFrame> frames{frame1, frame2, frame3}; NotifyMotionArgs motionArgs; - prepareDisplay(DISPLAY_ORIENTATION_90); + prepareDisplay(ui::ROTATION_90); mFakeEventHub->setVideoFrames({{EVENTHUB_ID, frames}}); processPosition(mapper, 100, 200); processSync(mapper); @@ -10289,7 +9317,7 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_WhenNotOrientationAware_MultipleFr // compared to the display. This is so that when the window transform (which contains the // display rotation) is applied later by InputDispatcher, the coordinates end up in the // window's coordinate space. - frame.rotate(getInverseRotation(DISPLAY_ORIENTATION_90)); + frame.rotate(getInverseRotation(ui::ROTATION_90)); }); ASSERT_EQ(frames, motionArgs.videoFrames); } @@ -10326,7 +9354,7 @@ TEST_F(MultiTouchInputMapperTest, Configure_EnabledForAssociatedDisplay) { TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleSingleTouch) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -10371,7 +9399,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleSingleTouch) { */ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_SinglePointer) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -10419,7 +9447,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_SinglePointer */ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_TwoPointers) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -10494,7 +9522,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_TwoPointers) */ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_ShouldCancelWhenAllTouchIsPalm) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -10592,7 +9620,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_ShouldCancelW */ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_KeepFirstPointer) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -10664,7 +9692,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_KeepFirstPoin */ TEST_F(MultiTouchInputMapperTest, Process_MultiTouch_WithInvalidTrackingId) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -10721,7 +9749,7 @@ TEST_F(MultiTouchInputMapperTest, Process_MultiTouch_WithInvalidTrackingId) { TEST_F(MultiTouchInputMapperTest, Reset_PreservesLastTouchState) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -10762,7 +9790,7 @@ TEST_F(MultiTouchInputMapperTest, Reset_PreservesLastTouchState) { TEST_F(MultiTouchInputMapperTest, Reset_PreservesLastTouchState_NoPointersDown) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -10790,7 +9818,7 @@ TEST_F(MultiTouchInputMapperTest, Reset_PreservesLastTouchState_NoPointersDown) TEST_F(MultiTouchInputMapperTest, StylusSourceIsAddedDynamicallyFromToolType) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE | TOOL_TYPE); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled()); @@ -10849,7 +9877,7 @@ protected: TEST_F(MultiTouchInputMapperTest_ExternalDevice, Viewports_Fallback) { prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper.getSources()); @@ -10880,7 +9908,7 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchpadCapture) { fakePointerController->setButtonState(0); // prepare device and capture - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT); mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0); mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); @@ -11030,7 +10058,7 @@ TEST_F(MultiTouchInputMapperTest, Process_UnCapturedTouchpadPointer) { fakePointerController->setButtonState(0); // prepare device and capture - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT); mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0); mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); @@ -11071,7 +10099,7 @@ TEST_F(MultiTouchInputMapperTest, WhenCapturedAndNotCaptured_GetSources) { std::shared_ptr<FakePointerController> fakePointerController = std::make_shared<FakePointerController>(); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT); mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0); mFakePolicy->setPointerController(fakePointerController); @@ -11098,7 +10126,7 @@ protected: TEST_F(BluetoothMultiTouchInputMapperTest, TimestampSmoothening) { addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); @@ -11148,7 +10176,7 @@ protected: fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1); fakePointerController->setPosition(0, 0); fakePointerController->setButtonState(0); - prepareDisplay(DISPLAY_ORIENTATION_0); + prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION); prepareAbsoluteAxisResolution(xAxisResolution, yAxisResolution); @@ -11508,7 +10536,7 @@ protected: process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); } - void prepareVirtualDisplay(int32_t orientation) { + void prepareVirtualDisplay(ui::Rotation orientation) { setDisplayInfoAndReconfigure(VIRTUAL_DISPLAY_ID, VIRTUAL_DISPLAY_WIDTH, VIRTUAL_DISPLAY_HEIGHT, orientation, VIRTUAL_DISPLAY_UNIQUE_ID, NO_PORT, ViewportType::VIRTUAL); @@ -11526,7 +10554,7 @@ TEST_F(JoystickInputMapperTest, Configure_AssignsDisplayUniqueId) { mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, VIRTUAL_DISPLAY_UNIQUE_ID); - prepareVirtualDisplay(DISPLAY_ORIENTATION_0); + prepareVirtualDisplay(ui::ROTATION_0); // Send an axis event processAxis(mapper, ABS_X, 100); @@ -11629,15 +10657,17 @@ protected: TEST_F(BatteryControllerTest, GetBatteryCapacity) { PeripheralController& controller = addControllerAndConfigure<PeripheralController>(); - ASSERT_TRUE(controller.getBatteryCapacity(DEFAULT_BATTERY)); - ASSERT_EQ(controller.getBatteryCapacity(DEFAULT_BATTERY).value_or(-1), BATTERY_CAPACITY); + ASSERT_TRUE(controller.getBatteryCapacity(FakeEventHub::DEFAULT_BATTERY)); + ASSERT_EQ(controller.getBatteryCapacity(FakeEventHub::DEFAULT_BATTERY).value_or(-1), + FakeEventHub::BATTERY_CAPACITY); } TEST_F(BatteryControllerTest, GetBatteryStatus) { PeripheralController& controller = addControllerAndConfigure<PeripheralController>(); - ASSERT_TRUE(controller.getBatteryStatus(DEFAULT_BATTERY)); - ASSERT_EQ(controller.getBatteryStatus(DEFAULT_BATTERY).value_or(-1), BATTERY_STATUS); + ASSERT_TRUE(controller.getBatteryStatus(FakeEventHub::DEFAULT_BATTERY)); + ASSERT_EQ(controller.getBatteryStatus(FakeEventHub::DEFAULT_BATTERY).value_or(-1), + FakeEventHub::BATTERY_STATUS); } // --- LightControllerTest --- diff --git a/services/inputflinger/tests/TestConstants.h b/services/inputflinger/tests/TestConstants.h new file mode 100644 index 0000000000..8dc9d71392 --- /dev/null +++ b/services/inputflinger/tests/TestConstants.h @@ -0,0 +1,30 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace android { + +using std::chrono_literals::operator""ms; + +// Timeout for waiting for an expected event +static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms; + +// An arbitrary time value. +static constexpr nsecs_t ARBITRARY_TIME = 1234; +static constexpr nsecs_t READ_TIME = 4321; + +} // namespace android diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index 64316baa3a..445ed182fe 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -311,7 +311,7 @@ public: return mFdp->ConsumeRandomLengthString(32); } TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor, - int32_t surfaceRotation) override { + ui::Rotation surfaceRotation) override { return mTransform; } void setTouchAffineTransformation(const TouchAffineTransformation t) { mTransform = t; } diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp index 46f00e8329..398cdf9a0e 100644 --- a/services/sensorservice/SensorInterface.cpp +++ b/services/sensorservice/SensorInterface.cpp @@ -87,6 +87,42 @@ VirtualSensor::VirtualSensor() : // --------------------------------------------------------------------------- +RuntimeSensor::RuntimeSensor(const sensor_t& sensor, sp<StateChangeCallback> callback) + : BaseSensor(sensor), mCallback(std::move(callback)) { +} + +status_t RuntimeSensor::activate(void*, bool enabled) { + if (enabled != mEnabled) { + mEnabled = enabled; + mCallback->onStateChanged(mEnabled, mSamplingPeriodNs, mBatchReportLatencyNs); + } + return OK; +} + +status_t RuntimeSensor::batch(void*, int, int, int64_t samplingPeriodNs, + int64_t maxBatchReportLatencyNs) { + if (mSamplingPeriodNs != samplingPeriodNs || mBatchReportLatencyNs != maxBatchReportLatencyNs) { + mSamplingPeriodNs = samplingPeriodNs; + mBatchReportLatencyNs = maxBatchReportLatencyNs; + if (mEnabled) { + mCallback->onStateChanged(mEnabled, mSamplingPeriodNs, mBatchReportLatencyNs); + } + } + return OK; +} + +status_t RuntimeSensor::setDelay(void*, int, int64_t ns) { + if (mSamplingPeriodNs != ns) { + mSamplingPeriodNs = ns; + if (mEnabled) { + mCallback->onStateChanged(mEnabled, mSamplingPeriodNs, mBatchReportLatencyNs); + } + } + return OK; +} + +// --------------------------------------------------------------------------- + ProximitySensor::ProximitySensor(const sensor_t& sensor, SensorService& service) : HardwareSensor(sensor), mSensorService(service) { } diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h index 57043592c5..5ee5e1224a 100644 --- a/services/sensorservice/SensorInterface.h +++ b/services/sensorservice/SensorInterface.h @@ -104,6 +104,32 @@ protected: // --------------------------------------------------------------------------- +class RuntimeSensor : public BaseSensor { +public: + static constexpr int DEFAULT_DEVICE_ID = 0; + + class StateChangeCallback : public virtual RefBase { + public: + virtual void onStateChanged(bool enabled, int64_t samplingPeriodNs, + int64_t batchReportLatencyNs) = 0; + }; + RuntimeSensor(const sensor_t& sensor, sp<StateChangeCallback> callback); + virtual status_t activate(void* ident, bool enabled) override; + virtual status_t batch(void* ident, int handle, int flags, int64_t samplingPeriodNs, + int64_t maxBatchReportLatencyNs) override; + virtual status_t setDelay(void* ident, int handle, int64_t ns) override; + virtual bool process(sensors_event_t*, const sensors_event_t&) { return false; } + virtual bool isVirtual() const override { return false; } + +private: + bool mEnabled = false; + int64_t mSamplingPeriodNs = 0; + int64_t mBatchReportLatencyNs = 0; + sp<StateChangeCallback> mCallback; +}; + +// --------------------------------------------------------------------------- + class ProximitySensor : public HardwareSensor { public: explicit ProximitySensor(const sensor_t& sensor, SensorService& service); diff --git a/services/sensorservice/SensorList.cpp b/services/sensorservice/SensorList.cpp index 85ce0f0018..6d36b4789b 100644 --- a/services/sensorservice/SensorList.cpp +++ b/services/sensorservice/SensorList.cpp @@ -29,12 +29,12 @@ namespace SensorServiceUtil { const Sensor SensorList::mNonSensor = Sensor("unknown"); bool SensorList::add( - int handle, SensorInterface* si, bool isForDebug, bool isVirtual) { + int handle, SensorInterface* si, bool isForDebug, bool isVirtual, int deviceId) { std::lock_guard<std::mutex> lk(mLock); if (handle == si->getSensor().getHandle() && mUsedHandle.insert(handle).second) { // will succeed as the mUsedHandle does not have this handle - mHandleMap.emplace(handle, Entry(si, isForDebug, isVirtual)); + mHandleMap.emplace(handle, Entry(si, isForDebug, isVirtual, deviceId)); return true; } // handle exist already or handle mismatch @@ -79,7 +79,8 @@ const Vector<Sensor> SensorList::getUserSensors() const { Vector<Sensor> sensors; forEachEntry( [&sensors] (const Entry& e) -> bool { - if (!e.isForDebug && !e.si->getSensor().isDynamicSensor()) { + if (!e.isForDebug && !e.si->getSensor().isDynamicSensor() + && e.deviceId == RuntimeSensor::DEFAULT_DEVICE_ID) { sensors.add(e.si->getSensor()); } return true; @@ -92,7 +93,8 @@ const Vector<Sensor> SensorList::getUserDebugSensors() const { Vector<Sensor> sensors; forEachEntry( [&sensors] (const Entry& e) -> bool { - if (!e.si->getSensor().isDynamicSensor()) { + if (!e.si->getSensor().isDynamicSensor() + && e.deviceId == RuntimeSensor::DEFAULT_DEVICE_ID) { sensors.add(e.si->getSensor()); } return true; @@ -105,7 +107,8 @@ const Vector<Sensor> SensorList::getDynamicSensors() const { Vector<Sensor> sensors; forEachEntry( [&sensors] (const Entry& e) -> bool { - if (!e.isForDebug && e.si->getSensor().isDynamicSensor()) { + if (!e.isForDebug && e.si->getSensor().isDynamicSensor() + && e.deviceId == RuntimeSensor::DEFAULT_DEVICE_ID) { sensors.add(e.si->getSensor()); } return true; @@ -118,7 +121,20 @@ const Vector<Sensor> SensorList::getVirtualSensors() const { Vector<Sensor> sensors; forEachEntry( [&sensors] (const Entry& e) -> bool { - if (e.isVirtual) { + if (e.isVirtual && e.deviceId == RuntimeSensor::DEFAULT_DEVICE_ID) { + sensors.add(e.si->getSensor()); + } + return true; + }); + return sensors; +} + +const Vector<Sensor> SensorList::getRuntimeSensors(int deviceId) const { + // lock in forEachEntry + Vector<Sensor> sensors; + forEachEntry( + [&sensors, deviceId] (const Entry& e) -> bool { + if (!e.isForDebug && e.deviceId == deviceId) { sensors.add(e.si->getSensor()); } return true; diff --git a/services/sensorservice/SensorList.h b/services/sensorservice/SensorList.h index 049ae7c855..79f6701922 100644 --- a/services/sensorservice/SensorList.h +++ b/services/sensorservice/SensorList.h @@ -40,14 +40,16 @@ public: sp<SensorInterface> si; const bool isForDebug; const bool isVirtual; - Entry(SensorInterface* si_, bool debug_, bool virtual_) : - si(si_), isForDebug(debug_), isVirtual(virtual_) { + const int deviceId; + Entry(SensorInterface* si_, bool debug_, bool virtual_, int deviceId_) : + si(si_), isForDebug(debug_), isVirtual(virtual_), deviceId(deviceId_) { } }; // After SensorInterface * is added into SensorList, it can be assumed that SensorList own the // object it pointed to and the object should not be released elsewhere. - bool add(int handle, SensorInterface* si, bool isForDebug = false, bool isVirtual = false); + bool add(int handle, SensorInterface* si, bool isForDebug = false, bool isVirtual = false, + int deviceId = RuntimeSensor::DEFAULT_DEVICE_ID); // After a handle is removed, the object that SensorInterface * pointing to may get deleted if // no more sp<> of the same object exist. @@ -60,6 +62,7 @@ public: const Vector<Sensor> getUserDebugSensors() const; const Vector<Sensor> getDynamicSensors() const; const Vector<Sensor> getVirtualSensors() const; + const Vector<Sensor> getRuntimeSensors(int deviceId) const; String8 getName(int handle) const; String8 getStringType(int handle) const; diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 21d6b6b16f..0c9fef5652 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -102,6 +102,33 @@ static const String16 sDumpPermission("android.permission.DUMP"); static const String16 sLocationHardwarePermission("android.permission.LOCATION_HARDWARE"); static const String16 sManageSensorsPermission("android.permission.MANAGE_SENSORS"); +namespace { + +// TODO(b/259227294): Move the sensor ranges to the HAL. +int32_t nextRuntimeSensorHandle() { + static constexpr int32_t kRuntimeHandleBase = 0x5F000000; + static constexpr int32_t kRuntimeHandleEnd = 0x5FFFFFFF; + static int32_t nextHandle = kRuntimeHandleBase; + if (nextHandle == kRuntimeHandleEnd) { + return -1; + } + return nextHandle++; +} + +class RuntimeSensorCallbackProxy : public RuntimeSensor::StateChangeCallback { + public: + RuntimeSensorCallbackProxy(sp<SensorService::RuntimeSensorStateChangeCallback> callback) + : mCallback(std::move(callback)) {} + void onStateChanged(bool enabled, int64_t samplingPeriodNs, + int64_t batchReportLatencyNs) override { + mCallback->onStateChanged(enabled, samplingPeriodNs, batchReportLatencyNs); + } + private: + sp<SensorService::RuntimeSensorStateChangeCallback> mCallback; +}; + +} // namespace + static bool isAutomotive() { sp<IServiceManager> serviceManager = defaultServiceManager(); if (serviceManager.get() == nullptr) { @@ -137,6 +164,60 @@ SensorService::SensorService() mMicSensorPrivacyPolicy = new MicrophonePrivacyPolicy(this); } +int SensorService::registerRuntimeSensor( + const sensor_t& sensor, int deviceId, sp<RuntimeSensorStateChangeCallback> callback) { + int handle = 0; + while (handle == 0 || !mSensors.isNewHandle(handle)) { + handle = nextRuntimeSensorHandle(); + if (handle < 0) { + // Ran out of the dedicated range for runtime sensors. + return handle; + } + } + + ALOGI("Registering runtime sensor handle 0x%x, type %d, name %s", + handle, sensor.type, sensor.name); + + sp<RuntimeSensor::StateChangeCallback> runtimeSensorCallback( + new RuntimeSensorCallbackProxy(std::move(callback))); + sensor_t runtimeSensor = sensor; + // force the handle to be consistent + runtimeSensor.handle = handle; + SensorInterface *si = new RuntimeSensor(runtimeSensor, std::move(runtimeSensorCallback)); + + Mutex::Autolock _l(mLock); + const Sensor& s = registerSensor(si, /* isDebug= */ false, /* isVirtual= */ false, deviceId); + + if (s.getHandle() != handle) { + // The registration was unsuccessful. + return s.getHandle(); + } + return handle; +} + +status_t SensorService::unregisterRuntimeSensor(int handle) { + ALOGI("Unregistering runtime sensor handle 0x%x disconnected", handle); + { + Mutex::Autolock _l(mLock); + if (!unregisterDynamicSensorLocked(handle)) { + ALOGE("Runtime sensor release error."); + return UNKNOWN_ERROR; + } + } + + ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock); + for (const sp<SensorEventConnection>& connection : connLock.getActiveConnections()) { + connection->removeSensor(handle); + } + return OK; +} + +status_t SensorService::sendRuntimeSensorEvent(const sensors_event_t& event) { + Mutex::Autolock _l(mLock); + mRuntimeSensorEventQueue.push(event); + return OK; +} + bool SensorService::initializeHmacKey() { int fd = open(SENSOR_SERVICE_HMAC_KEY_FILE, O_RDONLY|O_CLOEXEC); if (fd != -1) { @@ -407,10 +488,11 @@ bool SensorService::hasSensorAccessLocked(uid_t uid, const String16& opPackageNa && isUidActive(uid) && !isOperationRestrictedLocked(opPackageName); } -const Sensor& SensorService::registerSensor(SensorInterface* s, bool isDebug, bool isVirtual) { +const Sensor& SensorService::registerSensor(SensorInterface* s, bool isDebug, bool isVirtual, + int deviceId) { int handle = s->getSensor().getHandle(); int type = s->getSensor().getType(); - if (mSensors.add(handle, s, isDebug, isVirtual)){ + if (mSensors.add(handle, s, isDebug, isVirtual, deviceId)) { mRecentEvent.emplace(handle, new SensorServiceUtil::RecentEventLogger(type)); return s->getSensor(); } else { @@ -1003,6 +1085,7 @@ bool SensorService::threadLoop() { recordLastValueLocked(mSensorEventBuffer, count); // handle virtual sensors + bool bufferNeedsSorting = false; if (count && vcount) { sensors_event_t const * const event = mSensorEventBuffer; if (!mActiveVirtualSensors.empty()) { @@ -1038,12 +1121,37 @@ bool SensorService::threadLoop() { // record the last synthesized values recordLastValueLocked(&mSensorEventBuffer[count], k); count += k; - // sort the buffer by time-stamps - sortEventBuffer(mSensorEventBuffer, count); + bufferNeedsSorting = true; } } } + // handle runtime sensors + { + size_t k = 0; + while (!mRuntimeSensorEventQueue.empty()) { + if (count + k >= minBufferSize) { + ALOGE("buffer too small to hold all events: count=%zd, k=%zu, size=%zu", + count, k, minBufferSize); + break; + } + mSensorEventBuffer[count + k] = mRuntimeSensorEventQueue.front(); + mRuntimeSensorEventQueue.pop(); + k++; + } + if (k) { + // record the last synthesized values + recordLastValueLocked(&mSensorEventBuffer[count], k); + count += k; + bufferNeedsSorting = true; + } + } + + if (bufferNeedsSorting) { + // sort the buffer by time-stamps + sortEventBuffer(mSensorEventBuffer, count); + } + // handle backward compatibility for RotationVector sensor if (halVersion < SENSORS_DEVICE_API_VERSION_1_0) { for (int i = 0; i < count; i++) { @@ -1342,19 +1450,37 @@ Vector<Sensor> SensorService::getSensorList(const String16& opPackageName) { return accessibleSensorList; } +void SensorService::addSensorIfAccessible(const String16& opPackageName, const Sensor& sensor, + Vector<Sensor>& accessibleSensorList) { + if (canAccessSensor(sensor, "can't see", opPackageName)) { + accessibleSensorList.add(sensor); + } else if (sensor.getType() != SENSOR_TYPE_HEAD_TRACKER) { + ALOGI("Skipped sensor %s because it requires permission %s and app op %" PRId32, + sensor.getName().string(), sensor.getRequiredPermission().string(), + sensor.getRequiredAppOp()); + } +} + Vector<Sensor> SensorService::getDynamicSensorList(const String16& opPackageName) { Vector<Sensor> accessibleSensorList; mSensors.forEachSensor( [this, &opPackageName, &accessibleSensorList] (const Sensor& sensor) -> bool { if (sensor.isDynamicSensor()) { - if (canAccessSensor(sensor, "can't see", opPackageName)) { - accessibleSensorList.add(sensor); - } else if (sensor.getType() != SENSOR_TYPE_HEAD_TRACKER) { - ALOGI("Skipped sensor %s because it requires permission %s and app op %" PRId32, - sensor.getName().string(), - sensor.getRequiredPermission().string(), - sensor.getRequiredAppOp()); - } + addSensorIfAccessible(opPackageName, sensor, accessibleSensorList); + } + return true; + }); + makeUuidsIntoIdsForSensorList(accessibleSensorList); + return accessibleSensorList; +} + +Vector<Sensor> SensorService::getRuntimeSensorList(const String16& opPackageName, int deviceId) { + Vector<Sensor> accessibleSensorList; + mSensors.forEachEntry( + [this, &opPackageName, deviceId, &accessibleSensorList] ( + const SensorServiceUtil::SensorList::Entry& e) -> bool { + if (e.deviceId == deviceId) { + addSensorIfAccessible(opPackageName, e.si->getSensor(), accessibleSensorList); } return true; }); diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index 4ba3c51985..e4903987bc 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -42,6 +42,7 @@ #include <stdint.h> #include <sys/types.h> +#include <queue> #include <unordered_map> #include <unordered_set> #include <vector> @@ -143,6 +144,14 @@ public: virtual void onProximityActive(bool isActive) = 0; }; + class RuntimeSensorStateChangeCallback : public virtual RefBase { + public: + // Note that the callback is invoked from an async thread and can interact with the + // SensorService directly. + virtual void onStateChanged(bool enabled, int64_t samplingPeriodNanos, + int64_t batchReportLatencyNanos) = 0; + }; + static char const* getServiceName() ANDROID_API { return "sensorservice"; } SensorService() ANDROID_API; @@ -169,6 +178,11 @@ public: status_t addProximityActiveListener(const sp<ProximityActiveListener>& callback) ANDROID_API; status_t removeProximityActiveListener(const sp<ProximityActiveListener>& callback) ANDROID_API; + int registerRuntimeSensor(const sensor_t& sensor, int deviceId, + sp<RuntimeSensorStateChangeCallback> callback) ANDROID_API; + status_t unregisterRuntimeSensor(int handle) ANDROID_API; + status_t sendRuntimeSensorEvent(const sensors_event_t& event) ANDROID_API; + // Returns true if a sensor should be throttled according to our rate-throttling rules. static bool isSensorInCappedSet(int sensorType); @@ -346,6 +360,7 @@ private: // ISensorServer interface virtual Vector<Sensor> getSensorList(const String16& opPackageName); virtual Vector<Sensor> getDynamicSensorList(const String16& opPackageName); + virtual Vector<Sensor> getRuntimeSensorList(const String16& opPackageName, int deviceId); virtual sp<ISensorEventConnection> createSensorEventConnection( const String8& packageName, int requestedMode, const String16& opPackageName, const String16& attributionTag); @@ -364,8 +379,9 @@ private: bool isWakeUpSensor(int type) const; void recordLastValueLocked(sensors_event_t const* buffer, size_t count); static void sortEventBuffer(sensors_event_t* buffer, size_t count); - const Sensor& registerSensor(SensorInterface* sensor, - bool isDebug = false, bool isVirtual = false); + const Sensor& registerSensor(SensorInterface* sensor, bool isDebug = false, + bool isVirtual = false, + int deviceId = RuntimeSensor::DEFAULT_DEVICE_ID); const Sensor& registerVirtualSensor(SensorInterface* sensor, bool isDebug = false); const Sensor& registerDynamicSensorLocked(SensorInterface* sensor, bool isDebug = false); bool unregisterDynamicSensorLocked(int handle); @@ -375,6 +391,8 @@ private: sensors_event_t const* buffer, const int count); bool canAccessSensor(const Sensor& sensor, const char* operation, const String16& opPackageName); + void addSensorIfAccessible(const String16& opPackageName, const Sensor& sensor, + Vector<Sensor>& accessibleSensorList); static bool hasPermissionForSensor(const Sensor& sensor); static int getTargetSdkVersion(const String16& opPackageName); static void resetTargetSdkVersionCache(const String16& opPackageName); @@ -492,6 +510,7 @@ private: wp<const SensorEventConnection> * mMapFlushEventsToConnections; std::unordered_map<int, SensorServiceUtil::RecentEventLogger*> mRecentEvent; Mode mCurrentOperatingMode; + std::queue<sensors_event_t> mRuntimeSensorEventQueue; // true if the head tracker sensor type is currently restricted to system usage only // (can only be unrestricted for testing, via shell cmd) diff --git a/services/sensorservice/aidl/EventQueue.cpp b/services/sensorservice/aidl/EventQueue.cpp index 88ab7a7e41..c3947098c3 100644 --- a/services/sensorservice/aidl/EventQueue.cpp +++ b/services/sensorservice/aidl/EventQueue.cpp @@ -66,7 +66,6 @@ EventQueue::EventQueue(std::shared_ptr<IEventQueueCallback> callback, sp<::andro new EventQueueLooperCallback(internalQueue, callback), nullptr); } -// FIXME why was this on onLastStrongRef instead of dtor? EventQueue::~EventQueue() { mLooper->removeFd(mInternalQueue->getFd()); } diff --git a/services/sensorservice/aidl/SensorManager.cpp b/services/sensorservice/aidl/SensorManager.cpp index 6d8d5741af..9b0334443b 100644 --- a/services/sensorservice/aidl/SensorManager.cpp +++ b/services/sensorservice/aidl/SensorManager.cpp @@ -201,7 +201,7 @@ sp<Looper> SensorManagerAidl::getLooper() { // if thread not initialized, start thread mStopThread = false; std::thread pollThread{[&stopThread = mStopThread, looper = mLooper, javaVm = mJavaVm] { - struct sched_param p = {0}; + struct sched_param p = {}; p.sched_priority = 10; if (sched_setscheduler(0 /* current thread*/, SCHED_FIFO, &p) != 0) { LOG(ERROR) << "Could not use SCHED_FIFO for looper thread: " << strerror(errno); diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h index e220541461..c555b39db1 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h @@ -34,7 +34,7 @@ public: MOCK_METHOD(void, setExpensiveRenderingExpected, (DisplayId displayId, bool expected), (override)); MOCK_METHOD(bool, isUsingExpensiveRendering, (), (override)); - MOCK_METHOD(void, notifyDisplayUpdateImminent, (), (override)); + MOCK_METHOD(void, notifyDisplayUpdateImminentAndCpuReset, (), (override)); MOCK_METHOD(bool, usePowerHintSession, (), (override)); MOCK_METHOD(bool, supportsPowerHintSession, (), (override)); MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override)); diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index cb2c8c53ef..f05223cce0 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -57,6 +57,7 @@ using android::hardware::power::Boost; using android::hardware::power::IPower; using android::hardware::power::IPowerHintSession; using android::hardware::power::Mode; +using android::hardware::power::SessionHint; using android::hardware::power::WorkDuration; PowerAdvisor::~PowerAdvisor() = default; @@ -140,7 +141,7 @@ void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expec } } -void PowerAdvisor::notifyDisplayUpdateImminent() { +void PowerAdvisor::notifyDisplayUpdateImminentAndCpuReset() { // Only start sending this notification once the system has booted so we don't introduce an // early-boot dependency on Power HAL if (!mBootFinished.load()) { @@ -154,7 +155,7 @@ void PowerAdvisor::notifyDisplayUpdateImminent() { return; } - if (!halWrapper->notifyDisplayUpdateImminent()) { + if (!halWrapper->notifyDisplayUpdateImminentAndCpuReset()) { // The HAL has become unavailable; attempt to reconnect later mReconnectPowerHal = true; return; @@ -599,7 +600,7 @@ public: return ret.isOk(); } - bool notifyDisplayUpdateImminent() override { + bool notifyDisplayUpdateImminentAndCpuReset() override { // Power HAL 1.x doesn't have a notification for this ALOGV("HIDL notifyUpdateImminent received but can't send"); return true; @@ -675,8 +676,12 @@ bool AidlPowerHalWrapper::setExpensiveRendering(bool enabled) { return ret.isOk(); } -bool AidlPowerHalWrapper::notifyDisplayUpdateImminent() { - ALOGV("AIDL notifyDisplayUpdateImminent"); +bool AidlPowerHalWrapper::notifyDisplayUpdateImminentAndCpuReset() { + ALOGV("AIDL notifyDisplayUpdateImminentAndCpuReset"); + if (isPowerHintSessionRunning()) { + mPowerHintSession->sendHint(SessionHint::CPU_LOAD_RESET); + } + if (!mHasDisplayUpdateImminent) { ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it"); return true; diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h index 1c9d123a1f..d45e7cb572 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h @@ -48,7 +48,7 @@ public: virtual void onBootFinished() = 0; virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0; virtual bool isUsingExpensiveRendering() = 0; - virtual void notifyDisplayUpdateImminent() = 0; + virtual void notifyDisplayUpdateImminentAndCpuReset() = 0; // Checks both if it supports and if it's enabled virtual bool usePowerHintSession() = 0; virtual bool supportsPowerHintSession() = 0; @@ -106,7 +106,7 @@ public: virtual ~HalWrapper() = default; virtual bool setExpensiveRendering(bool enabled) = 0; - virtual bool notifyDisplayUpdateImminent() = 0; + virtual bool notifyDisplayUpdateImminentAndCpuReset() = 0; virtual bool supportsPowerHintSession() = 0; virtual bool isPowerHintSessionRunning() = 0; virtual void restartPowerHintSession() = 0; @@ -126,7 +126,7 @@ public: void onBootFinished() override; void setExpensiveRenderingExpected(DisplayId displayId, bool expected) override; bool isUsingExpensiveRendering() override { return mNotifiedExpensiveRendering; }; - void notifyDisplayUpdateImminent() override; + void notifyDisplayUpdateImminentAndCpuReset() override; bool usePowerHintSession() override; bool supportsPowerHintSession() override; bool isPowerHintSessionRunning() override; @@ -289,7 +289,7 @@ public: static std::unique_ptr<HalWrapper> connect(); bool setExpensiveRendering(bool enabled) override; - bool notifyDisplayUpdateImminent() override; + bool notifyDisplayUpdateImminentAndCpuReset() override; bool supportsPowerHintSession() override; bool isPowerHintSessionRunning() override; void restartPowerHintSession() override; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 0570c7314b..7bd08a7213 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1840,7 +1840,7 @@ void SurfaceFlinger::scheduleCommit(FrameHint hint) { if (hint == FrameHint::kActive) { mScheduler->resetIdleTimer(); } - mPowerAdvisor->notifyDisplayUpdateImminent(); + mPowerAdvisor->notifyDisplayUpdateImminentAndCpuReset(); mScheduler->scheduleFrame(); } diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h index c2c3d77364..5654691884 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h @@ -36,7 +36,7 @@ public: MockAidlPowerHalWrapper(); ~MockAidlPowerHalWrapper() override; MOCK_METHOD(bool, setExpensiveRendering, (bool enabled), (override)); - MOCK_METHOD(bool, notifyDisplayUpdateImminent, (), (override)); + MOCK_METHOD(bool, notifyDisplayUpdateImminentAndCpuReset, (), (override)); MOCK_METHOD(bool, supportsPowerHintSession, (), (override)); MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override)); MOCK_METHOD(void, restartPowerHintSession, (), (override)); diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h index fb1b3946a4..7fc625c4b6 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h @@ -32,7 +32,7 @@ public: MOCK_METHOD(void, setExpensiveRenderingExpected, (DisplayId displayId, bool expected), (override)); MOCK_METHOD(bool, isUsingExpensiveRendering, (), (override)); - MOCK_METHOD(void, notifyDisplayUpdateImminent, (), (override)); + MOCK_METHOD(void, notifyDisplayUpdateImminentAndCpuReset, (), (override)); MOCK_METHOD(bool, usePowerHintSession, (), (override)); MOCK_METHOD(bool, supportsPowerHintSession, (), (override)); MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override)); diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp deleted file mode 100644 index 80e9a3c3b1..0000000000 --- a/services/vr/hardware_composer/Android.bp +++ /dev/null @@ -1,134 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_native_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_native_license"], -} - -cc_library_shared { - name: "libvr_hwc-hal", - - system_ext_specific: true, - - srcs: [ - "impl/vr_hwc.cpp", - "impl/vr_composer_client.cpp", - ], - - static_libs: [ - "libbroadcastring", - "libdisplay", - ], - - shared_libs: [ - "android.frameworks.vr.composer@2.0", - "android.hardware.graphics.composer@2.1", - "android.hardware.graphics.composer@2.2", - "android.hardware.graphics.composer@2.3", - "android.hardware.graphics.composer@2.1-resources", - "android.hardware.graphics.mapper@2.0", - "android.hardware.graphics.mapper@3.0", - "android.hardware.graphics.mapper@4.0", - "libbase", - "libbufferhubqueue", - "libbinder", - "libcutils", - "libfmq", - "libhardware", - "libhidlbase", - "liblog", - "libsync", - "libui", - "libutils", - "libpdx_default_transport", - ], - - header_libs: [ - "android.hardware.graphics.composer@2.1-command-buffer", - "android.hardware.graphics.composer@2.3-hal", - ], - - export_header_lib_headers: [ - "android.hardware.graphics.composer@2.3-hal", - ], - - export_static_lib_headers: [ - "libdisplay", - ], - - export_shared_lib_headers: [ - "android.frameworks.vr.composer@2.0", - "android.hardware.graphics.composer@2.1", - "android.hardware.graphics.composer@2.2", - "android.hardware.graphics.composer@2.3", - ], - - export_include_dirs: ["."], - - cflags: [ - "-DLOG_TAG=\"vr_hwc\"", - "-DATRACE_TAG=ATRACE_TAG_GRAPHICS", - "-Wall", - "-Werror", - "-Wno-error=unused-private-field", - // Warnings in vr_hwc.cpp to be fixed after sync of goog/master. - "-Wno-sign-compare", - "-Wno-unused-parameter", - ], - -} - -cc_library_static { - name: "libvr_hwc-impl", - srcs: [ - "vr_composer.cpp", - ], - static_libs: [ - "libvr_hwc-binder", - ], - shared_libs: [ - "libbase", - "libbinder", - "liblog", - "libui", - "libutils", - "libvr_hwc-hal", - ], - export_shared_lib_headers: [ - "libvr_hwc-hal", - ], - cflags: [ - "-DLOG_TAG=\"vr_hwc\"", - "-Wall", - "-Werror", - ], -} - -cc_test { - name: "vr_hwc_test", - gtest: true, - srcs: ["tests/vr_composer_test.cpp"], - static_libs: [ - "libgtest", - "libvr_hwc-impl", - // NOTE: This needs to be included after the *-impl lib otherwise the - // symbols in the *-binder library get optimized out. - "libvr_hwc-binder", - ], - cflags: [ - "-Wall", - "-Werror", - // warnings in vr_composer_test.cpp to be fixed after merge of goog/master - "-Wno-sign-compare", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "libbinder", - "liblog", - "libui", - "libutils", - ], -} diff --git a/services/vr/hardware_composer/aidl/Android.bp b/services/vr/hardware_composer/aidl/Android.bp deleted file mode 100644 index fa71ed7633..0000000000 --- a/services/vr/hardware_composer/aidl/Android.bp +++ /dev/null @@ -1,36 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_native_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_native_license"], -} - -cc_library_static { - name: "libvr_hwc-binder", - srcs: [ - "android/dvr/IVrComposer.aidl", - "android/dvr/IVrComposerCallback.aidl", - "android/dvr/parcelable_composer_frame.cpp", - "android/dvr/parcelable_composer_layer.cpp", - "android/dvr/parcelable_unique_fd.cpp", - ], - aidl: { - local_include_dirs: ["."], - export_aidl_headers: true, - }, - export_include_dirs: ["."], - - cflags: [ - "-Wall", - "-Werror", - ], - - shared_libs: [ - "libbinder", - "libui", - "libutils", - "libvr_hwc-hal", - ], -} diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl deleted file mode 100644 index be1ec5b2a3..0000000000 --- a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl +++ /dev/null @@ -1,25 +0,0 @@ -package android.dvr; - -import android.dvr.IVrComposerCallback; - -/** - * Service interface exposed by VR HWC exposed to system apps which allows one - * system app to connect to get SurfaceFlinger's outputs (all displays). This - * is active when SurfaceFlinger is in VR mode, where all 2D output is - * redirected to VR HWC. - * - * @hide */ -interface IVrComposer -{ - const String SERVICE_NAME = "vr_hwc"; - - /** - * Registers a callback used to receive frame notifications. - */ - void registerObserver(in IVrComposerCallback callback); - - /** - * Clears a previously registered frame notification callback. - */ - void clearObserver(); -} diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl deleted file mode 100644 index aa70de1645..0000000000 --- a/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl +++ /dev/null @@ -1,22 +0,0 @@ -package android.dvr; - -import android.dvr.ParcelableComposerFrame; -import android.dvr.ParcelableUniqueFd; - -/** - * A system app will implement and register this callback with VRComposer - * to receive the layers SurfaceFlinger presented when in VR mode. - * - * @hide */ -interface IVrComposerCallback { - /** - * Called by the VR HWC service when a new frame is ready to be presented. - * - * @param frame The new frame VR HWC wants to present. - * @return A fence FD used to signal when the previous frame is no longer - * used by the client. This may be an invalid fence (-1) if the client is not - * using the previous frame, in which case the previous frame may be re-used - * at any point in time. - */ - ParcelableUniqueFd onNewFrame(in ParcelableComposerFrame frame); -} diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl deleted file mode 100644 index 84abc19c23..0000000000 --- a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl +++ /dev/null @@ -1,3 +0,0 @@ -package android.dvr; - -parcelable ParcelableComposerFrame cpp_header "android/dvr/parcelable_composer_frame.h"; diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl deleted file mode 100644 index a200345fbd..0000000000 --- a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl +++ /dev/null @@ -1,3 +0,0 @@ -package android.dvr; - -parcelable ParcelableComposerLayer cpp_header "android/dvr/parcelable_composer_layer.h"; diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl deleted file mode 100644 index eee9d138ba..0000000000 --- a/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl +++ /dev/null @@ -1,3 +0,0 @@ -package android.dvr; - -parcelable ParcelableUniqueFd cpp_header "android/dvr/parcelable_unique_fd.h"; diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp deleted file mode 100644 index db7d5dc225..0000000000 --- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "aidl/android/dvr/parcelable_composer_frame.h" - -#include <binder/Parcel.h> - -#include "aidl/android/dvr/parcelable_composer_layer.h" - -namespace android { -namespace dvr { - -ParcelableComposerFrame::ParcelableComposerFrame() {} - -ParcelableComposerFrame::ParcelableComposerFrame( - const ComposerView::Frame& frame) - : frame_(frame) {} - -ParcelableComposerFrame::~ParcelableComposerFrame() {} - -status_t ParcelableComposerFrame::writeToParcel(Parcel* parcel) const { - status_t ret = parcel->writeUint64(frame_.display_id); - if (ret != OK) return ret; - - ret = parcel->writeInt32(frame_.display_width); - if (ret != OK) return ret; - - ret = parcel->writeInt32(frame_.display_height); - if (ret != OK) return ret; - - ret = parcel->writeBool(frame_.removed); - if (ret != OK) return ret; - - ret = parcel->writeUint32(static_cast<uint32_t>(frame_.active_config)); - if (ret != OK) return ret; - - ret = parcel->writeUint32(static_cast<uint32_t>(frame_.color_mode)); - if (ret != OK) return ret; - - ret = parcel->writeUint32(static_cast<uint32_t>(frame_.power_mode)); - if (ret != OK) return ret; - - ret = parcel->writeUint32(static_cast<uint32_t>(frame_.vsync_enabled)); - if (ret != OK) return ret; - - ret = parcel->writeInt32(frame_.color_transform_hint); - if (ret != OK) return ret; - - for(size_t i = 0; i < 16; i++) { - ret = parcel->writeFloat(frame_.color_transform[i]); - if (ret != OK) return ret; - } - - std::vector<ParcelableComposerLayer> layers; - for (size_t i = 0; i < frame_.layers.size(); ++i) - layers.push_back(ParcelableComposerLayer(frame_.layers[i])); - - ret = parcel->writeParcelableVector(layers); - - return ret; -} - -status_t ParcelableComposerFrame::readFromParcel(const Parcel* parcel) { - status_t ret = parcel->readUint64(&frame_.display_id); - if (ret != OK) return ret; - - ret = parcel->readInt32(&frame_.display_width); - if (ret != OK) return ret; - - ret = parcel->readInt32(&frame_.display_height); - if (ret != OK) return ret; - - ret = parcel->readBool(&frame_.removed); - if (ret != OK) return ret; - - uint32_t value; - ret = parcel->readUint32(&value); - if (ret != OK) return ret; - frame_.active_config = static_cast<Config>(value); - - ret = parcel->readUint32(&value); - if (ret != OK) return ret; - frame_.color_mode = static_cast<ColorMode>(value); - - ret = parcel->readUint32(&value); - if (ret != OK) return ret; - frame_.power_mode = static_cast<IComposerClient::PowerMode>(value); - - ret = parcel->readUint32(&value); - if (ret != OK) return ret; - frame_.vsync_enabled = static_cast<IComposerClient::Vsync>(value); - - ret = parcel->readInt32(&frame_.color_transform_hint); - if (ret != OK) return ret; - - for(size_t i = 0; i < 16; i++) { - ret = parcel->readFloat(&frame_.color_transform[i]); - if (ret != OK) return ret; - } - - std::vector<ParcelableComposerLayer> layers; - ret = parcel->readParcelableVector(&layers); - if (ret != OK) return ret; - - frame_.layers.clear(); - for (size_t i = 0; i < layers.size(); ++i) - frame_.layers.push_back(layers[i].layer()); - - return ret; -} - -} // namespace dvr -} // namespace android diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h deleted file mode 100644 index a82df7f2e7..0000000000 --- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H -#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H - -#include <binder/Parcelable.h> -#include <impl/vr_hwc.h> - -namespace android { -namespace dvr { - -class ParcelableComposerFrame : public Parcelable { - public: - ParcelableComposerFrame(); - explicit ParcelableComposerFrame(const ComposerView::Frame& frame); - ~ParcelableComposerFrame() override; - - ComposerView::Frame frame() const { return frame_; } - - status_t writeToParcel(Parcel* parcel) const override; - status_t readFromParcel(const Parcel* parcel) override; - - private: - ComposerView::Frame frame_; -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp deleted file mode 100644 index c3621ebf0f..0000000000 --- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp +++ /dev/null @@ -1,240 +0,0 @@ -#include "aidl/android/dvr/parcelable_composer_layer.h" - -#include <binder/Parcel.h> -#include <ui/Fence.h> -#include <ui/GraphicBuffer.h> -#include <ui/GraphicBufferMapper.h> - -namespace android { -namespace dvr { - -ParcelableComposerLayer::ParcelableComposerLayer() {} - -ParcelableComposerLayer::ParcelableComposerLayer( - const ComposerView::ComposerLayer& layer) : layer_(layer) {} - -ParcelableComposerLayer::~ParcelableComposerLayer() {} - -status_t ParcelableComposerLayer::writeToParcel(Parcel* parcel) const { - status_t ret = parcel->writeUint64(layer_.id); - if (ret != OK) return ret; - - ret = parcel->write(*layer_.buffer); - if (ret != OK) return ret; - - ret = parcel->writeBool(layer_.fence->isValid()); - if (ret != OK) return ret; - - if (layer_.fence->isValid()) { - ret = parcel->writeFileDescriptor(layer_.fence->dup(), true); - if (ret != OK) return ret; - } - - ret = parcel->writeInt32(layer_.display_frame.left); - if (ret != OK) return ret; - - ret = parcel->writeInt32(layer_.display_frame.top); - if (ret != OK) return ret; - - ret = parcel->writeInt32(layer_.display_frame.right); - if (ret != OK) return ret; - - ret = parcel->writeInt32(layer_.display_frame.bottom); - if (ret != OK) return ret; - - ret = parcel->writeFloat(layer_.crop.left); - if (ret != OK) return ret; - - ret = parcel->writeFloat(layer_.crop.top); - if (ret != OK) return ret; - - ret = parcel->writeFloat(layer_.crop.right); - if (ret != OK) return ret; - - ret = parcel->writeFloat(layer_.crop.bottom); - if (ret != OK) return ret; - - ret = parcel->writeInt32(static_cast<int32_t>(layer_.blend_mode)); - if (ret != OK) return ret; - - ret = parcel->writeFloat(layer_.alpha); - if (ret != OK) return ret; - - ret = parcel->writeUint32(layer_.type); - if (ret != OK) return ret; - - ret = parcel->writeUint32(layer_.app_id); - if (ret != OK) return ret; - - ret = parcel->writeUint32(layer_.z_order); - if (ret != OK) return ret; - - ret = parcel->writeInt32(layer_.cursor_x); - if (ret != OK) return ret; - - ret = parcel->writeInt32(layer_.cursor_y); - if (ret != OK) return ret; - - uint32_t color = layer_.color.r | - (static_cast<uint32_t>(layer_.color.g) << 8) | - (static_cast<uint32_t>(layer_.color.b) << 16) | - (static_cast<uint32_t>(layer_.color.a) << 24); - ret = parcel->writeUint32(color); - if (ret != OK) return ret; - - ret = parcel->writeInt32(layer_.dataspace); - if (ret != OK) return ret; - - ret = parcel->writeInt32(layer_.transform); - if (ret != OK) return ret; - - ret = parcel->writeUint32(static_cast<uint32_t>(layer_.visible_regions.size())); - if (ret != OK) return ret; - - for (auto& rect: layer_.visible_regions) { - ret = parcel->writeInt32(rect.left); - ret = parcel->writeInt32(rect.top); - ret = parcel->writeInt32(rect.right); - ret = parcel->writeInt32(rect.bottom); - if (ret != OK) return ret; - } - - ret = parcel->writeUint32(static_cast<uint32_t>(layer_.damaged_regions.size())); - if (ret != OK) return ret; - - for (auto& rect: layer_.damaged_regions) { - ret = parcel->writeInt32(rect.left); - ret = parcel->writeInt32(rect.top); - ret = parcel->writeInt32(rect.right); - ret = parcel->writeInt32(rect.bottom); - if (ret != OK) return ret; - } - - return OK; -} - -status_t ParcelableComposerLayer::readFromParcel(const Parcel* parcel) { - status_t ret = parcel->readUint64(&layer_.id); - if (ret != OK) return ret; - - layer_.buffer = new GraphicBuffer(); - ret = parcel->read(*layer_.buffer); - if (ret != OK) { - layer_.buffer.clear(); - return ret; - } - - bool has_fence = 0; - ret = parcel->readBool(&has_fence); - if (ret != OK) return ret; - - if (has_fence) - layer_.fence = new Fence(dup(parcel->readFileDescriptor())); - else - layer_.fence = new Fence(); - - ret = parcel->readInt32(&layer_.display_frame.left); - if (ret != OK) return ret; - - ret = parcel->readInt32(&layer_.display_frame.top); - if (ret != OK) return ret; - - ret = parcel->readInt32(&layer_.display_frame.right); - if (ret != OK) return ret; - - ret = parcel->readInt32(&layer_.display_frame.bottom); - if (ret != OK) return ret; - - ret = parcel->readFloat(&layer_.crop.left); - if (ret != OK) return ret; - - ret = parcel->readFloat(&layer_.crop.top); - if (ret != OK) return ret; - - ret = parcel->readFloat(&layer_.crop.right); - if (ret != OK) return ret; - - ret = parcel->readFloat(&layer_.crop.bottom); - if (ret != OK) return ret; - - ret = parcel->readInt32(reinterpret_cast<int32_t*>(&layer_.blend_mode)); - if (ret != OK) return ret; - - ret = parcel->readFloat(&layer_.alpha); - if (ret != OK) return ret; - - ret = parcel->readUint32(&layer_.type); - if (ret != OK) return ret; - - ret = parcel->readUint32(&layer_.app_id); - if (ret != OK) return ret; - - ret = parcel->readUint32(&layer_.z_order); - if (ret != OK) return ret; - - ret = parcel->readInt32(&layer_.cursor_x); - if (ret != OK) return ret; - - ret = parcel->readInt32(&layer_.cursor_y); - if (ret != OK) return ret; - - uint32_t color; - ret = parcel->readUint32(&color); - if (ret != OK) return ret; - layer_.color.r = color & 0xFF; - layer_.color.g = (color >> 8) & 0xFF; - layer_.color.b = (color >> 16) & 0xFF; - layer_.color.a = (color >> 24) & 0xFF; - - ret = parcel->readInt32(&layer_.dataspace); - if (ret != OK) return ret; - - ret = parcel->readInt32(&layer_.transform); - if (ret != OK) return ret; - - uint32_t size; - ret = parcel->readUint32(&size); - if (ret != OK) return ret; - - for(size_t i = 0; i < size; i++) { - hwc_rect_t rect; - ret = parcel->readInt32(&rect.left); - if (ret != OK) return ret; - - ret = parcel->readInt32(&rect.top); - if (ret != OK) return ret; - - ret = parcel->readInt32(&rect.right); - if (ret != OK) return ret; - - ret = parcel->readInt32(&rect.bottom); - if (ret != OK) return ret; - - layer_.visible_regions.push_back(rect); - } - - ret = parcel->readUint32(&size); - if (ret != OK) return ret; - - for(size_t i = 0; i < size; i++) { - hwc_rect_t rect; - ret = parcel->readInt32(&rect.left); - if (ret != OK) return ret; - - ret = parcel->readInt32(&rect.top); - if (ret != OK) return ret; - - ret = parcel->readInt32(&rect.right); - if (ret != OK) return ret; - - ret = parcel->readInt32(&rect.bottom); - if (ret != OK) return ret; - - layer_.damaged_regions.push_back(rect); - } - - return OK; -} - -} // namespace dvr -} // namespace android diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h deleted file mode 100644 index 6d2ac097e5..0000000000 --- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H -#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H - -#include <binder/Parcelable.h> -#include <impl/vr_hwc.h> - -#include <memory> - -namespace android { -namespace dvr { - -class ParcelableComposerLayer : public Parcelable { - public: - ParcelableComposerLayer(); - explicit ParcelableComposerLayer(const ComposerView::ComposerLayer& layer); - ~ParcelableComposerLayer() override; - - ComposerView::ComposerLayer layer() const { return layer_; } - - status_t writeToParcel(Parcel* parcel) const override; - status_t readFromParcel(const Parcel* parcel) override; - - private: - ComposerView::ComposerLayer layer_; -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp deleted file mode 100644 index 9486f3c919..0000000000 --- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "android/dvr/parcelable_unique_fd.h" - -#include <binder/Parcel.h> - -namespace android { -namespace dvr { - -ParcelableUniqueFd::ParcelableUniqueFd() {} - -ParcelableUniqueFd::ParcelableUniqueFd(const base::unique_fd& fence) - : fence_(dup(fence.get())) {} - -ParcelableUniqueFd::~ParcelableUniqueFd() {} - -status_t ParcelableUniqueFd::writeToParcel(Parcel* parcel) const { - status_t ret = parcel->writeBool(fence_.get() >= 0); - if (ret != OK) return ret; - - if (fence_.get() >= 0) - ret = parcel->writeUniqueFileDescriptor(fence_); - - return ret; -} - -status_t ParcelableUniqueFd::readFromParcel(const Parcel* parcel) { - bool has_fence = 0; - status_t ret = parcel->readBool(&has_fence); - if (ret != OK) return ret; - - if (has_fence) - ret = parcel->readUniqueFileDescriptor(&fence_); - - return ret; -} - -} // namespace dvr -} // namespace android diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h deleted file mode 100644 index c4216f6212..0000000000 --- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H -#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H - -#include <android-base/unique_fd.h> -#include <binder/Parcelable.h> - -namespace android { -namespace dvr { - -// Provide a wrapper to serialized base::unique_fd. The wrapper also handles the -// case where the FD is invalid (-1), unlike FileDescriptor which expects a -// valid FD. -class ParcelableUniqueFd : public Parcelable { - public: - ParcelableUniqueFd(); - explicit ParcelableUniqueFd(const base::unique_fd& fence); - ~ParcelableUniqueFd() override; - - void set_fence(const base::unique_fd& fence) { - fence_.reset(dup(fence.get())); - } - base::unique_fd fence() const { return base::unique_fd(dup(fence_.get())); } - - status_t writeToParcel(Parcel* parcel) const override; - status_t readFromParcel(const Parcel* parcel) override; - - private: - base::unique_fd fence_; -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp deleted file mode 100644 index dd1603d4a9..0000000000 --- a/services/vr/hardware_composer/impl/vr_composer_client.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2016 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/frameworks/vr/composer/2.0/IVrComposerClient.h> -#include <hardware/gralloc.h> -#include <hardware/gralloc1.h> -#include <log/log.h> - -#include <memory> - -#include "impl/vr_hwc.h" -#include "impl/vr_composer_client.h" - -namespace android { -namespace dvr { - -using android::frameworks::vr::composer::V2_0::IVrComposerClient; - -VrComposerClient::VrComposerClient(dvr::VrHwc& hal) - : ComposerClient(&hal), mVrHal(hal) { - if (!init()) { - LOG_ALWAYS_FATAL("failed to initialize VrComposerClient"); - } -} - -VrComposerClient::~VrComposerClient() {} - -std::unique_ptr<ComposerCommandEngine> -VrComposerClient::createCommandEngine() { - return std::make_unique<VrCommandEngine>(*this); -} - -VrComposerClient::VrCommandEngine::VrCommandEngine(VrComposerClient& client) - : ComposerCommandEngine(client.mHal, client.mResources.get()), - mVrHal(client.mVrHal) {} - -VrComposerClient::VrCommandEngine::~VrCommandEngine() {} - -bool VrComposerClient::VrCommandEngine::executeCommand( - hardware::graphics::composer::V2_1::IComposerClient::Command command, - uint16_t length) { - IVrComposerClient::VrCommand vrCommand = - static_cast<IVrComposerClient::VrCommand>(command); - switch (vrCommand) { - case IVrComposerClient::VrCommand::SET_LAYER_INFO: - return executeSetLayerInfo(length); - case IVrComposerClient::VrCommand::SET_CLIENT_TARGET_METADATA: - return executeSetClientTargetMetadata(length); - case IVrComposerClient::VrCommand::SET_LAYER_BUFFER_METADATA: - return executeSetLayerBufferMetadata(length); - default: - return ComposerCommandEngine::executeCommand(command, length); - } -} - -bool VrComposerClient::VrCommandEngine::executeSetLayerInfo(uint16_t length) { - if (length != 2) { - return false; - } - - auto err = mVrHal.setLayerInfo(mCurrentDisplay, mCurrentLayer, read(), read()); - if (err != Error::NONE) { - mWriter->setError(getCommandLoc(), err); - } - - return true; -} - -bool VrComposerClient::VrCommandEngine::executeSetClientTargetMetadata( - uint16_t length) { - if (length != 7) - return false; - - auto err = mVrHal.setClientTargetMetadata(mCurrentDisplay, readBufferMetadata()); - if (err != Error::NONE) - mWriter->setError(getCommandLoc(), err); - - return true; -} - -bool VrComposerClient::VrCommandEngine::executeSetLayerBufferMetadata( - uint16_t length) { - if (length != 7) - return false; - - auto err = mVrHal.setLayerBufferMetadata(mCurrentDisplay, mCurrentLayer, - readBufferMetadata()); - if (err != Error::NONE) - mWriter->setError(getCommandLoc(), err); - - return true; -} - -IVrComposerClient::BufferMetadata -VrComposerClient::VrCommandEngine::readBufferMetadata() { - IVrComposerClient::BufferMetadata metadata = { - .width = read(), - .height = read(), - .stride = read(), - .layerCount = read(), - .format = - static_cast<android::hardware::graphics::common::V1_2::PixelFormat>( - readSigned()), - .usage = read64(), - }; - return metadata; -} - -} // namespace dvr -} // namespace android diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h deleted file mode 100644 index 1b2b5f4f56..0000000000 --- a/services/vr/hardware_composer/impl/vr_composer_client.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2017 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 ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H -#define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H - -#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h> -#include <composer-command-buffer/2.3/ComposerCommandBuffer.h> -#include <composer-hal/2.1/ComposerClient.h> -#include <composer-hal/2.1/ComposerCommandEngine.h> -#include <composer-hal/2.2/ComposerClient.h> -#include <composer-hal/2.3/ComposerClient.h> - -namespace android { -namespace dvr { - -class VrHwc; - -using hardware::graphics::composer::V2_1::hal::ComposerCommandEngine; -using hardware::graphics::composer::V2_3::hal::ComposerHal; -using hardware::graphics::composer::V2_3::hal::detail::ComposerClientImpl; - -using ComposerClient = ComposerClientImpl<IVrComposerClient, ComposerHal>; - -class VrComposerClient : public ComposerClient { - public: - explicit VrComposerClient(android::dvr::VrHwc& hal); - virtual ~VrComposerClient(); - - private: - class VrCommandEngine : public ComposerCommandEngine { - public: - explicit VrCommandEngine(VrComposerClient& client); - ~VrCommandEngine() override; - - bool executeCommand( - hardware::graphics::composer::V2_1::IComposerClient::Command command, - uint16_t length) override; - - private: - bool executeSetLayerInfo(uint16_t length); - bool executeSetClientTargetMetadata(uint16_t length); - bool executeSetLayerBufferMetadata(uint16_t length); - - IVrComposerClient::BufferMetadata readBufferMetadata(); - - android::dvr::VrHwc& mVrHal; - - VrCommandEngine(const VrCommandEngine&) = delete; - void operator=(const VrCommandEngine&) = delete; - }; - - VrComposerClient(const VrComposerClient&) = delete; - void operator=(const VrComposerClient&) = delete; - - std::unique_ptr<ComposerCommandEngine> createCommandEngine() override; - dvr::VrHwc& mVrHal; -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp deleted file mode 100644 index e530b16b1b..0000000000 --- a/services/vr/hardware_composer/impl/vr_hwc.cpp +++ /dev/null @@ -1,1178 +0,0 @@ -/* - * Copyright 2016 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 "impl/vr_hwc.h" - -#include "android-base/stringprintf.h" -#include <binder/IServiceManager.h> -#include <cutils/properties.h> -#include <private/dvr/display_client.h> -#include <ui/Fence.h> -#include <utils/Trace.h> - -#include <mutex> - -#include "vr_composer_client.h" - -using namespace android::hardware::graphics::common::V1_0; -using namespace android::hardware::graphics::composer::V2_3; - -using android::base::StringPrintf; -using android::hardware::hidl_handle; -using android::hardware::hidl_string; -using android::hardware::hidl_vec; -using android::hardware::Return; -using android::hardware::Void; - -namespace types = android::hardware::graphics::common; - -namespace android { -namespace dvr { -namespace { - -const Display kDefaultDisplayId = 1; -const Config kDefaultConfigId = 1; - -sp<GraphicBuffer> CreateGraphicBuffer( - const native_handle_t* handle, - const IVrComposerClient::BufferMetadata& metadata) { - sp<GraphicBuffer> buffer = new GraphicBuffer( - handle, GraphicBuffer::CLONE_HANDLE, metadata.width, metadata.height, - static_cast<int32_t>(metadata.format), metadata.layerCount, - metadata.usage, metadata.stride); - if (buffer->initCheck() != OK) { - ALOGE("Failed to create graphic buffer"); - return nullptr; - } - - return buffer; -} - -void GetPrimaryDisplaySize(int32_t* width, int32_t* height) { - *width = 1080; - *height = 1920; - - int error = 0; - auto display_client = display::DisplayClient::Create(&error); - if (!display_client) { - ALOGE("Could not connect to display service : %s(%d)", strerror(error), - error); - return; - } - - auto status = display_client->GetDisplayMetrics(); - if (!status) { - ALOGE("Could not get display metrics from display service : %s(%d)", - status.GetErrorMessage().c_str(), status.error()); - return; - } - - *width = status.get().display_width; - *height = status.get().display_height; -} - -} // namespace - -HwcDisplay::HwcDisplay(int32_t width, int32_t height) - : width_(width), height_(height) {} - -HwcDisplay::~HwcDisplay() {} - -bool HwcDisplay::SetClientTarget(const native_handle_t* handle, - base::unique_fd fence) { - if (handle) - buffer_ = CreateGraphicBuffer(handle, buffer_metadata_); - - fence_ = new Fence(fence.release()); - return true; -} - -void HwcDisplay::SetClientTargetMetadata( - const IVrComposerClient::BufferMetadata& metadata) { - buffer_metadata_ = metadata; -} - -HwcLayer* HwcDisplay::CreateLayer() { - uint64_t layer_id = layer_ids_++; - layers_.push_back(HwcLayer(layer_id)); - return &layers_.back(); -} - -HwcLayer* HwcDisplay::GetLayer(Layer id) { - for (size_t i = 0; i < layers_.size(); ++i) - if (layers_[i].info.id == id) - return &layers_[i]; - - return nullptr; -} - -bool HwcDisplay::DestroyLayer(Layer id) { - for (auto it = layers_.begin(); it != layers_.end(); ++it) { - if (it->info.id == id) { - layers_.erase(it); - return true; - } - } - - return false; -} - -void HwcDisplay::GetChangedCompositionTypes( - std::vector<Layer>* layer_ids, - std::vector<IComposerClient::Composition>* types) { - std::sort(layers_.begin(), layers_.end(), - [](const auto& lhs, const auto& rhs) { - return lhs.info.z_order < rhs.info.z_order; - }); - - const size_t no_layer = std::numeric_limits<size_t>::max(); - size_t first_client_layer = no_layer, last_client_layer = no_layer; - for (size_t i = 0; i < layers_.size(); ++i) { - switch (layers_[i].composition_type) { - case IComposerClient::Composition::SOLID_COLOR: - case IComposerClient::Composition::CURSOR: - case IComposerClient::Composition::SIDEBAND: - if (first_client_layer == no_layer) - first_client_layer = i; - - last_client_layer = i; - break; - default: - break; - } - } - - for (size_t i = 0; i < layers_.size(); ++i) { - if (i >= first_client_layer && i <= last_client_layer) { - if (layers_[i].composition_type != IComposerClient::Composition::CLIENT) { - layer_ids->push_back(layers_[i].info.id); - types->push_back(IComposerClient::Composition::CLIENT); - layers_[i].composition_type = IComposerClient::Composition::CLIENT; - } - - continue; - } - - if (layers_[i].composition_type != IComposerClient::Composition::DEVICE) { - layer_ids->push_back(layers_[i].info.id); - types->push_back(IComposerClient::Composition::DEVICE); - layers_[i].composition_type = IComposerClient::Composition::DEVICE; - } - } -} - -Error HwcDisplay::GetFrame( - std::vector<ComposerView::ComposerLayer>* out_frames) { - bool queued_client_target = false; - std::vector<ComposerView::ComposerLayer> frame; - for (const auto& layer : layers_) { - if (layer.composition_type == IComposerClient::Composition::CLIENT) { - if (queued_client_target) - continue; - - if (!buffer_.get()) { - ALOGE("Client composition requested but no client target buffer"); - return Error::BAD_LAYER; - } - - ComposerView::ComposerLayer client_target_layer = { - .buffer = buffer_, - .fence = fence_.get() ? fence_ : new Fence(-1), - .display_frame = {0, 0, static_cast<int32_t>(buffer_->getWidth()), - static_cast<int32_t>(buffer_->getHeight())}, - .crop = {0.0f, 0.0f, static_cast<float>(buffer_->getWidth()), - static_cast<float>(buffer_->getHeight())}, - .blend_mode = IComposerClient::BlendMode::NONE, - }; - - frame.push_back(client_target_layer); - queued_client_target = true; - } else { - if (!layer.info.buffer.get() || !layer.info.fence.get()) { - ALOGV("Layer requested without valid buffer"); - continue; - } - - frame.push_back(layer.info); - } - } - - out_frames->swap(frame); - return Error::NONE; -} - -std::vector<Layer> HwcDisplay::UpdateLastFrameAndGetLastFrameLayers() { - std::vector<Layer> last_frame_layers; - last_frame_layers.swap(last_frame_layers_ids_); - - for (const auto& layer : layers_) - last_frame_layers_ids_.push_back(layer.info.id); - - return last_frame_layers; -} - -void HwcDisplay::SetColorTransform(const float* matrix, int32_t hint) { - color_transform_hint_ = hint; - if (matrix) - memcpy(color_transform_, matrix, sizeof(color_transform_)); -} - -void HwcDisplay::dumpDebugInfo(std::string* result) const { - if (!result) { - return; - } - *result += StringPrintf("HwcDisplay: width: %d, height: %d, layers size: %zu, colormode: %d\ - , config: %d\n", width_, height_, layers_.size(), color_mode_, active_config_); - *result += StringPrintf("HwcDisplay buffer metadata: width: %d, height: %d, stride: %d,\ - layerCount: %d, pixelFormat: %d\n", buffer_metadata_.width, buffer_metadata_.height, - buffer_metadata_.stride, buffer_metadata_.layerCount, buffer_metadata_.format); - for (const auto& layer : layers_) { - layer.dumpDebugInfo(result); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// VrHwcClient - -VrHwc::VrHwc() { - vsync_callback_ = new VsyncCallback; -} - -VrHwc::~VrHwc() { - vsync_callback_->SetEventCallback(nullptr); -} - -bool VrHwc::hasCapability(hwc2_capability_t /* capability */) { return false; } - -void VrHwc::registerEventCallback(EventCallback* callback) { - std::unique_lock<std::mutex> lock(mutex_); - event_callback_ = callback; - int32_t width, height; - GetPrimaryDisplaySize(&width, &height); - // Create the primary display late to avoid initialization issues between - // VR HWC and SurfaceFlinger. - displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height)); - - // Surface flinger will make calls back into vr_hwc when it receives the - // onHotplug() call, so it's important to release mutex_ here. - lock.unlock(); - event_callback_->onHotplug(kDefaultDisplayId, - hardware::graphics::composer::V2_1:: - IComposerCallback::Connection::CONNECTED); - lock.lock(); - UpdateVsyncCallbackEnabledLocked(); -} - -void VrHwc::unregisterEventCallback() { - std::lock_guard<std::mutex> guard(mutex_); - event_callback_ = nullptr; - UpdateVsyncCallbackEnabledLocked(); -} - -uint32_t VrHwc::getMaxVirtualDisplayCount() { return 1; } - -Error VrHwc::destroyVirtualDisplay(Display display) { - std::lock_guard<std::mutex> guard(mutex_); - if (display == kDefaultDisplayId || displays_.erase(display) == 0) - return Error::BAD_DISPLAY; - ComposerView::Frame frame; - frame.display_id = display; - frame.removed = true; - if (observer_) - observer_->OnNewFrame(frame); - return Error::NONE; -} - -Error VrHwc::createLayer(Display display, Layer* outLayer) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* layer = display_ptr->CreateLayer(); - *outLayer = layer->info.id; - return Error::NONE; -} - -Error VrHwc::destroyLayer(Display display, Layer layer) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) { - return Error::BAD_DISPLAY; - } - - return display_ptr->DestroyLayer(layer) ? Error::NONE : Error::BAD_LAYER; -} - -Error VrHwc::getActiveConfig(Display display, Config* outConfig) { - std::lock_guard<std::mutex> guard(mutex_); - if (!FindDisplay(display)) - return Error::BAD_DISPLAY; - *outConfig = kDefaultConfigId; - return Error::NONE; -} - -Error VrHwc::getDisplayAttribute(Display display, Config config, - IComposerClient::Attribute attribute, - int32_t* outValue) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) { - return Error::BAD_DISPLAY; - } - if (config != kDefaultConfigId) { - return Error::BAD_CONFIG; - } - - switch (attribute) { - case IComposerClient::Attribute::WIDTH: - *outValue = display_ptr->width(); - break; - case IComposerClient::Attribute::HEIGHT: - *outValue = display_ptr->height(); - break; - case IComposerClient::Attribute::VSYNC_PERIOD: - { - int error = 0; - auto display_client = display::DisplayClient::Create(&error); - if (!display_client) { - ALOGE("Could not connect to display service : %s(%d)", - strerror(error), error); - // Return a default value of 30 fps - *outValue = 1000 * 1000 * 1000 / 30; - } else { - auto metrics = display_client->GetDisplayMetrics(); - *outValue = metrics.get().vsync_period_ns; - } - } - break; - case IComposerClient::Attribute::DPI_X: - case IComposerClient::Attribute::DPI_Y: - { - constexpr int32_t kDefaultDPI = 300; - int32_t dpi = property_get_int32("ro.vr.hwc.dpi", kDefaultDPI); - if (dpi <= 0) { - dpi = kDefaultDPI; - } - *outValue = 1000 * dpi; - } - break; - default: - return Error::BAD_PARAMETER; - } - - return Error::NONE; -} - -Error VrHwc::getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) { - std::lock_guard<std::mutex> guard(mutex_); - if (!FindDisplay(display)) - return Error::BAD_DISPLAY; - std::vector<Config> configs(1, kDefaultConfigId); - *outConfigs = hidl_vec<Config>(configs); - return Error::NONE; -} - -Error VrHwc::getDisplayName(Display /* display */, hidl_string* outName) { - *outName = hidl_string(); - return Error::NONE; -} - -Error VrHwc::getDisplayType(Display display, - IComposerClient::DisplayType* outType) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) { - *outType = IComposerClient::DisplayType::INVALID; - return Error::BAD_DISPLAY; - } - - if (display == kDefaultDisplayId) - *outType = IComposerClient::DisplayType::PHYSICAL; - else - *outType = IComposerClient::DisplayType::VIRTUAL; - - return Error::NONE; -} - -Error VrHwc::getDozeSupport(Display display, bool* outSupport) { - *outSupport = false; - std::lock_guard<std::mutex> guard(mutex_); - if (!FindDisplay(display)) - return Error::BAD_DISPLAY; - return Error::NONE; -} - -Error VrHwc::setActiveConfig(Display display, Config config) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - if (config != kDefaultConfigId) - return Error::BAD_CONFIG; - - display_ptr->set_active_config(config); - return Error::NONE; -} - -Error VrHwc::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - if (enabled != IComposerClient::Vsync::ENABLE && - enabled != IComposerClient::Vsync::DISABLE) { - return Error::BAD_PARAMETER; - } - - Error set_vsync_result = Error::NONE; - if (display == kDefaultDisplayId) { - sp<IVsyncService> vsync_service = interface_cast<IVsyncService>( - defaultServiceManager()->getService( - String16(IVsyncService::GetServiceName()))); - if (vsync_service == nullptr) { - ALOGE("Failed to get vsync service"); - return Error::NO_RESOURCES; - } - - if (enabled == IComposerClient::Vsync::ENABLE) { - ALOGI("Enable vsync"); - display_ptr->set_vsync_enabled(true); - status_t result = vsync_service->registerCallback(vsync_callback_); - if (result != OK) { - ALOGE("%s service registerCallback() failed: %s (%d)", - IVsyncService::GetServiceName(), strerror(-result), result); - set_vsync_result = Error::NO_RESOURCES; - } - } else if (enabled == IComposerClient::Vsync::DISABLE) { - ALOGI("Disable vsync"); - display_ptr->set_vsync_enabled(false); - status_t result = vsync_service->unregisterCallback(vsync_callback_); - if (result != OK) { - ALOGE("%s service unregisterCallback() failed: %s (%d)", - IVsyncService::GetServiceName(), strerror(-result), result); - set_vsync_result = Error::NO_RESOURCES; - } - } - - UpdateVsyncCallbackEnabledLocked(); - } - - return set_vsync_result; -} - -Error VrHwc::setColorTransform(Display display, const float* matrix, - int32_t hint) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - display_ptr->SetColorTransform(matrix, hint); - return Error::NONE; -} - -Error VrHwc::setClientTarget(Display display, buffer_handle_t target, - int32_t acquireFence, int32_t /* dataspace */, - const std::vector<hwc_rect_t>& /* damage */) { - base::unique_fd fence(acquireFence); - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - if (target == nullptr) - return Error::NONE; - - if (!display_ptr->SetClientTarget(target, std::move(fence))) - return Error::BAD_PARAMETER; - - return Error::NONE; -} - -Error VrHwc::setOutputBuffer(Display display, buffer_handle_t /* buffer */, - int32_t releaseFence) { - base::unique_fd fence(releaseFence); - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - // TODO(dnicoara): Is it necessary to do anything here? - return Error::NONE; -} - -Error VrHwc::validateDisplay( - Display display, std::vector<Layer>* outChangedLayers, - std::vector<IComposerClient::Composition>* outCompositionTypes, - uint32_t* /* outDisplayRequestMask */, - std::vector<Layer>* /* outRequestedLayers */, - std::vector<uint32_t>* /* outRequestMasks */) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - display_ptr->GetChangedCompositionTypes(outChangedLayers, - outCompositionTypes); - return Error::NONE; -} - -Error VrHwc::acceptDisplayChanges(Display /* display */) { return Error::NONE; } - -Error VrHwc::presentDisplay(Display display, int32_t* outPresentFence, - std::vector<Layer>* outLayers, - std::vector<int32_t>* outReleaseFences) { - *outPresentFence = -1; - outLayers->clear(); - outReleaseFences->clear(); - - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - - if (!display_ptr) - return Error::BAD_DISPLAY; - - ComposerView::Frame frame; - std::vector<Layer> last_frame_layers; - Error status = display_ptr->GetFrame(&frame.layers); - frame.display_id = display; - frame.display_width = display_ptr->width(); - frame.display_height = display_ptr->height(); - frame.active_config = display_ptr->active_config(); - frame.power_mode = display_ptr->power_mode(); - frame.vsync_enabled = display_ptr->vsync_enabled() ? - IComposerClient::Vsync::ENABLE : IComposerClient::Vsync::DISABLE; - frame.color_transform_hint = display_ptr->color_transform_hint(); - frame.color_mode = display_ptr->color_mode(); - memcpy(frame.color_transform, display_ptr->color_transform(), - sizeof(frame.color_transform)); - if (status != Error::NONE) - return status; - - last_frame_layers = display_ptr->UpdateLastFrameAndGetLastFrameLayers(); - - base::unique_fd fence; - if (observer_) - fence = observer_->OnNewFrame(frame); - - if (fence.get() < 0) - return Error::NONE; - - *outPresentFence = dup(fence.get()); - outLayers->swap(last_frame_layers); - for (size_t i = 0; i < outLayers->size(); ++i) - outReleaseFences->push_back(dup(fence.get())); - - return Error::NONE; -} - -Error VrHwc::setLayerCursorPosition(Display display, Layer layer, int32_t x, - int32_t y) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* hwc_layer = display_ptr->GetLayer(layer); - if (!hwc_layer) - return Error::BAD_LAYER; - - hwc_layer->info.cursor_x = x; - hwc_layer->info.cursor_y = y; - return Error::NONE; -} - -Error VrHwc::setLayerBuffer(Display display, Layer layer, - buffer_handle_t buffer, int32_t acquireFence) { - base::unique_fd fence(acquireFence); - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* hwc_layer = display_ptr->GetLayer(layer); - if (!hwc_layer) - return Error::BAD_LAYER; - - hwc_layer->info.buffer = CreateGraphicBuffer( - buffer, hwc_layer->buffer_metadata); - hwc_layer->info.fence = new Fence(fence.release()); - - return Error::NONE; -} - -Error VrHwc::setLayerSurfaceDamage(Display display, Layer layer, - const std::vector<hwc_rect_t>& damage) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* hwc_layer = display_ptr->GetLayer(layer); - if (!hwc_layer) - return Error::BAD_LAYER; - - hwc_layer->info.damaged_regions = damage; - return Error::NONE; -} - -Error VrHwc::setLayerBlendMode(Display display, Layer layer, int32_t mode) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* hwc_layer = display_ptr->GetLayer(layer); - if (!hwc_layer) - return Error::BAD_LAYER; - - hwc_layer->info.blend_mode = - static_cast<ComposerView::ComposerLayer::BlendMode>(mode); - - return Error::NONE; -} - -Error VrHwc::setLayerColor(Display display, Layer layer, - IComposerClient::Color color) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* hwc_layer = display_ptr->GetLayer(layer); - if (!hwc_layer) - return Error::BAD_LAYER; - - hwc_layer->info.color = color; - return Error::NONE; -} - -Error VrHwc::setLayerCompositionType(Display display, Layer layer, - int32_t type) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* hwc_layer = display_ptr->GetLayer(layer); - if (!hwc_layer) - return Error::BAD_LAYER; - - hwc_layer->composition_type = static_cast<HwcLayer::Composition>(type); - - return Error::NONE; -} - -Error VrHwc::setLayerDataspace(Display display, Layer layer, - int32_t dataspace) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* hwc_layer = display_ptr->GetLayer(layer); - if (!hwc_layer) - return Error::BAD_LAYER; - - hwc_layer->info.dataspace = dataspace; - return Error::NONE; -} - -Error VrHwc::setLayerDisplayFrame(Display display, Layer layer, - const hwc_rect_t& frame) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* hwc_layer = display_ptr->GetLayer(layer); - if (!hwc_layer) - return Error::BAD_LAYER; - - hwc_layer->info.display_frame = - {frame.left, frame.top, frame.right, frame.bottom}; - - return Error::NONE; -} - -Error VrHwc::setLayerPlaneAlpha(Display display, Layer layer, float alpha) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* hwc_layer = display_ptr->GetLayer(layer); - if (!hwc_layer) - return Error::BAD_LAYER; - - hwc_layer->info.alpha = alpha; - - return Error::NONE; -} - -Error VrHwc::setLayerSidebandStream(Display display, Layer /* layer */, - buffer_handle_t /* stream */) { - std::lock_guard<std::mutex> guard(mutex_); - if (!FindDisplay(display)) - return Error::BAD_DISPLAY; - return Error::NONE; -} - -Error VrHwc::setLayerSourceCrop(Display display, Layer layer, - const hwc_frect_t& crop) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* hwc_layer = display_ptr->GetLayer(layer); - if (!hwc_layer) - return Error::BAD_LAYER; - - hwc_layer->info.crop = {crop.left, crop.top, crop.right, crop.bottom}; - - return Error::NONE; -} - -Error VrHwc::setLayerTransform(Display display, Layer layer, - int32_t transform) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* hwc_layer = display_ptr->GetLayer(layer); - if (!hwc_layer) - return Error::BAD_LAYER; - - hwc_layer->info.transform = transform; - return Error::NONE; -} - -Error VrHwc::setLayerVisibleRegion(Display display, Layer layer, - const std::vector<hwc_rect_t>& visible) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* hwc_layer = display_ptr->GetLayer(layer); - if (!hwc_layer) - return Error::BAD_LAYER; - - hwc_layer->info.visible_regions = visible; - return Error::NONE; -} - -Error VrHwc::setLayerZOrder(Display display, Layer layer, uint32_t z) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* hwc_layer = display_ptr->GetLayer(layer); - if (!hwc_layer) - return Error::BAD_LAYER; - - hwc_layer->info.z_order = z; - - return Error::NONE; -} - -Error VrHwc::setLayerInfo(Display display, Layer layer, uint32_t type, - uint32_t appId) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* hwc_layer = display_ptr->GetLayer(layer); - if (!hwc_layer) - return Error::BAD_LAYER; - - hwc_layer->info.type = type; - hwc_layer->info.app_id = appId; - - return Error::NONE; -} - -Error VrHwc::setClientTargetMetadata( - Display display, const IVrComposerClient::BufferMetadata& metadata) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - display_ptr->SetClientTargetMetadata(metadata); - - return Error::NONE; -} - -Error VrHwc::setLayerBufferMetadata( - Display display, Layer layer, - const IVrComposerClient::BufferMetadata& metadata) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - HwcLayer* hwc_layer = display_ptr->GetLayer(layer); - if (!hwc_layer) - return Error::BAD_LAYER; - - hwc_layer->buffer_metadata = metadata; - - return Error::NONE; -} - -Return<void> VrHwc::getCapabilities(getCapabilities_cb hidl_cb) { - hidl_cb(hidl_vec<Capability>()); - return Void(); -} - -Return<void> VrHwc::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) { - std::string result; - - { - std::lock_guard<std::mutex> guard(mutex_); - result = "\nVrHwc states:\n"; - for (const auto& pair : displays_) { - result += StringPrintf("Display id: %lu\n", (unsigned long)pair.first); - pair.second->dumpDebugInfo(&result); - } - result += "\n"; - } - - hidl_cb(hidl_string(result)); - return Void(); -} - -Return<void> VrHwc::createClient(createClient_cb hidl_cb) { - std::lock_guard<std::mutex> guard(mutex_); - - Error status = Error::NONE; - sp<VrComposerClient> client; - if (!client_.promote().get()) { - client = new VrComposerClient(*this); - } else { - ALOGE("Already have a client"); - status = Error::NO_RESOURCES; - } - - client_ = client; - hidl_cb(status, client); - return Void(); -} - -Return<void> VrHwc::createClient_2_3(IComposer::createClient_2_3_cb hidl_cb) { - std::lock_guard<std::mutex> guard(mutex_); - - Error status = Error::NONE; - sp<VrComposerClient> client; - if (!client_.promote().get()) { - client = new VrComposerClient(*this); - } else { - ALOGE("Already have a client"); - status = Error::NO_RESOURCES; - } - - client_ = client; - hidl_cb(status, client); - return Void(); -} - -void VrHwc::ForceDisplaysRefresh() { - std::lock_guard<std::mutex> guard(mutex_); - if (event_callback_ != nullptr) { - for (const auto& pair : displays_) - event_callback_->onRefresh(pair.first); - } -} - -void VrHwc::RegisterObserver(Observer* observer) { - std::lock_guard<std::mutex> guard(mutex_); - if (observer_) - ALOGE("Overwriting observer"); - else - observer_ = observer; -} - -void VrHwc::UnregisterObserver(Observer* observer) { - std::lock_guard<std::mutex> guard(mutex_); - if (observer != observer_) - ALOGE("Trying to unregister unknown observer"); - else - observer_ = nullptr; -} - -HwcDisplay* VrHwc::FindDisplay(Display display) { - auto iter = displays_.find(display); - return iter == displays_.end() ? nullptr : iter->second.get(); -} - -void VrHwc::UpdateVsyncCallbackEnabledLocked() { - auto primary_display = FindDisplay(kDefaultDisplayId); - LOG_ALWAYS_FATAL_IF(event_callback_ != nullptr && primary_display == nullptr, - "Should have created the primary display by now"); - bool send_vsync = - event_callback_ != nullptr && primary_display->vsync_enabled(); - vsync_callback_->SetEventCallback(send_vsync ? event_callback_ : nullptr); -} - -Return<void> VrHwc::debug(const hidl_handle& fd, - const hidl_vec<hidl_string>& args) { - std::string result; - - { - std::lock_guard<std::mutex> guard(mutex_); - for (const auto& pair : displays_) { - result += StringPrintf("Display id: %d\n", static_cast<int>(pair.first)); - pair.second->dumpDebugInfo(&result); - } - result += "\n"; - } - - FILE* out = fdopen(dup(fd->data[0]), "w"); - fprintf(out, "%s", result.c_str()); - fclose(out); - - return Void(); -} - -void HwcLayer::dumpDebugInfo(std::string* result) const { - if (!result) { - return; - } - *result += StringPrintf("Layer: composition_type: %d, type: %d, app_id: %d, z_order: %d,\ - cursor_x: %d, cursor_y: %d, color(rgba): (%d,%d,%d,%d), dataspace: %d, transform: %d,\ - display_frame(LTRB): (%d,%d,%d,%d), crop(LTRB): (%.1f,%.1f,%.1f,%.1f), blend_mode: %d\n", - composition_type, info.type, info.app_id, info.z_order, info.cursor_x, info.cursor_y, - info.color.r, info.color.g, info.color.b, info.color.a, info.dataspace, info.transform, - info.display_frame.left, info.display_frame.top, info.display_frame.right, - info.display_frame.bottom, info.crop.left, info.crop.top, info.crop.right, - info.crop.bottom, info.blend_mode); - *result += StringPrintf("Layer buffer metadata: width: %d, height: %d, stride: %d, layerCount: %d\ - , pixelFormat: %d\n", buffer_metadata.width, buffer_metadata.height, buffer_metadata.stride, - buffer_metadata.layerCount, buffer_metadata.format); -} - -status_t VrHwc::VsyncCallback::onVsync(int64_t vsync_timestamp) { - ATRACE_NAME("vr_hwc onVsync"); - std::lock_guard<std::mutex> guard(mutex_); - if (callback_ != nullptr) - callback_->onVsync(kDefaultDisplayId, vsync_timestamp); - return OK; -} - -void VrHwc::VsyncCallback::SetEventCallback(EventCallback* callback) { - std::lock_guard<std::mutex> guard(mutex_); - callback_ = callback; -} - -// composer::V2_2::ComposerHal -Error VrHwc::setReadbackBuffer(Display display, - const native_handle_t* bufferHandle, - android::base::unique_fd fenceFd) { - return Error::NONE; -} - -Error VrHwc::getReadbackBufferFence(Display display, - android::base::unique_fd* outFenceFd) { - return Error::NONE; -} - -Error VrHwc::createVirtualDisplay_2_2(uint32_t width, uint32_t height, - types::V1_1::PixelFormat* format, - Display* outDisplay) { - *format = types::V1_1::PixelFormat::RGBA_8888; - *outDisplay = display_count_; - displays_[display_count_].reset(new HwcDisplay(width, height)); - display_count_++; - return Error::NONE; -} - -Error VrHwc::setPowerMode_2_2(Display display, - IComposerClient::PowerMode mode) { - bool dozeSupported = false; - - Error dozeSupportError = getDozeSupport(display, &dozeSupported); - - if (dozeSupportError != Error::NONE) - return dozeSupportError; - - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - if (mode < IComposerClient::PowerMode::OFF || - mode > IComposerClient::PowerMode::DOZE_SUSPEND) { - return Error::BAD_PARAMETER; - } - - if (!dozeSupported && (mode == IComposerClient::PowerMode::DOZE || - mode == IComposerClient::PowerMode::DOZE_SUSPEND)) { - return Error::UNSUPPORTED; - } - - display_ptr->set_power_mode(mode); - return Error::NONE; -} - -Error VrHwc::setLayerFloatColor(Display display, Layer layer, - IComposerClient::FloatColor color) { - return Error::NONE; -} - -Error VrHwc::getRenderIntents(Display display, types::V1_1::ColorMode mode, - std::vector<RenderIntent>* outIntents) { - return Error::NONE; -} - -std::array<float, 16> VrHwc::getDataspaceSaturationMatrix( - types::V1_1::Dataspace dataspace) { - return {}; -} - -// composer::V2_3::ComposerHal -Error VrHwc::getHdrCapabilities_2_3(Display /*display*/, - hidl_vec<Hdr>* /*outTypes*/, - float* outMaxLuminance, - float* outMaxAverageLuminance, - float* outMinLuminance) { - *outMaxLuminance = 0; - *outMaxAverageLuminance = 0; - *outMinLuminance = 0; - return Error::NONE; -} - -Error VrHwc::setLayerPerFrameMetadata_2_3( - Display display, Layer layer, - const std::vector<IComposerClient::PerFrameMetadata>& metadata) { - return Error::NONE; -} - -Error VrHwc::getPerFrameMetadataKeys_2_3( - Display display, - std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) { - return Error::NONE; -} - -Error VrHwc::setColorMode_2_3(Display display, ColorMode mode, - RenderIntent intent) { - std::lock_guard<std::mutex> guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3) - return Error::BAD_PARAMETER; - - display_ptr->set_color_mode(mode); - return Error::NONE; -} - -Error VrHwc::getRenderIntents_2_3(Display display, ColorMode mode, - std::vector<RenderIntent>* outIntents) { - return Error::NONE; -} - -Error VrHwc::getColorModes_2_3(Display display, hidl_vec<ColorMode>* outModes) { - return Error::NONE; -} - -Error VrHwc::getClientTargetSupport_2_3(Display display, uint32_t width, - uint32_t height, PixelFormat format, - Dataspace dataspace) { - return Error::NONE; -} - -Error VrHwc::getReadbackBufferAttributes_2_3(Display display, - PixelFormat* outFormat, - Dataspace* outDataspace) { - return Error::NONE; -} - -Error VrHwc::getDisplayIdentificationData(Display display, uint8_t* outPort, - std::vector<uint8_t>* outData) { - int error = 0; - auto display_client = display::DisplayClient::Create(&error); - if (!display_client) { - ALOGE("Could not connect to display service : %s(%d)", strerror(error), - error); - return Error::BAD_CONFIG; - } - auto edid_data = display_client->GetConfigurationData( - display::ConfigFileType::kDeviceEdid); - auto display_identification_port = - display_client->GetDisplayIdentificationPort(); - *outPort = display_identification_port.get(); - - std::copy(edid_data.get().begin(), edid_data.get().end(), - std::back_inserter(*outData)); - return Error::NONE; -} - -Error VrHwc::setLayerColorTransform(Display display, Layer layer, - const float* matrix) { - return Error::NONE; -} - -Error VrHwc::getDisplayedContentSamplingAttributes( - Display display, PixelFormat& format, Dataspace& dataspace, - hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) { - return Error::NONE; -} - -Error VrHwc::setDisplayedContentSamplingEnabled( - Display display, IComposerClient::DisplayedContentSampling enable, - hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, - uint64_t maxFrames) { - return Error::NONE; -} - -Error VrHwc::getDisplayedContentSample(Display display, uint64_t maxFrames, - uint64_t timestamp, uint64_t& frameCount, - hidl_vec<uint64_t>& sampleComponent0, - hidl_vec<uint64_t>& sampleComponent1, - hidl_vec<uint64_t>& sampleComponent2, - hidl_vec<uint64_t>& sampleComponent3) { - return Error::NONE; -} - -Error VrHwc::getDisplayCapabilities( - Display display, - std::vector<IComposerClient::DisplayCapability>* outCapabilities) { - return Error::NONE; -} - -Error VrHwc::setLayerPerFrameMetadataBlobs( - Display display, Layer layer, - std::vector<IComposerClient::PerFrameMetadataBlob>& blobs) { - return Error::NONE; -} - -Error VrHwc::getDisplayBrightnessSupport(Display display, bool* outSupport) { - return Error::NONE; -} - -Error VrHwc::setDisplayBrightness(Display display, float brightness) { - return Error::NONE; -} - -} // namespace dvr -} // namespace android diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h deleted file mode 100644 index 3e3a6307fa..0000000000 --- a/services/vr/hardware_composer/impl/vr_hwc.h +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright 2016 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 ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_HWC_H -#define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_HWC_H - -#include <android-base/unique_fd.h> -#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h> -#include <android/hardware/graphics/composer/2.3/IComposer.h> -#include <composer-hal/2.3/ComposerHal.h> -#include <private/dvr/vsync_service.h> -#include <ui/Fence.h> -#include <ui/GraphicBuffer.h> -#include <utils/StrongPointer.h> - -#include <mutex> -#include <unordered_map> - -using namespace android::frameworks::vr::composer::V2_0; -using namespace android::hardware::graphics::common::V1_0; -using namespace android::hardware::graphics::composer::V2_3; - -using android::hardware::hidl_bitfield; -using android::hardware::hidl_handle; -using android::hardware::hidl_string; -using android::hardware::hidl_vec; -using android::hardware::Return; -using android::hardware::Void; -using android::hardware::graphics::composer::V2_1::Config; -using android::hardware::graphics::composer::V2_1::Display; -using android::hardware::graphics::composer::V2_1::Error; -using android::hardware::graphics::composer::V2_1::Layer; -using android::hardware::graphics::composer::V2_3::IComposerClient; - -namespace android { - -class Fence; - -namespace dvr { - -class VrComposerClient; - -using android::hardware::graphics::composer::V2_3::hal::ComposerHal; - -namespace types = android::hardware::graphics::common; - -using types::V1_1::RenderIntent; -using types::V1_2::ColorMode; -using types::V1_2::Dataspace; -using types::V1_2::Hdr; -using types::V1_2::PixelFormat; - -class ComposerView { - public: - struct ComposerLayer { - using Recti = hardware::graphics::composer::V2_3::IComposerClient::Rect; - using Rectf = hardware::graphics::composer::V2_3::IComposerClient::FRect; - using BlendMode = - hardware::graphics::composer::V2_3::IComposerClient::BlendMode; - - Layer id; - sp<GraphicBuffer> buffer; - sp<Fence> fence; - Recti display_frame; - Rectf crop; - BlendMode blend_mode; - float alpha; - uint32_t type; - uint32_t app_id; - uint32_t z_order; - int32_t cursor_x; - int32_t cursor_y; - IComposerClient::Color color; - int32_t dataspace; - int32_t transform; - std::vector<hwc_rect_t> visible_regions; - std::vector<hwc_rect_t> damaged_regions; - }; - - struct Frame { - Display display_id; - // This is set to true to notify the upper layer that the display is - // being removed, or left false in the case of a normal frame. The upper - // layer tracks display IDs and will handle new ones showing up. - bool removed = false; - int32_t display_width; - int32_t display_height; - Config active_config; - ColorMode color_mode; - IComposerClient::PowerMode power_mode; - IComposerClient::Vsync vsync_enabled; - float color_transform[16]; - int32_t color_transform_hint; - std::vector<ComposerLayer> layers; - }; - - class Observer { - public: - virtual ~Observer() {} - - // Returns a list of layers that need to be shown together. Layers are - // returned in z-order, with the lowest layer first. - virtual base::unique_fd OnNewFrame(const Frame& frame) = 0; - }; - - virtual ~ComposerView() {} - - virtual void ForceDisplaysRefresh() = 0; - virtual void RegisterObserver(Observer* observer) = 0; - virtual void UnregisterObserver(Observer* observer) = 0; -}; - -struct HwcLayer { - using Composition = - hardware::graphics::composer::V2_3::IComposerClient::Composition; - - explicit HwcLayer(Layer new_id) { info.id = new_id; } - - void dumpDebugInfo(std::string* result) const; - - Composition composition_type; - ComposerView::ComposerLayer info; - IVrComposerClient::BufferMetadata buffer_metadata; -}; - -class HwcDisplay { - public: - HwcDisplay(int32_t width, int32_t height); - ~HwcDisplay(); - - int32_t width() const { return width_; } - int32_t height() const { return height_; } - - HwcLayer* CreateLayer(); - bool DestroyLayer(Layer id); - HwcLayer* GetLayer(Layer id); - - bool SetClientTarget(const native_handle_t* handle, base::unique_fd fence); - void SetClientTargetMetadata( - const IVrComposerClient::BufferMetadata& metadata); - - void GetChangedCompositionTypes( - std::vector<Layer>* layer_ids, - std::vector<IComposerClient::Composition>* composition); - - Error GetFrame(std::vector<ComposerView::ComposerLayer>* out_frame); - - std::vector<Layer> UpdateLastFrameAndGetLastFrameLayers(); - - Config active_config() const { return active_config_; } - void set_active_config(Config config) { active_config_ = config; } - - ColorMode color_mode() const { return color_mode_; } - void set_color_mode(ColorMode mode) { color_mode_ = mode; } - - IComposerClient::PowerMode power_mode() const { return power_mode_; } - void set_power_mode(IComposerClient::PowerMode mode) { power_mode_ = mode; } - - bool vsync_enabled() const { return vsync_enabled_; } - void set_vsync_enabled(bool vsync) {vsync_enabled_ = vsync;} - - const float* color_transform() const { return color_transform_; } - int32_t color_transform_hint() const { return color_transform_hint_; } - void SetColorTransform(const float* matrix, int32_t hint); - - void dumpDebugInfo(std::string* result) const; - - private: - // The client target buffer and the associated fence. - sp<GraphicBuffer> buffer_; - IVrComposerClient::BufferMetadata buffer_metadata_; - sp<Fence> fence_; - - // List of currently active layers. - std::vector<HwcLayer> layers_; - - std::vector<Layer> last_frame_layers_ids_; - - // Layer ID generator. - uint64_t layer_ids_ = 1; - - int32_t width_; - int32_t height_; - - Config active_config_; - ColorMode color_mode_; - IComposerClient::PowerMode power_mode_; - bool vsync_enabled_ = false; - float color_transform_[16]; - int32_t color_transform_hint_; - - HwcDisplay(const HwcDisplay&) = delete; - void operator=(const HwcDisplay&) = delete; -}; - -class VrHwc : public IComposer, public ComposerHal, public ComposerView { - public: - VrHwc(); - ~VrHwc() override; - - Error setLayerInfo(Display display, Layer layer, uint32_t type, - uint32_t appId); - Error setClientTargetMetadata( - Display display, const IVrComposerClient::BufferMetadata& metadata); - Error setLayerBufferMetadata( - Display display, Layer layer, - const IVrComposerClient::BufferMetadata& metadata); - - // composer::V2_1::ComposerHal - bool hasCapability(hwc2_capability_t capability) override; - - std::string dumpDebugInfo() override { return {}; } - - void registerEventCallback(ComposerHal::EventCallback* callback) override; - void unregisterEventCallback() override; - - uint32_t getMaxVirtualDisplayCount() override; - Error destroyVirtualDisplay(Display display) override; - - Error createLayer(Display display, Layer* outLayer) override; - Error destroyLayer(Display display, Layer layer) override; - - Error getActiveConfig(Display display, Config* outConfig) override; - Error getDisplayAttribute(Display display, Config config, - IComposerClient::Attribute attribute, - int32_t* outValue) override; - Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override; - Error getDisplayName(Display display, hidl_string* outName) override; - Error getDisplayType(Display display, - IComposerClient::DisplayType* outType) override; - Error getDozeSupport(Display display, bool* outSupport) override; - - Error setActiveConfig(Display display, Config config) override; - Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override; - - Error setColorTransform(Display display, const float* matrix, - int32_t hint) override; - Error setClientTarget(Display display, buffer_handle_t target, - int32_t acquireFence, int32_t dataspace, - const std::vector<hwc_rect_t>& damage) override; - Error setOutputBuffer(Display display, buffer_handle_t buffer, - int32_t releaseFence) override; - Error validateDisplay( - Display display, std::vector<Layer>* outChangedLayers, - std::vector<IComposerClient::Composition>* outCompositionTypes, - uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers, - std::vector<uint32_t>* outRequestMasks) override; - Error acceptDisplayChanges(Display display) override; - Error presentDisplay(Display display, int32_t* outPresentFence, - std::vector<Layer>* outLayers, - std::vector<int32_t>* outReleaseFences) override; - - Error setLayerCursorPosition(Display display, Layer layer, int32_t x, - int32_t y) override; - Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer, - int32_t acquireFence) override; - Error setLayerSurfaceDamage(Display display, Layer layer, - const std::vector<hwc_rect_t>& damage) override; - Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override; - Error setLayerColor(Display display, Layer layer, - IComposerClient::Color color) override; - Error setLayerCompositionType(Display display, Layer layer, - int32_t type) override; - Error setLayerDataspace(Display display, Layer layer, - int32_t dataspace) override; - Error setLayerDisplayFrame(Display display, Layer layer, - const hwc_rect_t& frame) override; - Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override; - Error setLayerSidebandStream(Display display, Layer layer, - buffer_handle_t stream) override; - Error setLayerSourceCrop(Display display, Layer layer, - const hwc_frect_t& crop) override; - Error setLayerTransform(Display display, Layer layer, - int32_t transform) override; - Error setLayerVisibleRegion(Display display, Layer layer, - const std::vector<hwc_rect_t>& visible) override; - Error setLayerZOrder(Display display, Layer layer, uint32_t z) override; - - // composer::V2_2::ComposerHal - Error setReadbackBuffer(Display display, const native_handle_t* bufferHandle, - android::base::unique_fd fenceFd) override; - Error getReadbackBufferFence(Display display, - android::base::unique_fd* outFenceFd) override; - Error createVirtualDisplay_2_2(uint32_t width, uint32_t height, - types::V1_1::PixelFormat* format, - Display* outDisplay) override; - Error setPowerMode_2_2(Display display, - IComposerClient::PowerMode mode) override; - Error setLayerFloatColor(Display display, Layer layer, - IComposerClient::FloatColor color) override; - Error getRenderIntents(Display display, types::V1_1::ColorMode mode, - std::vector<RenderIntent>* outIntents) override; - std::array<float, 16> getDataspaceSaturationMatrix( - types::V1_1::Dataspace dataspace) override; - - // composer::V2_3::ComposerHal - Error getHdrCapabilities_2_3(Display display, hidl_vec<Hdr>* outTypes, - float* outMaxLuminance, - float* outMaxAverageLuminance, - float* outMinLuminance) override; - Error setLayerPerFrameMetadata_2_3( - Display display, Layer layer, - const std::vector<IComposerClient::PerFrameMetadata>& metadata) override; - Error getPerFrameMetadataKeys_2_3( - Display display, - std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) override; - Error setColorMode_2_3(Display display, ColorMode mode, - RenderIntent intent) override; - Error getRenderIntents_2_3(Display display, ColorMode mode, - std::vector<RenderIntent>* outIntents) override; - Error getColorModes_2_3(Display display, - hidl_vec<ColorMode>* outModes) override; - Error getClientTargetSupport_2_3(Display display, uint32_t width, - uint32_t height, PixelFormat format, - Dataspace dataspace) override; - Error getReadbackBufferAttributes_2_3(Display display, PixelFormat* outFormat, - Dataspace* outDataspace) override; - Error getDisplayIdentificationData(Display display, uint8_t* outPort, - std::vector<uint8_t>* outData) override; - Error setLayerColorTransform(Display display, Layer layer, - const float* matrix) override; - Error getDisplayedContentSamplingAttributes( - Display display, PixelFormat& format, Dataspace& dataspace, - hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) - override; - Error setDisplayedContentSamplingEnabled( - Display display, IComposerClient::DisplayedContentSampling enable, - hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, - uint64_t maxFrames) override; - Error getDisplayedContentSample( - Display display, uint64_t maxFrames, uint64_t timestamp, - uint64_t& frameCount, hidl_vec<uint64_t>& sampleComponent0, - hidl_vec<uint64_t>& sampleComponent1, - hidl_vec<uint64_t>& sampleComponent2, - hidl_vec<uint64_t>& sampleComponent3) override; - Error getDisplayCapabilities(Display display, - std::vector<IComposerClient::DisplayCapability>* - outCapabilities) override; - Error setLayerPerFrameMetadataBlobs( - Display display, Layer layer, - std::vector<IComposerClient::PerFrameMetadataBlob>& blobs) override; - Error getDisplayBrightnessSupport(Display display, bool* outSupport) override; - Error setDisplayBrightness(Display display, float brightness) override; - - // IComposer: - Return<void> getCapabilities(getCapabilities_cb hidl_cb) override; - Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override; - Return<void> createClient(createClient_cb hidl_cb) override; - Return<void> createClient_2_3( - IComposer::createClient_2_3_cb hidl_cb) override; - - // ComposerView: - void ForceDisplaysRefresh() override; - void RegisterObserver(Observer* observer) override; - void UnregisterObserver(Observer* observer) override; - - Return<void> debug(const hidl_handle& fd, - const hidl_vec<hidl_string>& args) override; - - private: - class VsyncCallback : public BnVsyncCallback { - public: - status_t onVsync(int64_t vsync_timestamp) override; - void SetEventCallback(EventCallback* callback); - private: - std::mutex mutex_; - EventCallback* callback_; - }; - - HwcDisplay* FindDisplay(Display display); - - // Re-evaluate whether or not we should start making onVsync() callbacks to - // the client. We need enableCallback(true) to have been called, and - // setVsyncEnabled() to have been called for the primary display. The caller - // must have mutex_ locked already. - void UpdateVsyncCallbackEnabledLocked(); - - wp<VrComposerClient> client_; - - // Guard access to internal state from binder threads. - std::mutex mutex_; - - std::unordered_map<Display, std::unique_ptr<HwcDisplay>> displays_; - Display display_count_ = 2; - - EventCallback* event_callback_ = nullptr; - Observer* observer_ = nullptr; - - sp<VsyncCallback> vsync_callback_; - - VrHwc(const VrHwc&) = delete; - void operator=(const VrHwc&) = delete; -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_HWC_H diff --git a/services/vr/hardware_composer/tests/vr_composer_test.cpp b/services/vr/hardware_composer/tests/vr_composer_test.cpp deleted file mode 100644 index 2e70928662..0000000000 --- a/services/vr/hardware_composer/tests/vr_composer_test.cpp +++ /dev/null @@ -1,172 +0,0 @@ -#include <android/dvr/BnVrComposerCallback.h> -#include <binder/IServiceManager.h> -#include <gtest/gtest.h> -#include <sys/eventfd.h> -#include <vr_composer.h> - -namespace android { -namespace dvr { -namespace { - -const char kVrDisplayName[] = "VrDisplay_Test"; - -class TestComposerView : public ComposerView { - public: - TestComposerView() {} - ~TestComposerView() override = default; - - size_t display_refresh_count() const { return display_refresh_count_; } - - void ForceDisplaysRefresh() override { display_refresh_count_++; } - void RegisterObserver(Observer* observer) override {} - void UnregisterObserver(Observer* observer) override {} - - TestComposerView(const TestComposerView&) = delete; - void operator=(const TestComposerView&) = delete; - - private: - size_t display_refresh_count_ = 0; -}; - -class TestComposerCallback : public BnVrComposerCallback { - public: - TestComposerCallback() {} - ~TestComposerCallback() override = default; - - ComposerView::Frame last_frame() const { return last_frame_; } - - binder::Status onNewFrame( - const ParcelableComposerFrame& frame, - ParcelableUniqueFd* /* fence */) override { - last_frame_ = frame.frame(); - return binder::Status::ok(); - } - - private: - ComposerView::Frame last_frame_; - - TestComposerCallback(const TestComposerCallback&) = delete; - void operator=(const TestComposerCallback&) = delete; -}; - -class TestComposerCallbackWithFence : public TestComposerCallback { - public: - ~TestComposerCallbackWithFence() override = default; - - binder::Status onNewFrame( - const ParcelableComposerFrame& frame, - ParcelableUniqueFd* fence) override { - binder::Status status = TestComposerCallback::onNewFrame(frame, fence); - - base::unique_fd fd(eventfd(0, 0)); - EXPECT_LE(0, fd.get()); - fence->set_fence(fd); - - return status; - } -}; - -sp<GraphicBuffer> CreateBuffer() { - return new GraphicBuffer(600, 400, PIXEL_FORMAT_RGBA_8888, - GraphicBuffer::USAGE_HW_TEXTURE); -} - -} // namespace - -class VrComposerTest : public testing::Test { - public: - VrComposerTest() : composer_(new VrComposer(&composer_view_)) {} - ~VrComposerTest() override = default; - - sp<IVrComposer> GetComposerProxy() const { - sp<IServiceManager> sm(defaultServiceManager()); - return interface_cast<IVrComposer>(sm->getService(String16(kVrDisplayName))); - } - - void SetUp() override { - sp<IServiceManager> sm(defaultServiceManager()); - EXPECT_EQ(OK, - sm->addService(String16(kVrDisplayName), composer_, false)); - } - - protected: - TestComposerView composer_view_; - sp<VrComposer> composer_; - - VrComposerTest(const VrComposerTest&) = delete; - void operator=(const VrComposerTest&) = delete; -}; - -TEST_F(VrComposerTest, TestWithoutObserver) { - sp<IVrComposer> composer = GetComposerProxy(); - ComposerView::Frame frame; - - base::unique_fd fence = composer_->OnNewFrame(frame); - ASSERT_EQ(-1, fence.get()); -} - -TEST_F(VrComposerTest, TestWithObserver) { - sp<IVrComposer> composer = GetComposerProxy(); - sp<TestComposerCallback> callback = new TestComposerCallback(); - ASSERT_EQ(0, composer_view_.display_refresh_count()); - ASSERT_TRUE(composer->registerObserver(callback).isOk()); - ASSERT_EQ(1, composer_view_.display_refresh_count()); - - ComposerView::Frame frame; - base::unique_fd fence = composer_->OnNewFrame(frame); - ASSERT_EQ(-1, fence.get()); -} - -TEST_F(VrComposerTest, TestWithOneLayer) { - sp<IVrComposer> composer = GetComposerProxy(); - sp<TestComposerCallback> callback = new TestComposerCallbackWithFence(); - ASSERT_TRUE(composer->registerObserver(callback).isOk()); - - ComposerView::Frame frame; - frame.display_id = 1; - frame.removed = false; - frame.display_width = 600; - frame.display_height = 400; - frame.layers.push_back(ComposerView::ComposerLayer{ - .id = 1, - .buffer = CreateBuffer(), - .fence = new Fence(eventfd(0, 0)), - .display_frame = {0, 0, 600, 400}, - .crop = {0.0f, 0.0f, 600.0f, 400.0f}, - .blend_mode = IComposerClient::BlendMode::NONE, - .alpha = 1.0f, - .type = 1, - .app_id = 1, - }); - base::unique_fd fence = composer_->OnNewFrame(frame); - ASSERT_LE(0, fence.get()); - - ComposerView::Frame received_frame = callback->last_frame(); - ASSERT_EQ(frame.display_id, received_frame.display_id); - ASSERT_EQ(frame.display_width, received_frame.display_width); - ASSERT_EQ(frame.display_height, received_frame.display_height); - ASSERT_EQ(frame.removed, received_frame.removed); - ASSERT_EQ(1u, received_frame.layers.size()); - ASSERT_EQ(frame.layers[0].id, received_frame.layers[0].id); - ASSERT_NE(nullptr, received_frame.layers[0].buffer.get()); - ASSERT_TRUE(received_frame.layers[0].fence->isValid()); - ASSERT_EQ(frame.layers[0].display_frame.left, - received_frame.layers[0].display_frame.left); - ASSERT_EQ(frame.layers[0].display_frame.top, - received_frame.layers[0].display_frame.top); - ASSERT_EQ(frame.layers[0].display_frame.right, - received_frame.layers[0].display_frame.right); - ASSERT_EQ(frame.layers[0].display_frame.bottom, - received_frame.layers[0].display_frame.bottom); - ASSERT_EQ(frame.layers[0].crop.left, received_frame.layers[0].crop.left); - ASSERT_EQ(frame.layers[0].crop.top, received_frame.layers[0].crop.top); - ASSERT_EQ(frame.layers[0].crop.right, received_frame.layers[0].crop.right); - ASSERT_EQ(frame.layers[0].crop.bottom, received_frame.layers[0].crop.bottom); - ASSERT_EQ(frame.layers[0].blend_mode, received_frame.layers[0].blend_mode); - ASSERT_EQ(frame.layers[0].alpha, received_frame.layers[0].alpha); - ASSERT_EQ(frame.layers[0].type, received_frame.layers[0].type); - ASSERT_EQ(frame.layers[0].app_id, received_frame.layers[0].app_id); -} - -} // namespace dvr -} // namespace android diff --git a/services/vr/hardware_composer/vr_composer.cpp b/services/vr/hardware_composer/vr_composer.cpp deleted file mode 100644 index d93f370945..0000000000 --- a/services/vr/hardware_composer/vr_composer.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "vr_composer.h" - -#include <binder/IPCThreadState.h> -#include <binder/PermissionCache.h> - -namespace android { -namespace dvr { -namespace { - -bool CheckPermission() { - const android::IPCThreadState* ipc = android::IPCThreadState::self(); - const pid_t pid = ipc->getCallingPid(); - const uid_t uid = ipc->getCallingUid(); - const bool permission = PermissionCache::checkPermission( - String16("android.permission.RESTRICTED_VR_ACCESS"), pid, uid); - if (!permission) - ALOGE("permission denied to pid=%d uid=%u", pid, uid); - - return permission; -} - -} // namespace - -VrComposer::VrComposer(ComposerView* composer_view) - : composer_view_(composer_view) { - composer_view_->RegisterObserver(this); -} - -VrComposer::~VrComposer() { - composer_view_->UnregisterObserver(this); -} - -binder::Status VrComposer::registerObserver( - const sp<IVrComposerCallback>& callback) { - { - std::lock_guard<std::mutex> guard(mutex_); - - if (!CheckPermission()) - return binder::Status::fromStatusT(PERMISSION_DENIED); - - if (callback_.get()) { - ALOGE("Failed to register callback, already registered"); - return binder::Status::fromStatusT(ALREADY_EXISTS); - } - - callback_ = callback; - IInterface::asBinder(callback_)->linkToDeath(this); - } - - // Don't take the lock to force display refresh otherwise it could end in a - // deadlock since HWC calls this with new frames and it has a lock of its own - // to serialize access to the display information. - composer_view_->ForceDisplaysRefresh(); - return binder::Status::ok(); -} - -binder::Status VrComposer::clearObserver() { - std::lock_guard<std::mutex> guard(mutex_); - callback_ = nullptr; - return binder::Status::ok(); -} - -base::unique_fd VrComposer::OnNewFrame(const ComposerView::Frame& frame) { - std::lock_guard<std::mutex> guard(mutex_); - - if (!callback_.get()) - return base::unique_fd(); - - ParcelableComposerFrame parcelable_frame(frame); - ParcelableUniqueFd fence; - binder::Status ret = callback_->onNewFrame(parcelable_frame, &fence); - if (!ret.isOk()) - ALOGE("Failed to send new frame: %s", ret.toString8().string()); - - return fence.fence(); -} - -void VrComposer::binderDied(const wp<IBinder>& /* who */) { - std::lock_guard<std::mutex> guard(mutex_); - - callback_ = nullptr; -} - -} // namespace dvr -} // namespace android diff --git a/services/vr/hardware_composer/vr_composer.h b/services/vr/hardware_composer/vr_composer.h deleted file mode 100644 index 1273352ad0..0000000000 --- a/services/vr/hardware_composer/vr_composer.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H -#define ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H - -#include <android/dvr/BnVrComposer.h> -#include <impl/vr_hwc.h> - -namespace android { -namespace dvr { - -class VrComposerCallback; - -// Implementation of the IVrComposer service used to notify VR Window Manager -// when SurfaceFlinger presents 2D UI changes. -// -// VR HWC updates the presented frame via the ComposerView::Observer interface. -// On notification |callback_| is called to update VR Window Manager. -// NOTE: If VR Window Manager isn't connected, the notification is a no-op. -class VrComposer - : public BnVrComposer, - public ComposerView::Observer, - public IBinder::DeathRecipient { - public: - explicit VrComposer(ComposerView* composer_view); - ~VrComposer() override; - - // BnVrComposer: - binder::Status registerObserver( - const sp<IVrComposerCallback>& callback) override; - - binder::Status clearObserver() override; - - // ComposerView::Observer: - base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override; - - private: - // IBinder::DeathRecipient: - void binderDied(const wp<IBinder>& who) override; - - std::mutex mutex_; - - sp<IVrComposerCallback> callback_; - - ComposerView* composer_view_; // Not owned. - - VrComposer(const VrComposer&) = delete; - void operator=(const VrComposer&) = delete; -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H |